/* * Copyright (C) 2018-2019 - Vito Caputo - * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * 3D vector operations header * * Variants prefixed with _ return a result vector struct by value. * * Variants missing the _ prefix for vector result operations return a pointer * and must be either supplied the result memory as the first "res" argument * which is then returned after being populated with the result's value, or * NULL to allocate space for the result and that pointer is returned after being * populated with its value. When supplying NULL result pointers the functions * must allocate memory and thus may return NULL on OOM, so callers should * check for NULL returns when supplying NULL for "res". * * Example: * v3f_t foo, *foop; * * foo = _v3f_mult(&(v3f_t){1.f,1.f,1.f}, &(v3f_t){2.f,2.f,2.f}); * * is equivalent to: * * v3f_mult(&foo, &(v3f_t){1.f,1.f,1.f}, &(v3f_t){2.f,2.f,2.f}); * * or dynamically allocated: * * foop = v3f_mult(NULL, &(v3f_t){1.f,1.f,1.f}, &(v3f_t){2.f,2.f,2.f}); * free(foop); * * is equivalent to: * * foop = malloc(sizeof(v3f_t)); * v3f_mult(foop, &(v3f_t){1.f,1.f,1.f}, &(v3f_t){2.f,2.f,2.f}); * free(foop); */ #ifndef _V3F_H #define _V3F_H #include #include typedef struct v3f_t { float x, y, z; } v3f_t; static inline v3f_t * _v3f_allocated(v3f_t **ptr) { if (!*ptr) *ptr = malloc(sizeof(v3f_t)); return *ptr; } static inline v3f_t _v3f_add(const v3f_t *a, const v3f_t *b) { return (v3f_t){a->x + b->x, a->y + b->y, a->z + b->z}; } static inline v3f_t * v3f_add(v3f_t *res, const v3f_t *a, const v3f_t *b) { if (_v3f_allocated(&res)) *res = _v3f_add(a, b); return res; } static inline v3f_t _v3f_sub(const v3f_t *a, const v3f_t *b) { return (v3f_t){a->x - b->x, a->y - b->y, a->z - b->z}; } static inline v3f_t * v3f_sub(v3f_t *res, const v3f_t *a, const v3f_t *b) { if (_v3f_allocated(&res)) *res = _v3f_sub(a, b); return res; } static inline v3f_t _v3f_mult(const v3f_t *a, const v3f_t *b) { return (v3f_t){a->x * b->x, a->y * b->y, a->z * b->z}; } static inline v3f_t * v3f_mult(v3f_t *res, const v3f_t *a, const v3f_t *b) { if (_v3f_allocated(&res)) *res = _v3f_mult(a, b); return res; } static inline v3f_t _v3f_mult_scalar(const v3f_t *v, float scalar) { return (v3f_t){v->x * scalar, v->y * scalar, v->z * scalar}; } static inline v3f_t * v3f_mult_scalar(v3f_t *res, const v3f_t *v, float scalar) { if (_v3f_allocated(&res)) *res = _v3f_mult_scalar(v, scalar); return res; } static inline v3f_t _v3f_div_scalar(const v3f_t *v, float scalar) { return _v3f_mult_scalar(v, 1.f / scalar); } static inline v3f_t * v3f_div_scalar(v3f_t *res, const v3f_t *v, float scalar) { if (_v3f_allocated(&res)) *res = _v3f_div_scalar(v, scalar); return res; } static inline float v3f_dot(const v3f_t *a, const v3f_t *b) { return a->x * b->x + a->y * b->y + a->z * b->z; } static inline float v3f_length(const v3f_t *v) { return sqrtf(v3f_dot(v, v)); } static inline float v3f_distance(const v3f_t *a, const v3f_t *b) { return v3f_length(v3f_sub(&(v3f_t){}, a, b)); } static inline float v3f_distance_sq(const v3f_t *a, const v3f_t *b) { v3f_t d = _v3f_sub(a, b); return v3f_dot(&d, &d); } static inline v3f_t _v3f_normalize(const v3f_t *v) { return _v3f_mult_scalar(v, 1.0f / v3f_length(v)); } static inline v3f_t * v3f_normalize(v3f_t *res, const v3f_t *v) { if (_v3f_allocated(&res)) *res = _v3f_normalize(v); return res; } static inline v3f_t _v3f_lerp(const v3f_t *a, const v3f_t *b, float t) { v3f_t lerp_a, lerp_b; lerp_a = _v3f_mult_scalar(a, 1.0f - t); lerp_b = _v3f_mult_scalar(b, t); return _v3f_add(&lerp_a, &lerp_b); } static inline v3f_t * v3f_lerp(v3f_t *res, const v3f_t *a, const v3f_t *b, float t) { if (_v3f_allocated(&res)) *res = _v3f_lerp(a, b, t); return res; } static inline v3f_t _v3f_nlerp(const v3f_t *a, const v3f_t *b, float t) { v3f_t lerp = _v3f_lerp(a, b, t); return _v3f_normalize(&lerp); } static inline v3f_t * v3f_nlerp(v3f_t *res, const v3f_t *a, const v3f_t *b, float t) { if (_v3f_allocated(&res)) *res = _v3f_nlerp(a, b, t); return res; } /* * 1 ab-------bb * | | | * | | | * | | | * 0 aa-------ba * t_x: 0---------1 * ^ * t_y */ static inline v3f_t _v3f_bilerp(const v3f_t *aa, const v3f_t *ab, const v3f_t *ba, const v3f_t *bb, float t_x, float t_y) { v3f_t xa = _v3f_lerp(aa, ba, t_x); v3f_t xb = _v3f_lerp(ab, bb, t_x); return _v3f_lerp(&xa, &xb, t_y); } static inline v3f_t * v3f_bilerp(v3f_t *res, const v3f_t *aa, const v3f_t *ab, const v3f_t *ba, const v3f_t *bb, float t_x, float t_y) { if (_v3f_allocated(&res)) *res = _v3f_bilerp(aa, ab, ba, bb, t_x, t_y); return res; } /* * abb-------bbb * /| /| * aba-------bba| * | | | | * |aab------|bab * |/ |/ * aaa-------baa */ static inline v3f_t _v3f_trilerp(const v3f_t *aaa, const v3f_t *aba, const v3f_t *aab, const v3f_t *abb, const v3f_t *baa, const v3f_t *bba, const v3f_t *bab, const v3f_t *bbb, float t_x, float t_y, float t_z) { v3f_t xya = _v3f_bilerp(aaa, aba, baa, bba, t_x, t_y); v3f_t xyb = _v3f_bilerp(aab, abb, bab, bbb, t_x, t_y); return _v3f_lerp(&xya, &xyb, t_z); } static inline v3f_t * v3f_trilerp(v3f_t *res, const v3f_t *aaa, const v3f_t *aba, const v3f_t *aab, const v3f_t *abb, const v3f_t *baa, const v3f_t *bba, const v3f_t *bab, const v3f_t *bbb, float t_x, float t_y, float t_z) { if (_v3f_allocated(&res)) *res = _v3f_trilerp(aaa, aba, aab, abb, baa, bba, bab, bbb, t_x, t_y, t_z); return res; } static inline v3f_t _v3f_cross(const v3f_t *a, const v3f_t *b) { return (v3f_t){ .x = a->y * b->z - a->z * b->y, .y = a->z * b->x - a->x * b->z, .z = a->x * b->y - a->y * b->x, }; } static inline v3f_t * v3f_cross(v3f_t *res, const v3f_t *a, const v3f_t *b) { if (_v3f_allocated(&res)) *res = _v3f_cross(a, b); return res; } static inline v3f_t _v3f_rand(const v3f_t *min, const v3f_t *max) { return (v3f_t){ .x = min->x + (float)rand() * (1.f/RAND_MAX) * (max->x - min->x), .y = min->y + (float)rand() * (1.f/RAND_MAX) * (max->y - min->y), .z = min->z + (float)rand() * (1.f/RAND_MAX) * (max->z - min->z), }; } static inline v3f_t * v3f_rand(v3f_t *res, const v3f_t *min, const v3f_t *max) { if (_v3f_allocated(&res)) *res = _v3f_rand(min, max); return res; } static inline v3f_t _v3f_ceil(const v3f_t *v) { return (v3f_t){ .x = ceilf(v->x), .y = ceilf(v->y), .z = ceilf(v->z), }; } static inline v3f_t * v3f_ceil(v3f_t *res, const v3f_t *v) { if (_v3f_allocated(&res)) *res = _v3f_ceil(v); return res; } static inline v3f_t _v3f_floor(const v3f_t *v) { return (v3f_t){ .x = floorf(v->x), .y = floorf(v->y), .z = floorf(v->z), }; } static inline v3f_t * v3f_floor(v3f_t *res, const v3f_t *v) { if (_v3f_allocated(&res)) *res = _v3f_floor(v); return res; } #endif