From: John Tsiombikas Date: Mon, 10 Dec 2018 17:42:58 +0000 (+0200) Subject: added libanim, and moved gph-cmath into libs/cgmath X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=commitdiff_plain;h=3c8a42c780f4fb7817badbc136f7312aa20dd5ef added libanim, and moved gph-cmath into libs/cgmath --- diff --git a/libs/anim/GNUmakefile b/libs/anim/GNUmakefile new file mode 100644 index 0000000..b795392 --- /dev/null +++ b/libs/anim/GNUmakefile @@ -0,0 +1,12 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +alib = libanim.a + +CFLAGS = -Wno-main -g -I.. -I../../src + +$(alib): $(obj) + $(AR) rcs $@ $(obj) + +.PHONY: clean +clean: + rm -f $(obj) $(alib) diff --git a/libs/anim/Makefile b/libs/anim/Makefile new file mode 100644 index 0000000..657e083 --- /dev/null +++ b/libs/anim/Makefile @@ -0,0 +1,27 @@ +obj = anim.obj track.obj +alib = anim.lib + +def = -dM_PI=3.141592653589793 +opt = -5 -fp5 -otexan -I.. -I../../src $(def) +dbg = -d1 + +!ifdef __UNIX__ +RM = rm -f +!else +RM = del +!endif + +CC = wcc386 +CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos + +$(alib): $(obj) + wlib -b -n $@ $(obj) + +.c: src + +.c.obj: .autodepend + $(CC) -fo=$@ $(CFLAGS) $[* + +clean: .symbolic + $(RM) *.obj + $(RM) $(alib) diff --git a/libs/anim/Makefile.dj b/libs/anim/Makefile.dj new file mode 100644 index 0000000..e73b990 --- /dev/null +++ b/libs/anim/Makefile.dj @@ -0,0 +1,30 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.cof) +alib = anim.dja + +ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM) + hostsys = dos +else + hostsys = unix + TOOLPREFIX = i586-pc-msdosdjgpp- +endif + +CC = $(TOOLPREFIX)gcc +AR = $(TOOLPREFIX)ar +CFLAGS = -Wno-main -march=pentium -g -O3 -ffast-math -I.. -I../../src + +$(alib): $(obj) + $(AR) rcs $@ $(obj) + +%.cof: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +.PHONY: clean +ifeq ($(hostsys), dos) +clean: + del src\*.cof + del $(alib) +else +clean: + rm -f $(obj) $(alib) +endif diff --git a/libs/anim/src/anim.c b/libs/anim/src/anim.c new file mode 100644 index 0000000..a2f1944 --- /dev/null +++ b/libs/anim/src/anim.c @@ -0,0 +1,1020 @@ +/* +libanim - hierarchical keyframe animation library +Copyright (C) 2012-2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +*/ +#include +#include +#include +#include +#include "anim.h" +#include "dynarr.h" + +#include "cgmath/cgmath.h" + +#define ROT_USE_SLERP + +static void invalidate_cache(struct anm_node *node); + +int anm_init_animation(struct anm_animation *anim) +{ + int i, j; + static const float defaults[] = { + 0.0f, 0.0f, 0.0f, /* default position */ + 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */ + 1.0f, 1.0f, 1.0f /* default scale factor */ + }; + + anim->name = 0; + + for(i=0; itracks + i) == -1) { + for(j=0; jtracks + i); + } + } + anm_set_track_default(anim->tracks + i, defaults[i]); + } + return 0; +} + +void anm_destroy_animation(struct anm_animation *anim) +{ + int i; + for(i=0; itracks + i); + } + free(anim->name); +} + +void anm_set_animation_name(struct anm_animation *anim, const char *name) +{ + char *newname = malloc(strlen(name) + 1); + if(!newname) return; + + strcpy(newname, name); + + free(anim->name); + anim->name = newname; +} + +/* ---- node implementation ----- */ + +int anm_init_node(struct anm_node *node) +{ + memset(node, 0, sizeof *node); + + node->cur_anim[1] = -1; + + if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) { + return -1; + } + if(anm_init_animation(node->animations) == -1) { + dynarr_free(node->animations); + return -1; + } + +#ifdef ANIM_THREAD_SAFE + /* initialize thread-local matrix cache */ + pthread_key_create(&node->cache_key, 0); + pthread_mutex_init(&node->cache_list_lock, 0); +#endif + + return 0; +} + +void anm_destroy_node(struct anm_node *node) +{ + int i, num_anim; + free(node->name); + + num_anim = anm_get_animation_count(node); + for(i=0; ianimations + i); + } + dynarr_free(node->animations); + +#ifdef ANIM_THREAD_SAFE + /* destroy thread-specific cache */ + pthread_key_delete(node->cache_key); + + while(node->cache_list) { + struct mat_cache *tmp = node->cache_list; + node->cache_list = tmp->next; + free(tmp); + } +#endif +} + +void anm_destroy_node_tree(struct anm_node *tree) +{ + struct anm_node *c, *tmp; + + if(!tree) return; + + c = tree->child; + while(c) { + tmp = c; + c = c->next; + + anm_destroy_node_tree(tmp); + } + anm_destroy_node(tree); +} + +struct anm_node *anm_create_node(void) +{ + struct anm_node *n; + + if((n = malloc(sizeof *n))) { + if(anm_init_node(n) == -1) { + free(n); + return 0; + } + } + return n; +} + +void anm_free_node(struct anm_node *node) +{ + anm_destroy_node(node); + free(node); +} + +void anm_free_node_tree(struct anm_node *tree) +{ + struct anm_node *c, *tmp; + + if(!tree) return; + + c = tree->child; + while(c) { + tmp = c; + c = c->next; + + anm_free_node_tree(tmp); + } + + anm_free_node(tree); +} + +int anm_set_node_name(struct anm_node *node, const char *name) +{ + char *str; + + if(!(str = malloc(strlen(name) + 1))) { + return -1; + } + strcpy(str, name); + free(node->name); + node->name = str; + return 0; +} + +const char *anm_get_node_name(struct anm_node *node) +{ + return node->name ? node->name : ""; +} + +void anm_link_node(struct anm_node *p, struct anm_node *c) +{ + c->next = p->child; + p->child = c; + + c->parent = p; + invalidate_cache(c); +} + +int anm_unlink_node(struct anm_node *p, struct anm_node *c) +{ + struct anm_node *iter; + + if(p->child == c) { + p->child = c->next; + c->next = 0; + invalidate_cache(c); + return 0; + } + + iter = p->child; + while(iter->next) { + if(iter->next == c) { + iter->next = c->next; + c->next = 0; + invalidate_cache(c); + return 0; + } + } + return -1; +} + +void anm_set_pivot(struct anm_node *node, float x, float y, float z) +{ + node->pivot[0] = x; + node->pivot[1] = y; + node->pivot[2] = z; +} + +void anm_get_pivot(struct anm_node *node, float *x, float *y, float *z) +{ + *x = node->pivot[0]; + *y = node->pivot[1]; + *z = node->pivot[2]; +} + + +/* animation management */ + +int anm_use_node_animation(struct anm_node *node, int aidx) +{ + if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) { + return 0; /* no change, no invalidation */ + } + + if(aidx < 0 || aidx >= anm_get_animation_count(node)) { + return -1; + } + + node->cur_anim[0] = aidx; + node->cur_anim[1] = -1; + node->cur_mix = 0; + node->blend_dur = -1; + + invalidate_cache(node); + return 0; +} + +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t) +{ + int num_anim; + + if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx && + fabs(t - node->cur_mix) < 1e-6) { + return 0; /* no change, no invalidation */ + } + + num_anim = anm_get_animation_count(node); + if(aidx < 0 || aidx >= num_anim) { + return anm_use_animation(node, bidx); + } + if(bidx < 0 || bidx >= num_anim) { + return anm_use_animation(node, aidx); + } + node->cur_anim[0] = aidx; + node->cur_anim[1] = bidx; + node->cur_mix = t; + + invalidate_cache(node); + return 0; +} + +int anm_use_animation(struct anm_node *node, int aidx) +{ + struct anm_node *child; + + if(anm_use_node_animation(node, aidx) == -1) { + return -1; + } + + child = node->child; + while(child) { + if(anm_use_animation(child, aidx) == -1) { + return -1; + } + child = child->next; + } + return 0; +} + +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t) +{ + struct anm_node *child; + + if(anm_use_node_animations(node, aidx, bidx, t) == -1) { + return -1; + } + + child = node->child; + while(child) { + if(anm_use_animations(child, aidx, bidx, t) == -1) { + return -1; + } + child = child->next; + } + return 0; + +} + +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which) +{ + if(which < 0 || which >= 2) { + return; + } + node->cur_anim_offset[which] = offs; +} + +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which) +{ + if(which < 0 || which >= 2) { + return 0; + } + return node->cur_anim_offset[which]; +} + +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which) +{ + struct anm_node *c = node->child; + while(c) { + anm_set_animation_offset(c, offs, which); + c = c->next; + } + + anm_set_node_animation_offset(node, offs, which); +} + +int anm_get_active_animation_index(const struct anm_node *node, int which) +{ + if(which < 0 || which >= 2) return -1; + return node->cur_anim[which]; +} + +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which) +{ + int idx = anm_get_active_animation_index(node, which); + if(idx < 0 || idx >= anm_get_animation_count(node)) { + return 0; + } + return node->animations + idx; +} + +float anm_get_active_animation_mix(const struct anm_node *node) +{ + return node->cur_mix; +} + +int anm_get_animation_count(const struct anm_node *node) +{ + return dynarr_size(node->animations); +} + +int anm_add_node_animation(struct anm_node *node) +{ + struct anm_animation newanim; + anm_init_animation(&newanim); + + node->animations = dynarr_push(node->animations, &newanim); + return 0; +} + +int anm_remove_node_animation(struct anm_node *node, int idx) +{ + fprintf(stderr, "anm_remove_animation: unimplemented!"); + abort(); + return 0; +} + +int anm_add_animation(struct anm_node *node) +{ + struct anm_node *child; + + if(anm_add_node_animation(node) == -1) { + return -1; + } + + child = node->child; + while(child) { + if(anm_add_animation(child)) { + return -1; + } + child = child->next; + } + return 0; +} + +int anm_remove_animation(struct anm_node *node, int idx) +{ + struct anm_node *child; + + if(anm_remove_node_animation(node, idx) == -1) { + return -1; + } + + child = node->child; + while(child) { + if(anm_remove_animation(child, idx) == -1) { + return -1; + } + child = child->next; + } + return 0; +} + +struct anm_animation *anm_get_animation(struct anm_node *node, int idx) +{ + if(idx < 0 || idx > anm_get_animation_count(node)) { + return 0; + } + return node->animations + idx; +} + +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name) +{ + return anm_get_animation(node, anm_find_animation(node, name)); +} + +int anm_find_animation(struct anm_node *node, const char *name) +{ + int i, count = anm_get_animation_count(node); + for(i=0; ianimations[i].name, name) == 0) { + return i; + } + } + return -1; +} + +/* all the rest act on the current animation(s) */ + +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in) +{ + int i; + struct anm_animation *anim = anm_get_active_animation(node, 0); + if(!anim) return; + + for(i=0; itracks + i, in); + } + invalidate_cache(node); +} + +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex) +{ + int i; + struct anm_animation *anim = anm_get_active_animation(node, 0); + if(!anim) return; + + for(i=0; itracks + i, ex); + } + invalidate_cache(node); +} + +void anm_set_node_active_animation_name(struct anm_node *node, const char *name) +{ + struct anm_animation *anim = anm_get_active_animation(node, 0); + if(!anim) return; + + anm_set_animation_name(anim, name); +} + +void anm_set_active_animation_name(struct anm_node *node, const char *name) +{ + struct anm_node *child; + + anm_set_node_active_animation_name(node, name); + + child = node->child; + while(child) { + anm_set_active_animation_name(child, name); + child = child->next; + } +} + +const char *anm_get_active_animation_name(struct anm_node *node) +{ + struct anm_animation *anim = anm_get_active_animation(node, 0); + if(anim) { + return anim->name; + } + return 0; +} + +/* ---- high level animation blending ---- */ +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur) +{ + struct anm_node *c = node->child; + + if(anmidx == node->cur_anim[0]) { + return; + } + + while(c) { + anm_transition(c, anmidx, start, dur); + c = c->next; + } + + anm_node_transition(node, anmidx, start, dur); +} + +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur) +{ + if(anmidx == node->cur_anim[0]) { + return; + } + + node->cur_anim[1] = anmidx; + node->cur_anim_offset[1] = start; + node->blend_dur = dur; +} + + +#define BLEND_START_TM node->cur_anim_offset[1] + +static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which) +{ + float t; + + if(node->blend_dur >= 0) { + /* we're in transition... */ + t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur; + if(t < 0.0) t = 0.0; + + node->cur_mix = t; + + if(t > 1.0) { + /* switch completely over to the target animation and stop blending */ + anm_use_node_animation(node, node->cur_anim[1]); + node->cur_anim_offset[0] = node->cur_anim_offset[1]; + } + } + + return tm - node->cur_anim_offset[which]; +} + + +void anm_set_position(struct anm_node *node, const float *pos, anm_time_t tm) +{ + anm_set_position3f(node, pos[0], pos[1], pos[2], tm); +} + +void anm_set_position3f(struct anm_node *node, float x, float y, float z, anm_time_t tm) +{ + struct anm_animation *anim = anm_get_active_animation(node, 0); + if(!anim) return; + + anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, x); + anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, y); + anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, z); + invalidate_cache(node); +} + +void anm_get_node_position(struct anm_node *node, float *pos, anm_time_t tm) +{ + anm_time_t tm0 = animation_time(node, tm, 0); + struct anm_animation *anim0 = anm_get_active_animation(node, 0); + struct anm_animation *anim1 = anm_get_active_animation(node, 1); + + if(!anim0) { + pos[0] = pos[1] = pos[2] = 0.0f; + return; + } + + pos[0] = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0); + pos[1] = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0); + pos[2] = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0); + + if(anim1) { + anm_time_t tm1 = animation_time(node, tm, 1); + float x1 = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1); + float y1 = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1); + float z1 = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1); + + pos[0] = pos[0] + (x1 - pos[0]) * node->cur_mix; + pos[1] = pos[1] + (y1 - pos[1]) * node->cur_mix; + pos[2] = pos[2] + (z1 - pos[2]) * node->cur_mix; + } +} + +void anm_set_rotation(struct anm_node *node, const float *qrot, anm_time_t tm) +{ + anm_set_rotation4f(node, qrot[0], qrot[1], qrot[2], qrot[3], tm); +} + +void anm_set_rotation4f(struct anm_node *node, float x, float y, float z, float w, anm_time_t tm) +{ + struct anm_animation *anim = anm_get_active_animation(node, 0); + if(!anim) return; + + anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, x); + anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, y); + anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, z); + anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, w); + invalidate_cache(node); +} + +void anm_set_rotation_axis(struct anm_node *node, float angle, float x, float y, float z, anm_time_t tm) +{ + cgm_quat q; + cgm_vec3 axis; + + cgm_vcons(&axis, x, y, z); + cgm_qrotation(&q, &axis, angle); + + anm_set_rotation(node, (float*)&q, tm); +} + +static void get_node_rotation(cgm_quat *qres, struct anm_node *node, anm_time_t tm, struct anm_animation *anim) +{ +#ifndef ROT_USE_SLERP + qres->x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm); + qres->y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm); + qres->z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm); + qres->w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm); +#else + int idx0, idx1, last_idx; + anm_time_t tstart, tend; + float t, dt; + struct anm_track *track_x, *track_y, *track_z, *track_w; + cgm_quat q1, q2; + + track_x = anim->tracks + ANM_TRACK_ROT_X; + track_y = anim->tracks + ANM_TRACK_ROT_Y; + track_z = anim->tracks + ANM_TRACK_ROT_Z; + track_w = anim->tracks + ANM_TRACK_ROT_W; + + if(!track_x->count) { + qres->x = track_x->def_val; + qres->y = track_y->def_val; + qres->z = track_z->def_val; + qres->w = track_w->def_val; + return; + } + + last_idx = track_x->count - 1; + + tstart = track_x->keys[0].time; + tend = track_x->keys[last_idx].time; + + if(tstart == tend) { + qres->x = track_x->keys[0].val; + qres->y = track_y->keys[0].val; + qres->z = track_z->keys[0].val; + qres->w = track_w->keys[0].val; + return; + } + + tm = anm_remap_time(track_x, tm, tstart, tend); + + idx0 = anm_get_key_interval(track_x, tm); + assert(idx0 >= 0 && idx0 < track_x->count); + idx1 = idx0 + 1; + + if(idx0 == last_idx) { + qres->x = track_x->keys[idx0].val; + qres->y = track_y->keys[idx0].val; + qres->z = track_z->keys[idx0].val; + qres->w = track_w->keys[idx0].val; + return; + } + + dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time); + t = (float)(tm - track_x->keys[idx0].time) / dt; + + q1.x = track_x->keys[idx0].val; + q1.y = track_y->keys[idx0].val; + q1.z = track_z->keys[idx0].val; + q1.w = track_w->keys[idx0].val; + + q2.x = track_x->keys[idx1].val; + q2.y = track_y->keys[idx1].val; + q2.z = track_z->keys[idx1].val; + q2.w = track_w->keys[idx1].val; + + cgm_qslerp(qres, &q1, &q2, t); +#endif +} + +//get_node_rotation(cgm_quat *qres, struct anm_node *node, anm_time_t tm, struct anm_animation *anim) +void anm_get_node_rotation(struct anm_node *node, float *qrot, anm_time_t tm) +{ + anm_time_t tm0 = animation_time(node, tm, 0); + struct anm_animation *anim0 = anm_get_active_animation(node, 0); + struct anm_animation *anim1 = anm_get_active_animation(node, 1); + + if(!anim0) { + qrot[0] = qrot[1] = qrot[2] = 0.0f; + qrot[3] = 1.0f; + return; + } + + + if(anim1) { + cgm_quat q0, q1; + anm_time_t tm1 = animation_time(node, tm, 1); + + get_node_rotation(&q0, node, tm0, anim0); + get_node_rotation(&q1, node, tm1, anim1); + + cgm_qslerp((cgm_quat*)qrot, &q0, &q1, node->cur_mix); + } else { + get_node_rotation((cgm_quat*)qrot, node, tm0, anim0); + } +} + +void anm_set_scaling(struct anm_node *node, const float *scale, anm_time_t tm) +{ + anm_set_scaling3f(node, scale[0], scale[1], scale[2], tm); +} + +void anm_set_scaling3f(struct anm_node *node, float x, float y, float z, anm_time_t tm) +{ + struct anm_animation *anim = anm_get_active_animation(node, 0); + if(!anim) return; + + anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, x); + anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, y); + anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, z); + invalidate_cache(node); +} + +void anm_get_node_scaling(struct anm_node *node, float *scale, anm_time_t tm) +{ + anm_time_t tm0 = animation_time(node, tm, 0); + struct anm_animation *anim0 = anm_get_active_animation(node, 0); + struct anm_animation *anim1 = anm_get_active_animation(node, 1); + + if(!anim0) { + scale[0] = scale[1] = scale[2] = 1.0f; + return; + } + + scale[0] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0); + scale[1] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0); + scale[2] = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0); + + if(anim1) { + anm_time_t tm1 = animation_time(node, tm, 1); + float x1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1); + float y1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1); + float z1 = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1); + + scale[0] = scale[0] + (x1 - scale[0]) * node->cur_mix; + scale[1] = scale[1] + (y1 - scale[1]) * node->cur_mix; + scale[2] = scale[2] + (z1 - scale[2]) * node->cur_mix; + } +} + +void anm_get_position(struct anm_node *node, float *pos, anm_time_t tm) +{ + if(!node->parent) { + anm_get_node_position(node, pos, tm); + } else { + float xform[16]; + anm_get_matrix(node, xform, tm); + cgm_mget_translation(xform, (cgm_vec3*)pos); + } +} + +void anm_get_rotation(struct anm_node *node, float *qrot, anm_time_t tm) +{ + if(!node->parent) { + anm_get_node_rotation(node, qrot, tm); + } else { + cgm_quat rot; + anm_get_node_rotation(node, &rot.x, tm); + anm_get_rotation(node->parent, qrot, tm); + cgm_qmul((cgm_quat*)qrot, &rot); + } +} + +void anm_get_scaling(struct anm_node *node, float *scale, anm_time_t tm) +{ + anm_get_node_scaling(node, scale, tm); + if(node->parent) { + cgm_vec3 ps; + anm_get_scaling(node->parent, &ps.x, tm); + cgm_vmul((cgm_vec3*)scale, &ps); + } +} + +void anm_get_node_matrix(struct anm_node *node, float *mat, anm_time_t tm) +{ + int i; + float rmat[16]; + cgm_vec3 pos, scale; + cgm_quat rot; + + anm_get_node_position(node, &pos.x, tm); + anm_get_node_rotation(node, &rot.x, tm); + anm_get_node_scaling(node, &scale.x, tm); + + cgm_mtranslation(mat, node->pivot[0], node->pivot[1], node->pivot[2]); + cgm_mrotation_quat(rmat, &rot); + + /* + for(i=0; i<3; i++) { + mat[i * 4] = rmat[i * 4]; + mat[i * 4 + 1] = rmat[i * 4 + 1]; + mat[i * 4 + 2] = rmat[i * 4 + 2]; + } + */ + for(i=0; i<3; i++) { + mat[i] = rmat[i]; + mat[4 + i] = rmat[4 + i]; + mat[8 + i] = rmat[8 + i]; + } + + mat[0] *= scale.x; mat[4] *= scale.y; mat[8] *= scale.z; mat[12] += pos.x; + mat[1] *= scale.x; mat[5] *= scale.y; mat[9] *= scale.z; mat[13] += pos.y; + mat[2] *= scale.x; mat[6] *= scale.y; mat[10] *= scale.z; mat[14] += pos.z; + + cgm_mpretranslate(mat, -node->pivot[0], -node->pivot[1], -node->pivot[2]); + + /* that's basically: pivot * rotation * translation * scaling * -pivot */ +} + +void anm_get_node_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm) +{ + anm_get_node_matrix(node, mat, tm); + cgm_minverse(mat); +} + +void anm_eval_node(struct anm_node *node, anm_time_t tm) +{ + anm_get_node_matrix(node, node->matrix, tm); +} + +void anm_eval(struct anm_node *node, anm_time_t tm) +{ + struct anm_node *c; + + anm_eval_node(node, tm); + + if(node->parent) { + /* due to post-order traversal, the parent matrix is already evaluated */ + cgm_mmul(node->matrix, node->parent->matrix); + } + + /* recersively evaluate all children */ + c = node->child; + while(c) { + anm_eval(c, tm); + c = c->next; + } +} + +float *anm_get_matrix(struct anm_node *node, float *mat, anm_time_t tm) +{ +#ifdef ANIM_THREAD_SAFE + struct mat_cache *cache = pthread_getspecific(node->cache_key); + if(!cache) { + cache = malloc(sizeof *cache); + assert(cache); + + pthread_mutex_lock(&node->cache_list_lock); + cache->next = node->cache_list; + node->cache_list = cache; + pthread_mutex_unlock(&node->cache_list_lock); + + cache->time = ANM_TIME_INVAL; + cache->inv_time = ANM_TIME_INVAL; + pthread_setspecific(node->cache_key, cache); + } +#else + struct mat_cache *cache = &node->cache; +#endif + + if(cache->time != tm) { + anm_get_node_matrix(node, cache->matrix, tm); + + if(node->parent) { + float parent_mat[16]; + + anm_get_matrix(node->parent, parent_mat, tm); + cgm_mmul(cache->matrix, parent_mat); + } + cache->time = tm; + } + + if(mat) { + cgm_mcopy(mat, cache->matrix); + } + return cache->matrix; +} + +float *anm_get_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm) +{ +#ifdef ANIM_THREAD_SAFE + struct mat_cache *cache = pthread_getspecific(node->cache_key); + if(!cache) { + cache = malloc(sizeof *cache); + assert(cache); + + pthread_mutex_lock(&node->cache_list_lock); + cache->next = node->cache_list; + node->cache_list = cache; + pthread_mutex_unlock(&node->cache_list_lock); + + cache->inv_time = ANM_TIME_INVAL; + cache->inv_time = ANM_TIME_INVAL; + pthread_setspecific(node->cache_key, cache); + } +#else + struct mat_cache *cache = &node->cache; +#endif + + if(cache->inv_time != tm) { + anm_get_matrix(node, cache->inv_matrix, tm); + cgm_minverse(cache->inv_matrix); + cache->inv_time = tm; + } + + if(mat) { + cgm_mcopy(mat, cache->inv_matrix); + } + return cache->inv_matrix; +} + +anm_time_t anm_get_start_time(struct anm_node *node) +{ + int i, j; + struct anm_node *c; + anm_time_t res = LONG_MAX; + + for(j=0; j<2; j++) { + struct anm_animation *anim = anm_get_active_animation(node, j); + if(!anim) break; + + for(i=0; itracks[i].count) { + anm_time_t tm = anim->tracks[i].keys[0].time; + if(tm < res) { + res = tm; + } + } + } + } + + c = node->child; + while(c) { + anm_time_t tm = anm_get_start_time(c); + if(tm < res) { + res = tm; + } + c = c->next; + } + return res; +} + +anm_time_t anm_get_end_time(struct anm_node *node) +{ + int i, j; + struct anm_node *c; + anm_time_t res = LONG_MIN; + + for(j=0; j<2; j++) { + struct anm_animation *anim = anm_get_active_animation(node, j); + if(!anim) break; + + for(i=0; itracks[i].count) { + anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time; + if(tm > res) { + res = tm; + } + } + } + } + + c = node->child; + while(c) { + anm_time_t tm = anm_get_end_time(c); + if(tm > res) { + res = tm; + } + c = c->next; + } + return res; +} + +static void invalidate_cache(struct anm_node *node) +{ + struct anm_node *c; + +#ifdef ANIM_THREAD_SAFE + struct mat_cache *cache = pthread_getspecific(node->cache_key); + if(cache) { + cache->time = cache->inv_time = ANM_TIME_INVAL; + } +#else + node->cache.time = node->cache.inv_time = ANM_TIME_INVAL; +#endif + + c = node->child; + while(c) { + invalidate_cache(c); + c = c->next; + } +} diff --git a/libs/anim/src/anim.h b/libs/anim/src/anim.h new file mode 100644 index 0000000..e5433f7 --- /dev/null +++ b/libs/anim/src/anim.h @@ -0,0 +1,250 @@ +/* +libanim - hierarchical keyframe animation library +Copyright (C) 2012-2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +*/ +#ifndef LIBANIM_H_ +#define LIBANIM_H_ + +#include "config.h" + +#if _MSC_VER >= 1900 +#define _TIMESPEC_DEFINED +#endif + +#ifdef ANIM_THREAD_SAFE +#include +#endif + +#include "track.h" + +enum { + ANM_TRACK_POS_X, + ANM_TRACK_POS_Y, + ANM_TRACK_POS_Z, + + ANM_TRACK_ROT_X, + ANM_TRACK_ROT_Y, + ANM_TRACK_ROT_Z, + ANM_TRACK_ROT_W, + + ANM_TRACK_SCL_X, + ANM_TRACK_SCL_Y, + ANM_TRACK_SCL_Z, + + ANM_NUM_TRACKS +}; + +struct anm_animation { + char *name; + struct anm_track tracks[ANM_NUM_TRACKS]; +}; + +struct anm_node { + char *name; + + int cur_anim[2]; + anm_time_t cur_anim_offset[2]; + float cur_mix; + + /* high-level animation blending transition duration */ + anm_time_t blend_dur; + + struct anm_animation *animations; + float pivot[3]; + + /* matrix cache */ + struct mat_cache { + float matrix[16], inv_matrix[16]; + anm_time_t time, inv_time; + struct mat_cache *next; +#ifdef ANIM_THREAD_SAFE + } *cache_list; + pthread_key_t cache_key; + pthread_mutex_t cache_list_lock; +#else + } cache; +#endif + + /* matrix calculated by anm_eval functions (no locking, meant as a pre-pass) */ + float matrix[16]; + + struct anm_node *parent; + struct anm_node *child; + struct anm_node *next; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int anm_init_animation(struct anm_animation *anim); +void anm_destroy_animation(struct anm_animation *anim); + +void anm_set_animation_name(struct anm_animation *anim, const char *name); + + +/* ---- node/hierarchy management ---- */ + +/* node constructor and destructor */ +int anm_init_node(struct anm_node *node); +void anm_destroy_node(struct anm_node *node); + +/* recursively destroy an animation node tree */ +void anm_destroy_node_tree(struct anm_node *tree); + +/* helper functions to allocate/construct and destroy/free with + * a single call. They call anm_init_node and anm_destroy_node + * internally. + */ +struct anm_node *anm_create_node(void); +void anm_free_node(struct anm_node *node); + +/* recursively destroy and free the nodes of a node tree */ +void anm_free_node_tree(struct anm_node *tree); + +int anm_set_node_name(struct anm_node *node, const char *name); +const char *anm_get_node_name(struct anm_node *node); + +/* link and unlink nodes with parent/child relations */ +void anm_link_node(struct anm_node *parent, struct anm_node *child); +int anm_unlink_node(struct anm_node *parent, struct anm_node *child); + +void anm_set_pivot(struct anm_node *node, float x, float y, float z); +void anm_get_pivot(struct anm_node *node, float *x, float *y, float *z); + +/* ---- multiple animations and animation blending ---- */ + +/* set active animation(s) */ +int anm_use_node_animation(struct anm_node *node, int aidx); +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t); +/* recursive variants */ +int anm_use_animation(struct anm_node *node, int aidx); +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t); + +/* set/get current animation offset(s) */ +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which); +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which); +/* recursive variant */ +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which); + +/* returns the requested current animation index, which can be 0 or 1 */ +int anm_get_active_animation_index(const struct anm_node *node, int which); +/* returns the requested current animation, which can be 0 or 1 */ +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which); +float anm_get_active_animation_mix(const struct anm_node *node); + +int anm_get_animation_count(const struct anm_node *node); + +/* add/remove an animation to the specified node */ +int anm_add_node_animation(struct anm_node *node); +int anm_remove_node_animation(struct anm_node *node, int idx); + +/* add/remove an animation to the specified node and all it's descendants */ +int anm_add_animation(struct anm_node *node); +int anm_remove_animation(struct anm_node *node, int idx); + +struct anm_animation *anm_get_animation(struct anm_node *node, int idx); +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name); + +int anm_find_animation(struct anm_node *node, const char *name); + +/* set the interpolator for the (first) currently active animation */ +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in); +/* set the extrapolator for the (first) currently active animation */ +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex); + +/* set the name of the currently active animation of this node only */ +void anm_set_node_active_animation_name(struct anm_node *node, const char *name); +/* recursively set the name of the currently active animation for this node + * and all it's descendants */ +void anm_set_active_animation_name(struct anm_node *node, const char *name); +/* get the name of the currently active animation of this node */ +const char *anm_get_active_animation_name(struct anm_node *node); + + +/* ---- high level animation blending interface ---- */ +/* XXX this convenience interface assumes monotonically increasing time values + * in all subsequent calls to anm_get_* and anm_eval_* functions. + * + * anmidx: index of the animation to transition to + * start: when to start the transition + * dur: transition duration + * + * sets up a transition from the current animation (cur_anim[0]) to another animation. + * at time start + dur, the transition will be completed, cur_anim[0] will be the new + * animation and cur_anim_offset[0] will be equal to start. + */ +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur); +/* non-recursive variant, acts on a single node (you probably DON'T want to use this) */ +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur); + + +/* ---- keyframes / PRS interpolation ---- */ + +void anm_set_position(struct anm_node *node, const float *pos, anm_time_t tm); +void anm_set_position3f(struct anm_node *node, float x, float y, float z, anm_time_t tm); +void anm_get_node_position(struct anm_node *node, float *pos, anm_time_t tm); + +void anm_set_rotation(struct anm_node *node, const float *qrot, anm_time_t tm); +void anm_set_rotation4f(struct anm_node *node, float x, float y, float z, float w, anm_time_t tm); +void anm_set_rotation_axis(struct anm_node *node, float angle, float x, float y, float z, anm_time_t tm); +void anm_get_node_rotation(struct anm_node *node, float *qrot, anm_time_t tm); + +void anm_set_scaling(struct anm_node *node, const float *scale, anm_time_t tm); +void anm_set_scaling3f(struct anm_node *node, float x, float y, float z, anm_time_t tm); +void anm_get_node_scaling(struct anm_node *node, float *scale, anm_time_t tm); + +/* these three return the full p/r/s taking hierarchy into account */ +void anm_get_position(struct anm_node *node, float *pos, anm_time_t tm); +void anm_get_rotation(struct anm_node *node, float *qrot, anm_time_t tm); +void anm_get_scaling(struct anm_node *node, float *scale, anm_time_t tm); + +/* those return the start and end times of the whole tree */ +anm_time_t anm_get_start_time(struct anm_node *node); +anm_time_t anm_get_end_time(struct anm_node *node); + + +/* ---- transformation matrices ---- */ + +/* these calculate the matrix and inverse matrix of this node alone */ +void anm_get_node_matrix(struct anm_node *node, float *mat, anm_time_t tm); +void anm_get_node_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm); + +/* ---- top-down matrix calculation interface ---- */ + +/* calculate and set the matrix of this node */ +void anm_eval_node(struct anm_node *node, anm_time_t tm); +/* calculate and set the matrix of this node and all its children recursively */ +void anm_eval(struct anm_node *node, anm_time_t tm); + + +/* ---- bottom-up lazy matrix calculation interface ---- */ + +/* These calculate the matrix and inverse matrix of this node taking hierarchy + * into account. The results are cached in thread-specific storage and returned + * if there's no change in time or tracks from the last query... + * + * A pointer to the internal cached matrix is returned, and also if mat is not + * null, the matrix is copied there. + */ +float *anm_get_matrix(struct anm_node *node, float *mat, anm_time_t tm); +float *anm_get_inv_matrix(struct anm_node *node, float *mat, anm_time_t tm); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBANIM_H_ */ diff --git a/libs/anim/src/config.h b/libs/anim/src/config.h new file mode 100644 index 0000000..f00310c --- /dev/null +++ b/libs/anim/src/config.h @@ -0,0 +1,6 @@ +#ifndef ANIM_CONFIG_H_ +#define ANIM_CONFIG_H_ + +#undef ANIM_THREAD_SAFE + +#endif /* ANIM_CONFIG_H_ */ diff --git a/libs/anim/src/track.c b/libs/anim/src/track.c new file mode 100644 index 0000000..a144efd --- /dev/null +++ b/libs/anim/src/track.c @@ -0,0 +1,334 @@ +/* +libanim - hierarchical keyframe animation library +Copyright (C) 2012-2015 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include "track.h" +#include "dynarr.h" + +static int keycmp(const void *a, const void *b); +static int find_prev_key(struct anm_keyframe *arr, int start, int end, anm_time_t tm); + +static float interp_step(float v0, float v1, float v2, float v3, float t); +static float interp_linear(float v0, float v1, float v2, float v3, float t); +static float interp_cubic(float v0, float v1, float v2, float v3, float t); + +static anm_time_t remap_extend(anm_time_t tm, anm_time_t start, anm_time_t end); +static anm_time_t remap_clamp(anm_time_t tm, anm_time_t start, anm_time_t end); +static anm_time_t remap_repeat(anm_time_t tm, anm_time_t start, anm_time_t end); +static anm_time_t remap_pingpong(anm_time_t tm, anm_time_t start, anm_time_t end); + +/* XXX keep this in sync with enum anm_interpolator at track.h */ +static float (*interp[])(float, float, float, float, float) = { + interp_step, + interp_linear, + interp_cubic, + 0 +}; + +/* XXX keep this in sync with enum anm_extrapolator at track.h */ +static anm_time_t (*remap_time[])(anm_time_t, anm_time_t, anm_time_t) = { + remap_extend, + remap_clamp, + remap_repeat, + remap_pingpong, + 0 +}; + +int anm_init_track(struct anm_track *track) +{ + memset(track, 0, sizeof *track); + + if(!(track->keys = dynarr_alloc(0, sizeof *track->keys))) { + return -1; + } + track->interp = ANM_INTERP_LINEAR; + track->extrap = ANM_EXTRAP_CLAMP; + return 0; +} + +void anm_destroy_track(struct anm_track *track) +{ + dynarr_free(track->keys); +} + +struct anm_track *anm_create_track(void) +{ + struct anm_track *track; + + if((track = malloc(sizeof *track))) { + if(anm_init_track(track) == -1) { + free(track); + return 0; + } + } + return track; +} + +void anm_free_track(struct anm_track *track) +{ + anm_destroy_track(track); + free(track); +} + +void anm_copy_track(struct anm_track *dest, const struct anm_track *src) +{ + free(dest->name); + if(dest->keys) { + dynarr_free(dest->keys); + } + + if(src->name) { + dest->name = malloc(strlen(src->name) + 1); + strcpy(dest->name, src->name); + } + + dest->count = src->count; + dest->keys = dynarr_alloc(src->count, sizeof *dest->keys); + memcpy(dest->keys, src->keys, src->count * sizeof *dest->keys); + + dest->def_val = src->def_val; + dest->interp = src->interp; + dest->extrap = src->extrap; +} + +int anm_set_track_name(struct anm_track *track, const char *name) +{ + char *tmp; + + if(!(tmp = malloc(strlen(name) + 1))) { + return -1; + } + free(track->name); + track->name = tmp; + return 0; +} + +const char *anm_get_track_name(struct anm_track *track) +{ + return track->name; +} + +void anm_set_track_interpolator(struct anm_track *track, enum anm_interpolator in) +{ + track->interp = in; +} + +void anm_set_track_extrapolator(struct anm_track *track, enum anm_extrapolator ex) +{ + track->extrap = ex; +} + +anm_time_t anm_remap_time(struct anm_track *track, anm_time_t tm, anm_time_t start, anm_time_t end) +{ + return remap_time[track->extrap](tm, start, end); +} + +void anm_set_track_default(struct anm_track *track, float def) +{ + track->def_val = def; +} + +int anm_set_keyframe(struct anm_track *track, struct anm_keyframe *key) +{ + int idx = anm_get_key_interval(track, key->time); + + /* if we got a valid keyframe index, compare them... */ + if(idx >= 0 && idx < track->count && keycmp(key, track->keys + idx) == 0) { + /* ... it's the same key, just update the value */ + track->keys[idx].val = key->val; + } else { + /* ... it's a new key, add it and re-sort them */ + void *tmp; + if(!(tmp = dynarr_push(track->keys, key))) { + return -1; + } + track->keys = tmp; + /* TODO lazy qsort */ + qsort(track->keys, ++track->count, sizeof *track->keys, keycmp); + } + return 0; +} + +static int keycmp(const void *a, const void *b) +{ + return ((struct anm_keyframe*)a)->time - ((struct anm_keyframe*)b)->time; +} + +struct anm_keyframe *anm_get_keyframe(struct anm_track *track, int idx) +{ + if(idx < 0 || idx >= track->count) { + return 0; + } + return track->keys + idx; +} + +int anm_get_key_interval(struct anm_track *track, anm_time_t tm) +{ + int last; + + if(!track->count || tm < track->keys[0].time) { + return -1; + } + + last = track->count - 1; + if(tm > track->keys[last].time) { + return last; + } + + return find_prev_key(track->keys, 0, last, tm); +} + +static int find_prev_key(struct anm_keyframe *arr, int start, int end, anm_time_t tm) +{ + int mid; + + if(end - start <= 1) { + return start; + } + + mid = (start + end) / 2; + if(tm < arr[mid].time) { + return find_prev_key(arr, start, mid, tm); + } + if(tm > arr[mid].time) { + return find_prev_key(arr, mid, end, tm); + } + return mid; +} + +int anm_set_value(struct anm_track *track, anm_time_t tm, float val) +{ + struct anm_keyframe key; + key.time = tm; + key.val = val; + + return anm_set_keyframe(track, &key); +} + +float anm_get_value(struct anm_track *track, anm_time_t tm) +{ + int idx0, idx1, last_idx; + anm_time_t tstart, tend; + float t, dt; + float v0, v1, v2, v3; + + if(!track->count) { + return track->def_val; + } + + last_idx = track->count - 1; + + tstart = track->keys[0].time; + tend = track->keys[last_idx].time; + + if(tstart == tend) { + return track->keys[0].val; + } + + tm = remap_time[track->extrap](tm, tstart, tend); + + idx0 = anm_get_key_interval(track, tm); + assert(idx0 >= 0 && idx0 < track->count); + idx1 = idx0 + 1; + + if(idx0 == last_idx) { + return track->keys[idx0].val; + } + + dt = (float)(track->keys[idx1].time - track->keys[idx0].time); + t = (float)(tm - track->keys[idx0].time) / dt; + + v1 = track->keys[idx0].val; + v2 = track->keys[idx1].val; + + /* get the neigboring values to allow for cubic interpolation */ + v0 = idx0 > 0 ? track->keys[idx0 - 1].val : v1; + v3 = idx1 < last_idx ? track->keys[idx1 + 1].val : v2; + + return interp[track->interp](v0, v1, v2, v3, t); +} + + +static float interp_step(float v0, float v1, float v2, float v3, float t) +{ + return v1; +} + +static float interp_linear(float v0, float v1, float v2, float v3, float t) +{ + return v1 + (v2 - v1) * t; +} + +static float interp_cubic(float a, float b, float c, float d, float t) +{ + float x, y, z, w; + float tsq = t * t; + + x = -a + 3.0 * b - 3.0 * c + d; + y = 2.0 * a - 5.0 * b + 4.0 * c - d; + z = c - a; + w = 2.0 * b; + + return 0.5 * (x * tsq * t + y * tsq + z * t + w); +} + +static anm_time_t remap_extend(anm_time_t tm, anm_time_t start, anm_time_t end) +{ + return remap_repeat(tm, start, end); +} + +static anm_time_t remap_clamp(anm_time_t tm, anm_time_t start, anm_time_t end) +{ + if(start == end) { + return start; + } + return tm < start ? start : (tm >= end ? end : tm); +} + +static anm_time_t remap_repeat(anm_time_t tm, anm_time_t start, anm_time_t end) +{ + anm_time_t x, interv = end - start; + + if(interv == 0) { + return start; + } + + x = (tm - start) % interv; + if(x < 0) { + x += interv; + } + return x + start; + + /*if(tm < start) { + while(tm < start) { + tm += interv; + } + return tm; + } + return (tm - start) % interv + start;*/ +} + +static anm_time_t remap_pingpong(anm_time_t tm, anm_time_t start, anm_time_t end) +{ + anm_time_t interv = end - start; + anm_time_t x = remap_repeat(tm, start, end + interv); + + return x > end ? end + interv - x : x; +} diff --git a/libs/anim/src/track.h b/libs/anim/src/track.h new file mode 100644 index 0000000..89749dd --- /dev/null +++ b/libs/anim/src/track.h @@ -0,0 +1,119 @@ +/* +libanim - hierarchical keyframe animation library +Copyright (C) 2012-2014 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +*/ + +/* An animation track defines the values of a single scalar over time + * and supports various interpolation and extrapolation modes. + */ +#ifndef LIBANIM_TRACK_H_ +#define LIBANIM_TRACK_H_ + +#include +#include "config.h" + +enum anm_interpolator { + ANM_INTERP_STEP, + ANM_INTERP_LINEAR, + ANM_INTERP_CUBIC +}; + +enum anm_extrapolator { + ANM_EXTRAP_EXTEND, /* extend to infinity */ + ANM_EXTRAP_CLAMP, /* clamp to last value */ + ANM_EXTRAP_REPEAT, /* repeat motion */ + ANM_EXTRAP_PINGPONG /* repeat with mirroring */ +}; + +typedef long anm_time_t; +#define ANM_TIME_INVAL LONG_MIN + +#define ANM_SEC2TM(x) ((anm_time_t)((x) * 1000)) +#define ANM_MSEC2TM(x) ((anm_time_t)(x)) +#define ANM_TM2SEC(x) ((x) / 1000.0) +#define ANM_TM2MSEC(x) (x) + +struct anm_keyframe { + anm_time_t time; + float val; +}; + +struct anm_track { + char *name; + int count; + struct anm_keyframe *keys; + + float def_val; + + enum anm_interpolator interp; + enum anm_extrapolator extrap; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* track constructor and destructor */ +int anm_init_track(struct anm_track *track); +void anm_destroy_track(struct anm_track *track); + +/* helper functions that use anm_init_track and anm_destroy_track internally */ +struct anm_track *anm_create_track(void); +void anm_free_track(struct anm_track *track); + +/* copies track src to dest + * XXX: dest must have been initialized first + */ +void anm_copy_track(struct anm_track *dest, const struct anm_track *src); + +int anm_set_track_name(struct anm_track *track, const char *name); +const char *anm_get_track_name(struct anm_track *track); + +void anm_set_track_interpolator(struct anm_track *track, enum anm_interpolator in); +void anm_set_track_extrapolator(struct anm_track *track, enum anm_extrapolator ex); + +anm_time_t anm_remap_time(struct anm_track *track, anm_time_t tm, anm_time_t start, anm_time_t end); + +void anm_set_track_default(struct anm_track *track, float def); + +/* set or update a keyframe */ +int anm_set_keyframe(struct anm_track *track, struct anm_keyframe *key); + +/* get the idx-th keyframe, returns null if it doesn't exist */ +struct anm_keyframe *anm_get_keyframe(struct anm_track *track, int idx); + +/* Finds the 0-based index of the intra-keyframe interval which corresponds + * to the specified time. If the time falls exactly onto the N-th keyframe + * the function returns N. + * + * Special cases: + * - if the time is before the first keyframe -1 is returned. + * - if the time is after the last keyframe, the index of the last keyframe + * is returned. + */ +int anm_get_key_interval(struct anm_track *track, anm_time_t tm); + +int anm_set_value(struct anm_track *track, anm_time_t tm, float val); + +/* evaluates and returns the value of the track for a particular time */ +float anm_get_value(struct anm_track *track, anm_time_t tm); + +#ifdef __cplusplus +} +#endif + + +#endif /* LIBANIM_TRACK_H_ */ diff --git a/libs/cgmath/cgmath.h b/libs/cgmath/cgmath.h new file mode 100644 index 0000000..e660437 --- /dev/null +++ b/libs/cgmath/cgmath.h @@ -0,0 +1,243 @@ +/* gph-cmath - C graphics math library + * Copyright (C) 2018 John Tsiombikas + * + * This program is free software. Feel free to use, modify, and/or redistribute + * it under the terms of the MIT/X11 license. See LICENSE for details. + * If you intend to redistribute parts of the code without the LICENSE file + * replace this paragraph with the full contents of the LICENSE file. + * + * Function prefixes signify the data type of their operand(s): + * - cgm_v... functions are operations on cgm_vec3 vectors + * - cgm_w... functions are operations on cgm_vec4 vectors + * - cgm_q... functions are operations on cgm_quat quaternions (w + xi + yj + zk) + * - cgm_m... functions are operations on 4x4 matrices (stored as linear 16 float arrays) + * - cgm_r... functions are operations on cgm_ray rays + * + * NOTE: *ALL* matrix arguments are pointers to 16 floats. Even the functions + * which operate on 3x3 matrices, actually use the upper 3x3 of a 4x4 matrix, + * and still expect an array of 16 floats. + * + * NOTE: matrices are treated by all operations as column-major, to match OpenGL + * conventions, so everything is pretty much transposed. +*/ +#ifndef CGMATH_H_ +#define CGMATH_H_ + +#include +#include + +typedef struct { + float x, y, z; +} cgm_vec3; + +typedef struct { + float x, y, z, w; +} cgm_vec4, cgm_quat; + +typedef struct { + cgm_vec3 origin, dir; +} cgm_ray; + +typedef enum cgm_euler_mode { + CGM_EULER_XYZ, + CGM_EULER_XZY, + CGM_EULER_YXZ, + CGM_EULER_YZX, + CGM_EULER_ZXY, + CGM_EULER_ZYX, + CGM_EULER_ZXZ, + CGM_EULER_ZYZ, + CGM_EULER_YXY, + CGM_EULER_YZY, + CGM_EULER_XYX, + CGM_EULER_XZX +} cgm_euler_mode; + +#ifdef __cplusplus +extern "C" { +#endif + +/* --- operations on cgm_vec3 --- */ +static inline void cgm_vcons(cgm_vec3 *v, float x, float y, float z); + +static inline void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b); +static inline void cgm_vsub(cgm_vec3 *a, const cgm_vec3 *b); +static inline void cgm_vmul(cgm_vec3 *a, const cgm_vec3 *b); +static inline void cgm_vscale(cgm_vec3 *v, float s); +static inline void cgm_vmul_m4v3(cgm_vec3 *v, const float *m); /* m4x4 * v */ +static inline void cgm_vmul_v3m4(cgm_vec3 *v, const float *m); /* v * m4x4 */ +static inline void cgm_vmul_m3v3(cgm_vec3 *v, const float *m); /* m3x3 * v (m still 16 floats) */ +static inline void cgm_vmul_v3m3(cgm_vec3 *v, const float *m); /* v * m3x3 (m still 16 floats) */ + +static inline float cgm_vdot(const cgm_vec3 *a, const cgm_vec3 *b); +static inline void cgm_vcross(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b); +static inline float cgm_vlength(const cgm_vec3 *v); +static inline float cgm_vlength_sq(const cgm_vec3 *v); +static inline float cgm_vdist(const cgm_vec3 *a, const cgm_vec3 *b); +static inline float cgm_vdist_sq(const cgm_vec3 *a, const cgm_vec3 *b); +static inline void cgm_vnormalize(cgm_vec3 *v); + +static inline void cgm_vreflect(cgm_vec3 *v, const cgm_vec3 *n); +static inline void cgm_vrefract(cgm_vec3 *v, const cgm_vec3 *n, float ior); + +static inline void cgm_vrotate_quat(cgm_vec3 *v, const cgm_quat *q); +static inline void cgm_vrotate_axis(cgm_vec3 *v, int axis, float angle); +static inline void cgm_vrotate(cgm_vec3 *v, float angle, float x, float y, float z); +static inline void cgm_vrotate_euler(cgm_vec3 *v, float a, float b, float c, enum cgm_euler_mode mode); + +static inline void cgm_vlerp(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b, float t); + +/* --- operations on cgm_vec4 --- */ +static inline void cgm_wcons(cgm_vec4 *v, float x, float y, float z, float w); + +static inline void cgm_wadd(cgm_vec4 *a, const cgm_vec4 *b); +static inline void cgm_wsub(cgm_vec4 *a, const cgm_vec4 *b); +static inline void cgm_wmul(cgm_vec4 *a, const cgm_vec4 *b); +static inline void cgm_wscale(cgm_vec4 *v, float s); + +static inline void cgm_wmul_m4v4(cgm_vec4 *v, const float *m); +static inline void cgm_wmul_v4m4(cgm_vec4 *v, const float *m); +static inline void cgm_wmul_m34v4(cgm_vec4 *v, const float *m); /* doesn't affect w */ +static inline void cgm_wmul_v4m43(cgm_vec4 *v, const float *m); /* doesn't affect w */ +static inline void cgm_wmul_m3v4(cgm_vec4 *v, const float *m); /* (m still 16 floats) */ +static inline void cgm_wmul_v4m3(cgm_vec4 *v, const float *m); /* (m still 16 floats) */ + +static inline float cgm_wlength(const cgm_vec4 *v); +static inline float cgm_wlength_sq(const cgm_vec4 *v); +static inline float cgm_wdist(const cgm_vec4 *a, const cgm_vec4 *b); +static inline float cgm_wdist_sq(const cgm_vec4 *a, const cgm_vec4 *b); +static inline void cgm_wnormalize(cgm_vec4 *v); + +static inline void cgm_wlerp(cgm_vec4 *res, const cgm_vec4 *a, const cgm_vec4 *b, float t); + +/* --- operations on quaternions --- */ +static inline void cgm_qcons(cgm_quat *q, float x, float y, float z, float w); + +static inline void cgm_qneg(cgm_quat *q); +static inline void cgm_qadd(cgm_quat *a, const cgm_quat *b); +static inline void cgm_qsub(cgm_quat *a, const cgm_quat *b); +static inline void cgm_qmul(cgm_quat *a, const cgm_quat *b); + +static inline float cgm_qlength(const cgm_quat *q); +static inline float cgm_qlength_sq(const cgm_quat *q); +static inline void cgm_qnormalize(cgm_quat *q); +static inline void cgm_qconjugate(cgm_quat *q); +static inline void cgm_qinvert(cgm_quat *q); + +static inline void cgm_qrotation(cgm_quat *q, const cgm_vec3 *axis, float angle); +static inline void cgm_qrotate(cgm_quat *q, const cgm_vec3 *axis, float angle); + +static inline void cgm_qslerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t); +static inline void cgm_qlerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t); + +/* --- operations on matrices --- */ +static inline void cgm_mcopy(float *dest, const float *src); +static inline void cgm_mzero(float *m); +static inline void cgm_midentity(float *m); + +static inline void cgm_mmul(float *a, const float *b); +static inline void cgm_mpremul(float *a, const float *b); + +static inline void cgm_msubmatrix(float *m, int row, int col); +static inline void cgm_mupper3(float *m); +static inline float cgm_msubdet(const float *m, int row, int col); +static inline float cgm_mcofactor(const float *m, int row, int col); +static inline float cgm_mdet(const float *m); +static inline void cgm_mtranspose(float *m); +static inline void cgm_mcofmatrix(float *m); +static inline int cgm_minverse(float *m); /* returns 0 on success, -1 for singular */ + +static inline void cgm_mtranslation(float *m, float x, float y, float z); +static inline void cgm_mscaling(float *m, float sx, float sy, float sz); +static inline void cgm_mrotation_x(float *m, float angle); +static inline void cgm_mrotation_y(float *m, float angle); +static inline void cgm_mrotation_z(float *m, float angle); +static inline void cgm_mrotation_axis(float *m, int idx, float angle); +static inline void cgm_mrotation(float *m, float angle, float x, float y, float z); +static inline void cgm_mrotation_euler(float *m, float a, float b, float c, int mode); +static inline void cgm_mrotation_quat(float *m, const cgm_quat *q); + +static inline void cgm_mtranslate(float *m, float x, float y, float z); +static inline void cgm_mscale(float *m, float sx, float sy, float sz); +static inline void cgm_mrotate_x(float *m, float angle); +static inline void cgm_mrotate_y(float *m, float angle); +static inline void cgm_mrotate_z(float *m, float angle); +static inline void cgm_mrotate_axis(float *m, int idx, float angle); +static inline void cgm_mrotate(float *m, float angle, float x, float y, float z); +static inline void cgm_mrotate_euler(float *m, float a, float b, float c, int mode); +static inline void cgm_mrotate_quat(float *m, const cgm_quat *q); + +static inline void cgm_mpretranslate(float *m, float x, float y, float z); +static inline void cgm_mprescale(float *m, float sx, float sy, float sz); +static inline void cgm_mprerotate_x(float *m, float angle); +static inline void cgm_mprerotate_y(float *m, float angle); +static inline void cgm_mprerotate_z(float *m, float angle); +static inline void cgm_mprerotate_axis(float *m, int idx, float angle); +static inline void cgm_mprerotate(float *m, float angle, float x, float y, float z); +static inline void cgm_mprerotate_euler(float *m, float a, float b, float c, int mode); +static inline void cgm_mprerotate_quat(float *m, const cgm_quat *q); + +static inline void cgm_mget_translation(const float *m, cgm_vec3 *res); +static inline void cgm_mget_rotation(const float *m, cgm_quat *res); +static inline void cgm_mget_scaling(const float *m, cgm_vec3 *res); +static inline void cgm_mget_frustum_plane(const float *m, int p, cgm_vec4 *res); + +static inline void cgm_mlookat(float *m, const cgm_vec3 *pos, const cgm_vec3 *targ, + const cgm_vec3 *up); +static inline void cgm_minv_lookat(float *m, const cgm_vec3 *pos, const cgm_vec3 *targ, + const cgm_vec3 *up); +static inline void cgm_mortho(float *m, float left, float right, float bot, float top, + float znear, float zfar); +static inline void cgm_mfrustum(float *m, float left, float right, float bot, float top, + float znear, float zfar); +static inline void cgm_mperspective(float *m, float vfov, float aspect, float znear, float zfar); + +static inline void cgm_mmirror(float *m, float a, float b, float c, float d); + +/* --- operations on rays --- */ +static inline void cgm_rcons(cgm_ray *r, float x, float y, float z, float dx, float dy, float dz); + +static inline void cgm_rmul_mr(cgm_ray *ray, const float *m); /* m4x4 * ray */ +static inline void cgm_rmul_rm(cgm_ray *ray, const float *m); /* ray * m4x4 */ + +static inline void cgm_rreflect(cgm_ray *ray, const cgm_vec3 *n); +static inline void cgm_rrefract(cgm_ray *ray, const cgm_vec3 *n, float ior); + +/* --- miscellaneous utility functions --- */ +static inline float cgm_deg_to_rad(float deg); +static inline float cgm_rad_to_deg(float rad); + +static inline float cgm_smoothstep(float a, float b, float x); +static inline float cgm_lerp(float a, float b, float t); +static inline float cgm_bezier(float a, float b, float c, float d, float t); + +static inline void cgm_discrand(cgm_vec3 *v, float rad); +static inline void cgm_sphrand(cgm_vec3 *v, float rad); + +static inline void cgm_unproject(cgm_vec3 *res, const cgm_vec3 *norm_scrpos, + const float *inv_viewproj); +static inline void cgm_glu_unproject(float winx, float winy, float winz, + const float *view, const float *proj, const int *vp, + float *objx, float *objy, float *objz); + +static inline void cgm_pick_ray(cgm_ray *ray, float nx, float ny, + const float *viewmat, const float *projmat); + +static inline void cgm_raypos(cgm_vec3 *p, const cgm_ray *ray, float t); + +/* calculate barycentric coordinates of point pt in triangle (a, b, c) */ +static inline void cgm_bary(cgm_vec3 *bary, const cgm_vec3 *a, + const cgm_vec3 *b, const cgm_vec3 *c, const cgm_vec3 *pt); + +#include "cgmvec3.inl" +#include "cgmvec4.inl" +#include "cgmquat.inl" +#include "cgmmat.inl" +#include "cgmray.inl" +#include "cgmmisc.inl" + +#ifdef __cplusplus +} +#endif + +#endif /* CGMATH_H_ */ diff --git a/libs/cgmath/cgmmat.inl b/libs/cgmath/cgmmat.inl new file mode 100644 index 0000000..c369b84 --- /dev/null +++ b/libs/cgmath/cgmmat.inl @@ -0,0 +1,623 @@ +/* gph-cmath - C graphics math library + * Copyright (C) 2018 John Tsiombikas + * + * This program is free software. Feel free to use, modify, and/or redistribute + * it under the terms of the MIT/X11 license. See LICENSE for details. + * If you intend to redistribute parts of the code without the LICENSE file + * replace this paragraph with the full contents of the LICENSE file. + */ +static inline void cgm_mcopy(float *dest, const float *src) +{ + memcpy(dest, src, 16 * sizeof(float)); +} + +static inline void cgm_mzero(float *m) +{ + static float z[16]; + cgm_mcopy(m, z); +} + +static inline void cgm_midentity(float *m) +{ + static float id[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + cgm_mcopy(m, id); +} + +static inline void cgm_mmul(float *a, const float *b) +{ + int i, j; + float res[16]; + float *resptr = res; + float *arow = a; + + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + *resptr++ = arow[0] * b[j] + arow[1] * b[4 + j] + + arow[2] * b[8 + j] + arow[3] * b[12 + j]; + } + arow += 4; + } + cgm_mcopy(a, res); +} + +static inline void cgm_mpremul(float *a, const float *b) +{ + int i, j; + float res[16]; + float *resptr = res; + const float *brow = b; + + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + *resptr++ = brow[0] * a[j] + brow[1] * a[4 + j] + + brow[2] * a[8 + j] + brow[3] * a[12 + j]; + } + brow += 4; + } + cgm_mcopy(a, res); +} + +static inline void cgm_msubmatrix(float *m, int row, int col) +{ + float orig[16]; + int i, j, subi, subj; + + cgm_mcopy(orig, m); + + subi = 0; + for(i=0; i<4; i++) { + if(i == row) continue; + + subj = 0; + for(j=0; j<4; j++) { + if(j == col) continue; + + m[subi * 4 + subj++] = orig[i * 4 + j]; + } + subi++; + } + + cgm_mupper3(m); +} + +static inline void cgm_mupper3(float *m) +{ + m[3] = m[7] = m[11] = m[12] = m[13] = m[14] = 0.0f; + m[15] = 1.0f; +} + +static inline float cgm_msubdet(const float *m, int row, int col) +{ + float tmp[16]; + float subdet00, subdet01, subdet02; + + cgm_mcopy(tmp, m); + cgm_msubmatrix(tmp, row, col); + + subdet00 = tmp[5] * tmp[10] - tmp[6] * tmp[9]; + subdet01 = tmp[4] * tmp[10] - tmp[6] * tmp[8]; + subdet02 = tmp[4] * tmp[9] - tmp[5] * tmp[8]; + + return tmp[0] * subdet00 - tmp[1] * subdet01 + tmp[2] * subdet02; +} + +static inline float cgm_mcofactor(const float *m, int row, int col) +{ + float min = cgm_msubdet(m, row, col); + return (row + col) & 1 ? -min : min; +} + +static inline float cgm_mdet(const float *m) +{ + return m[0] * cgm_msubdet(m, 0, 0) - m[1] * cgm_msubdet(m, 0, 1) + + m[2] * cgm_msubdet(m, 0, 2) - m[3] * cgm_msubdet(m, 0, 3); +} + +static inline void cgm_mtranspose(float *m) +{ + int i, j; + for(i=0; i<4; i++) { + for(j=0; jx * q->x; + float ysq2 = 2.0f * q->y * q->y; + float zsq2 = 2.0f * q->z * q->z; + float sx = 1.0f - ysq2 - zsq2; + float sy = 1.0f - xsq2 - zsq2; + float sz = 1.0f - xsq2 - ysq2; + + m[3] = m[7] = m[11] = m[12] = m[13] = m[14] = 0.0f; + m[15] = 1.0f; + + m[0] = sx; + m[1] = 2.0f * q->x * q->y + 2.0f * q->w * q->z; + m[2] = 2.0f * q->z * q->x - 2.0f * q->w * q->y; + m[4] = 2.0f * q->x * q->y - 2.0f * q->w * q->z; + m[5] = sy; + m[6] = 2.0f * q->y * q->z + 2.0f * q->w * q->x; + m[8] = 2.0f * q->z * q->x + 2.0f * q->w * q->y; + m[9] = 2.0f * q->y * q->z - 2.0f * q->w * q->x; + m[10] = sz; +} + +static inline void cgm_mtranslate(float *m, float x, float y, float z) +{ + float tm[16]; + cgm_mtranslation(tm, x, y, z); + cgm_mmul(m, tm); +} + +static inline void cgm_mscale(float *m, float sx, float sy, float sz) +{ + float sm[16]; + cgm_mscaling(sm, sx, sy, sz); + cgm_mmul(m, sm); +} + +static inline void cgm_mrotate_x(float *m, float angle) +{ + float rm[16]; + cgm_mrotation_x(rm, angle); + cgm_mmul(m, rm); +} + +static inline void cgm_mrotate_y(float *m, float angle) +{ + float rm[16]; + cgm_mrotation_y(rm, angle); + cgm_mmul(m, rm); +} + +static inline void cgm_mrotate_z(float *m, float angle) +{ + float rm[16]; + cgm_mrotation_z(rm, angle); + cgm_mmul(m, rm); +} + +static inline void cgm_mrotate_axis(float *m, int idx, float angle) +{ + float rm[16]; + cgm_mrotation_axis(rm, idx, angle); + cgm_mmul(m, rm); +} + +static inline void cgm_mrotate(float *m, float angle, float x, float y, float z) +{ + float rm[16]; + cgm_mrotation(rm, angle, x, y, z); + cgm_mmul(m, rm); +} + +static inline void cgm_mrotate_euler(float *m, float a, float b, float c, int mode) +{ + float rm[16]; + cgm_mrotation_euler(rm, a, b, c, mode); + cgm_mmul(m, rm); +} + +static inline void cgm_mrotate_quat(float *m, const cgm_quat *q) +{ + float rm[16]; + cgm_mrotation_quat(rm, q); + cgm_mmul(m, rm); +} + + +static inline void cgm_mpretranslate(float *m, float x, float y, float z) +{ + float tm[16]; + cgm_mtranslation(tm, x, y, z); + cgm_mpremul(m, tm); +} + +static inline void cgm_mprescale(float *m, float sx, float sy, float sz) +{ + float sm[16]; + cgm_mscaling(sm, sx, sy, sz); + cgm_mpremul(m, sm); +} + +static inline void cgm_mprerotate_x(float *m, float angle) +{ + float rm[16]; + cgm_mrotation_x(rm, angle); + cgm_mpremul(m, rm); +} + +static inline void cgm_mprerotate_y(float *m, float angle) +{ + float rm[16]; + cgm_mrotation_y(rm, angle); + cgm_mpremul(m, rm); +} + +static inline void cgm_mprerotate_z(float *m, float angle) +{ + float rm[16]; + cgm_mrotation_z(rm, angle); + cgm_mpremul(m, rm); +} + +static inline void cgm_mprerotate_axis(float *m, int idx, float angle) +{ + float rm[16]; + cgm_mrotation_axis(rm, idx, angle); + cgm_mpremul(m, rm); +} + +static inline void cgm_mprerotate(float *m, float angle, float x, float y, float z) +{ + float rm[16]; + cgm_mrotation(rm, angle, x, y, z); + cgm_mpremul(m, rm); +} + +static inline void cgm_mprerotate_euler(float *m, float a, float b, float c, int mode) +{ + float rm[16]; + cgm_mrotation_euler(rm, a, b, c, mode); + cgm_mpremul(m, rm); +} + +static inline void cgm_mprerotate_quat(float *m, const cgm_quat *q) +{ + float rm[16]; + cgm_mrotation_quat(rm, q); + cgm_mpremul(m, rm); +} + + +static inline void cgm_mget_translation(const float *m, cgm_vec3 *res) +{ + res->x = m[12]; + res->y = m[13]; + res->z = m[14]; +} + +/* Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + * article "Quaternion Calculus and Fast Animation". + * adapted from: http://www.geometrictools.com/LibMathematics/Algebra/Wm5Quaternion.inl + */ +static inline void cgm_mget_rotation(const float *m, cgm_quat *res) +{ + static const int next[3] = {1, 2, 0}; + float quat[4]; + int i, j, k; + + float trace = m[0] + m[5] + m[10]; + float root; + + if(trace > 0.0f) { + // |w| > 1/2 + root = sqrt(trace + 1.0f); // 2w + res->w = 0.5f * root; + root = 0.5f / root; // 1 / 4w + res->x = (m[6] - m[9]) * root; + res->y = (m[8] - m[2]) * root; + res->z = (m[1] - m[4]) * root; + } else { + // |w| <= 1/2 + i = 0; + if(m[5] > m[0]) { + i = 1; + } + if(m[10] > m[i * 4 + i]) { + i = 2; + } + j = next[i]; + k = next[j]; + + root = sqrt(m[i * 4 + i] - m[j * 4 + j] - m[k * 4 + k] + 1.0f); + quat[i + 1] = 0.5f * root; + root = 0.5f / root; + quat[0] = (m[j + 4 + k] - m[k * 4 + j]) * root; + quat[j + 1] = (m[i * 4 + j] - m[j * 4 + i]) * root; + quat[k + 1] = (m[i * 4 + k] - m[k * 4 + i]) * root; + res->w = quat[0]; + res->x = quat[1]; + res->y = quat[2]; + res->z = quat[3]; + } +} + +static inline void cgm_mget_scaling(const float *m, cgm_vec3 *res) +{ + res->x = sqrt(m[0] * m[0] + m[4] * m[4] + m[8] * m[8]); + res->y = sqrt(m[1] * m[1] + m[5] * m[5] + m[9] * m[9]); + res->z = sqrt(m[2] * m[2] + m[6] * m[6] + m[10] * m[10]); +} + +static inline void cgm_mget_frustum_plane(const float *m, int p, cgm_vec4 *res) +{ + int row = p >> 1; + const float *rowptr = m + row * 4; + + if((p & 1) == 0) { + res->x = m[12] + rowptr[0]; + res->y = m[13] + rowptr[1]; + res->z = m[14] + rowptr[2]; + res->w = m[15] + rowptr[3]; + } else { + res->x = m[12] - rowptr[0]; + res->y = m[13] - rowptr[1]; + res->z = m[14] - rowptr[2]; + res->w = m[15] - rowptr[3]; + } +} + +static inline void cgm_mlookat(float *m, const cgm_vec3 *pos, const cgm_vec3 *targ, + const cgm_vec3 *up) +{ + float trans[16]; + cgm_vec3 dir = *targ, right, vup; + + cgm_vsub(&dir, pos); + cgm_vnormalize(&dir); + cgm_vcross(&right, &dir, up); + cgm_vnormalize(&right); + cgm_vcross(&vup, &right, &dir); + cgm_vnormalize(&vup); + + cgm_midentity(m); + m[0] = right.x; + m[1] = right.y; + m[2] = right.z; + m[4] = vup.x; + m[5] = vup.y; + m[6] = vup.z; + m[8] = -dir.x; + m[9] = -dir.y; + m[10] = -dir.z; + + cgm_mtranslation(trans, pos->x, pos->y, pos->z); + cgm_mmul(m, trans); +} + +static inline void cgm_minv_lookat(float *m, const cgm_vec3 *pos, const cgm_vec3 *targ, + const cgm_vec3 *up) +{ + float rot[16]; + cgm_vec3 dir = *targ, right, vup; + + cgm_vsub(&dir, pos); + cgm_vnormalize(&dir); + cgm_vcross(&right, &dir, up); + cgm_vnormalize(&right); + cgm_vcross(&vup, &right, &dir); + cgm_vnormalize(&vup); + + cgm_midentity(rot); + rot[0] = right.x; + rot[4] = right.y; + rot[8] = right.z; + rot[1] = vup.x; + rot[5] = vup.y; + rot[9] = vup.z; + rot[2] = -dir.x; + rot[6] = -dir.y; + rot[10] = -dir.z; + + cgm_mtranslation(m, -pos->x, -pos->y, -pos->z); + cgm_mmul(m, rot); +} + +static inline void cgm_mortho(float *m, float left, float right, float bot, float top, + float znear, float zfar) +{ + float dx = right - left; + float dy = top - bot; + float dz = zfar - znear; + + cgm_midentity(m); + m[0] = 2.0f / dx; + m[5] = 2.0f / dy; + m[10] = -2.0f / dz; + m[12] = -(right + left) / dx; + m[13] = -(top + bot) / dy; + m[14] = -(zfar + znear) / dz; +} + +static inline void cgm_mfrustum(float *m, float left, float right, float bot, float top, + float znear, float zfar) +{ + float dx = right - left; + float dy = top - bot; + float dz = zfar - znear; + + cgm_mzero(m); + m[0] = 2.0f * znear / dx; + m[5] = 2.0f * znear / dy; + m[8] = (right + left) / dx; + m[9] = (top + bot) / dy; + m[10] = -(zfar + znear) / dz; + m[14] = -2.0f * zfar * znear / dz; + m[11] = -1.0f; +} + +static inline void cgm_mperspective(float *m, float vfov, float aspect, float znear, float zfar) +{ + float s = 1.0f / (float)tan(vfov / 2.0f); + float range = znear - zfar; + + cgm_mzero(m); + m[0] = s / aspect; + m[5] = s; + m[10] = (znear + zfar) / range; + m[14] = 2.0f * znear * zfar / range; + m[11] = -1.0f; +} + +static inline void cgm_mmirror(float *m, float a, float b, float c, float d) +{ + m[0] = 1.0f - 2.0f * a * a; + m[5] = 1.0f - 2.0f * b * b; + m[10] = 1.0f - 2.0f * c * c; + m[15] = 1.0f; + + m[1] = m[4] = -2.0f * a * b; + m[2] = m[8] = -2.0f * a * c; + m[6] = m[9] = -2.0f * b * c; + + m[12] = -2.0f * a * d; + m[13] = -2.0f * b * d; + m[14] = -2.0f * c * d; + + m[3] = m[7] = m[11] = 0.0f; +} diff --git a/libs/cgmath/cgmmisc.inl b/libs/cgmath/cgmmisc.inl new file mode 100644 index 0000000..6cfa37d --- /dev/null +++ b/libs/cgmath/cgmmisc.inl @@ -0,0 +1,154 @@ +/* gph-cmath - C graphics math library + * Copyright (C) 2018 John Tsiombikas + * + * This program is free software. Feel free to use, modify, and/or redistribute + * it under the terms of the MIT/X11 license. See LICENSE for details. + * If you intend to redistribute parts of the code without the LICENSE file + * replace this paragraph with the full contents of the LICENSE file. + */ +#include + +static inline float cgm_deg_to_rad(float deg) +{ + return M_PI * deg / 180.0f; +} + +static inline float cgm_rad_to_deg(float rad) +{ + return 180.0f * rad / M_PI; +} + +static inline float cgm_smoothstep(float a, float b, float x) +{ + if(x < a) return 0.0f; + if(x >= b) return 1.0f; + + x = (x - a) / (b - a); + return x * x * (3.0f - 2.0f * x); +} + +static inline float cgm_lerp(float a, float b, float t) +{ + return a + (b - a) * t; +} + +static inline float cgm_bezier(float a, float b, float c, float d, float t) +{ + float omt, omt3, t3, f; + t3 = t * t * t; + omt = 1.0f - t; + omt3 = omt * omt * omt; + f = 3.0f * t * omt; + + return (a * omt3) + (b * f * omt) + (c * f * t) + (d * t3); +} + +static inline void cgm_discrand(cgm_vec3 *pt, float rad) +{ + float theta = 2.0f * M_PI * (float)rand() / RAND_MAX; + float r = sqrt((float)rand() / RAND_MAX) * rad; + pt->x = cos(theta) * r; + pt->y = sin(theta) * r; + pt->z = 0.0f; +} + +static inline void cgm_sphrand(cgm_vec3 *pt, float rad) +{ + float u, v, theta, phi; + + u = (float)rand() / RAND_MAX; + v = (float)rand() / RAND_MAX; + + theta = 2.0f * M_PI * u; + phi = acos(2.0f * v - 1.0f); + + pt->x = cos(theta) * sin(phi) * rad; + pt->y = sin(theta) * sin(phi) * rad; + pt->z = cos(phi) * rad; +} + +static inline void cgm_unproject(cgm_vec3 *res, const cgm_vec3 *norm_scrpos, + const float *inv_viewproj) +{ + cgm_vec4 pos; + + pos.x = 2.0f * norm_scrpos->x - 1.0f; + pos.y = 2.0f * norm_scrpos->y - 1.0f; + pos.z = 2.0f * norm_scrpos->z - 1.0f; + pos.w = 1.0f; + + cgm_wmul_m4v4(&pos, inv_viewproj); + + res->x = pos.x / pos.w; + res->y = pos.y / pos.w; + res->z = pos.z / pos.w; +} + +static inline void cgm_glu_unproject(float winx, float winy, float winz, + const float *view, const float *proj, const int *vp, + float *objx, float *objy, float *objz) +{ + cgm_vec3 npos, res; + float inv_pv[16]; + + cgm_mcopy(inv_pv, proj); + cgm_mmul(inv_pv, view); + + npos.x = (winx - vp[0]) / vp[2]; + npos.y = (winy - vp[1]) / vp[4]; + npos.z = winz; + + cgm_unproject(&res, &npos, inv_pv); + + *objx = res.x; + *objy = res.y; + *objz = res.z; +} + +static inline void cgm_pick_ray(cgm_ray *ray, float nx, float ny, + const float *viewmat, const float *projmat) +{ + cgm_vec3 npos, farpt; + float inv_pv[16]; + + cgm_mcopy(inv_pv, projmat); + cgm_mmul(inv_pv, viewmat); + + cgm_vcons(&npos, nx, ny, 0.0f); + cgm_unproject(&ray->origin, &npos, inv_pv); + npos.z = 1.0f; + cgm_unproject(&farpt, &npos, inv_pv); + + ray->dir.x = farpt.x - ray->origin.x; + ray->dir.y = farpt.y - ray->origin.y; + ray->dir.z = farpt.z - ray->origin.z; +} + +static inline void cgm_raypos(cgm_vec3 *p, const cgm_ray *ray, float t) +{ + p->x = ray->origin.x + ray->dir.x * t; + p->y = ray->origin.y + ray->dir.y * t; + p->z = ray->origin.z + ray->dir.z * t; +} + +static inline void cgm_bary(cgm_vec3 *bary, const cgm_vec3 *a, + const cgm_vec3 *b, const cgm_vec3 *c, const cgm_vec3 *pt) +{ + float d00, d01, d11, d20, d21, denom; + cgm_vec3 v0 = *b, v1 = *c, v2 = *pt; + + cgm_vsub(&v0, a); + cgm_vsub(&v1, a); + cgm_vsub(&v2, a); + + d00 = cgm_vdot(&v0, &v0); + d01 = cgm_vdot(&v0, &v1); + d11 = cgm_vdot(&v1, &v1); + d20 = cgm_vdot(&v2, &v0); + d21 = cgm_vdot(&v2, &v1); + denom = d00 * d11 - d01 * d01; + + bary->y = (d11 * d20 - d01 * d21) / denom; + bary->z = (d00 * d21 - d01 * d20) / denom; + bary->x = 1.0f - bary->y - bary->z; +} diff --git a/libs/cgmath/cgmquat.inl b/libs/cgmath/cgmquat.inl new file mode 100644 index 0000000..4b29fd2 --- /dev/null +++ b/libs/cgmath/cgmquat.inl @@ -0,0 +1,159 @@ +/* gph-cmath - C graphics math library + * Copyright (C) 2018 John Tsiombikas + * + * This program is free software. Feel free to use, modify, and/or redistribute + * it under the terms of the MIT/X11 license. See LICENSE for details. + * If you intend to redistribute parts of the code without the LICENSE file + * replace this paragraph with the full contents of the LICENSE file. + */ +static inline void cgm_qcons(cgm_quat *q, float x, float y, float z, float w) +{ + q->x = x; + q->y = y; + q->z = z; + q->w = w; +} + + +static inline void cgm_qneg(cgm_quat *q) +{ + q->x = -q->x; + q->y = -q->y; + q->z = -q->z; + q->w = -q->w; +} + +static inline void cgm_qadd(cgm_quat *a, const cgm_quat *b) +{ + a->x += b->x; + a->y += b->y; + a->z += b->z; + a->w += b->w; +} + +static inline void cgm_qsub(cgm_quat *a, const cgm_quat *b) +{ + a->x -= b->x; + a->y -= b->y; + a->z -= b->z; + a->w -= b->w; +} + +static inline void cgm_qmul(cgm_quat *a, const cgm_quat *b) +{ + float x, y, z, dot; + cgm_vec3 cross; + + dot = a->x * b->x + a->y * b->y + a->z * b->z; + cgm_vcross(&cross, (cgm_vec3*)a, (cgm_vec3*)b); + + x = a->w * b->x + b->w * a->x + cross.x; + y = a->w * b->y + b->w * a->y + cross.y; + z = a->w * b->z + b->w * a->z + cross.z; + a->w = a->w * b->w - dot; + a->x = x; + a->y = y; + a->z = z; +} + +static inline float cgm_qlength(const cgm_quat *q) +{ + return sqrt(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w); +} + +static inline float cgm_qlength_sq(const cgm_quat *q) +{ + return q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w; +} + +static inline void cgm_qnormalize(cgm_quat *q) +{ + float len = cgm_qlength(q); + if(len != 0.0f) { + float s = 1.0f / len; + q->x *= s; + q->y *= s; + q->z *= s; + q->w *= s; + } +} + +static inline void cgm_qconjugate(cgm_quat *q) +{ + q->x = -q->x; + q->y = -q->y; + q->z = -q->z; +} + +static inline void cgm_qinvert(cgm_quat *q) +{ + float len_sq = cgm_qlength_sq(q); + cgm_qconjugate(q); + if(len_sq != 0.0f) { + float s = 1.0f / len_sq; + q->x *= s; + q->y *= s; + q->z *= s; + q->w *= s; + } +} + +static inline void cgm_qrotation(cgm_quat *q, const cgm_vec3 *axis, float angle) +{ + float hangle = angle * 0.5f; + float sin_ha = sin(hangle); + q->w = cos(hangle); + q->x = axis->x * sin_ha; + q->y = axis->y * sin_ha; + q->z = axis->z * sin_ha; +} + +static inline void cgm_qrotate(cgm_quat *q, const cgm_vec3 *axis, float angle) +{ + cgm_quat qrot; + cgm_qrotation(&qrot, axis, angle); + cgm_qmul(q, &qrot); +} + +static inline void cgm_qslerp(cgm_quat *res, const cgm_quat *quat1, const cgm_quat *q2, float t) +{ + float angle, dot, a, b, sin_angle; + cgm_quat q1 = *quat1; + + dot = quat1->x * q2->x + quat1->y * q2->y + quat1->z * q2->z + quat1->w * q2->w; + if(dot < 0.0f) { + /* make sure we inteprolate across the shortest arc */ + cgm_qneg(&q1); + dot = -dot; + } + + /* clamp dot to [-1, 1] in order to avoid domain errors in acos due to + * floating point imprecisions + */ + if(dot < -1.0f) dot = -1.0f; + if(dot > 1.0f) dot = 1.0f; + angle = acos(dot); + + sin_angle = sin(angle); + if(sin_angle == 0.0f) { + /* use linear interpolation to avoid div/zero */ + a = 1.0f; + b = t; + } else { + a = sin((1.0f - t) * angle) / sin_angle; + b = sin(t * angle) / sin_angle; + } + + res->x = q1.x * a + q2->x * b; + res->y = q1.y * a + q2->y * b; + res->z = q1.z * a + q2->z * b; + res->w = q1.w * a + q2->w * b; +} + +static inline void cgm_qlerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t) +{ + res->x = a->x + (b->x - a->x) * t; + res->y = a->y + (b->y - a->y) * t; + res->z = a->z + (b->z - a->z) * t; + res->w = a->w + (b->w - a->w) * t; +} diff --git a/libs/cgmath/cgmray.inl b/libs/cgmath/cgmray.inl new file mode 100644 index 0000000..063a7e0 --- /dev/null +++ b/libs/cgmath/cgmray.inl @@ -0,0 +1,39 @@ +/* gph-cmath - C graphics math library + * Copyright (C) 2018 John Tsiombikas + * + * This program is free software. Feel free to use, modify, and/or redistribute + * it under the terms of the MIT/X11 license. See LICENSE for details. + * If you intend to redistribute parts of the code without the LICENSE file + * replace this paragraph with the full contents of the LICENSE file. + */ +static inline void cgm_rcons(cgm_ray *r, float x, float y, float z, float dx, float dy, float dz) +{ + r->origin.x = x; + r->origin.y = y; + r->origin.z = z; + r->dir.x = dx; + r->dir.y = dy; + r->dir.z = dz; +} + +static inline void cgm_rmul_mr(cgm_ray *ray, const float *m) +{ + cgm_vmul_m4v3(&ray->origin, m); + cgm_vmul_m3v3(&ray->dir, m); +} + +static inline void cgm_rmul_rm(cgm_ray *ray, const float *m) +{ + cgm_vmul_v3m4(&ray->origin, m); + cgm_vmul_v3m3(&ray->dir, m); +} + +static inline void cgm_rreflect(cgm_ray *ray, const cgm_vec3 *n) +{ + cgm_vreflect(&ray->dir, n); +} + +static inline void cgm_rrefract(cgm_ray *ray, const cgm_vec3 *n, float ior) +{ + cgm_vrefract(&ray->dir, n, ior); +} diff --git a/libs/cgmath/cgmvec3.inl b/libs/cgmath/cgmvec3.inl new file mode 100644 index 0000000..88211c4 --- /dev/null +++ b/libs/cgmath/cgmvec3.inl @@ -0,0 +1,188 @@ +/* gph-cmath - C graphics math library + * Copyright (C) 2018 John Tsiombikas + * + * This program is free software. Feel free to use, modify, and/or redistribute + * it under the terms of the MIT/X11 license. See LICENSE for details. + * If you intend to redistribute parts of the code without the LICENSE file + * replace this paragraph with the full contents of the LICENSE file. + */ +static inline void cgm_vcons(cgm_vec3 *v, float x, float y, float z) +{ + v->x = x; + v->y = y; + v->z = z; +} + +static inline void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b) +{ + a->x += b->x; + a->y += b->y; + a->z += b->z; +} + +static inline void cgm_vsub(cgm_vec3 *a, const cgm_vec3 *b) +{ + a->x -= b->x; + a->y -= b->y; + a->z -= b->z; +} + +static inline void cgm_vmul(cgm_vec3 *a, const cgm_vec3 *b) +{ + a->x *= b->x; + a->y *= b->y; + a->z *= b->z; +} + +static inline void cgm_vscale(cgm_vec3 *v, float s) +{ + v->x *= s; + v->y *= s; + v->z *= s; +} + +static inline void cgm_vmul_m4v3(cgm_vec3 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + m[12]; + float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + m[13]; + v->z = v->x * m[2] + v->y * m[6] + v->z * m[10] + m[14]; + v->x = x; + v->y = y; +} + +static inline void cgm_vmul_v3m4(cgm_vec3 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + m[3]; + float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + m[7]; + v->z = v->x * m[8] + v->y * m[9] + v->z * m[10] + m[11]; + v->x = x; + v->y = y; +} + +static inline void cgm_vmul_m3v3(cgm_vec3 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[4] + v->z * m[8]; + float y = v->x * m[1] + v->y * m[5] + v->z * m[9]; + v->z = v->x * m[2] + v->y * m[6] + v->z * m[10]; + v->x = x; + v->y = y; +} + +static inline void cgm_vmul_v3m3(cgm_vec3 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[1] + v->z * m[2]; + float y = v->x * m[4] + v->y * m[5] + v->z * m[6]; + v->z = v->x * m[8] + v->y * m[9] + v->z * m[10]; + v->x = x; + v->y = y; +} + +static inline float cgm_vdot(const cgm_vec3 *a, const cgm_vec3 *b) +{ + return a->x * b->x + a->y * b->y + a->z * b->z; +} + +static inline void cgm_vcross(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b) +{ + res->x = a->y * b->z - a->z * b->y; + res->y = a->z * b->x - a->x * b->z; + res->z = a->x * b->y - a->y * b->x; +} + +static inline float cgm_vlength(const cgm_vec3 *v) +{ + return sqrt(v->x * v->x + v->y * v->y + v->z * v->z); +} + +static inline float cgm_vlength_sq(const cgm_vec3 *v) +{ + return v->x * v->x + v->y * v->y + v->z * v->z; +} + +static inline float cgm_vdist(const cgm_vec3 *a, const cgm_vec3 *b) +{ + float dx = a->x - b->x; + float dy = a->y - b->y; + float dz = a->z - b->z; + return sqrt(dx * dx + dy * dy + dz * dz); +} + +static inline float cgm_vdist_sq(const cgm_vec3 *a, const cgm_vec3 *b) +{ + float dx = a->x - b->x; + float dy = a->y - b->y; + float dz = a->z - b->z; + return dx * dx + dy * dy + dz * dz; +} + +static inline void cgm_vnormalize(cgm_vec3 *v) +{ + float len = cgm_vlength(v); + if(len != 0.0f) { + float s = 1.0f / len; + v->x *= s; + v->y *= s; + v->z *= s; + } +} + +static inline void cgm_vreflect(cgm_vec3 *v, const cgm_vec3 *n) +{ + float ndotv2 = cgm_vdot(v, n) * 2.0f; + v->x -= n->x * ndotv2; + v->y -= n->y * ndotv2; + v->z -= n->z * ndotv2; +} + +static inline void cgm_vrefract(cgm_vec3 *v, const cgm_vec3 *n, float ior) +{ + float ndotv = cgm_vdot(v, n); + float k = 1.0f - ior * ior * (1.0f - ndotv * ndotv); + if(k < 0.0f) { + cgm_vreflect(v, n); /* TIR */ + } else { + float sqrt_k = sqrt(k); + v->x = ior * v->x - (ior * ndotv + sqrt_k) * n->x; + v->y = ior * v->y - (ior * ndotv + sqrt_k) * n->y; + v->z = ior * v->z - (ior * ndotv + sqrt_k) * n->z; + } +} + +static inline void cgm_vrotate_quat(cgm_vec3 *v, const cgm_quat *q) +{ + cgm_quat vq, inv_q = *q, tmp_q = *q; + + cgm_qcons(&vq, v->x, v->y, v->z, 0.0f); + cgm_qinvert(&inv_q); + cgm_qmul(&tmp_q, &vq); + cgm_qmul(&vq, &inv_q); + cgm_vcons(v, vq.x, vq.y, vq.z); +} + +static inline void cgm_vrotate_axis(cgm_vec3 *v, int axis, float angle) +{ + float m[16]; + cgm_mrotation_axis(m, axis, angle); + cgm_vmul_m3v3(v, m); +} + +static inline void cgm_vrotate(cgm_vec3 *v, float angle, float x, float y, float z) +{ + float m[16]; + cgm_mrotation(m, angle, x, y, z); + cgm_vmul_m3v3(v, m); +} + +static inline void cgm_vrotate_euler(cgm_vec3 *v, float a, float b, float c, enum cgm_euler_mode mode) +{ + float m[16]; + cgm_mrotation_euler(m, a, b, c, mode); + cgm_vmul_m3v3(v, m); +} + +static inline void cgm_vlerp(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b, float t) +{ + res->x = a->x + (b->x - a->x) * t; + res->y = a->y + (b->y - a->y) * t; + res->z = a->z + (b->z - a->z) * t; +} diff --git a/libs/cgmath/cgmvec4.inl b/libs/cgmath/cgmvec4.inl new file mode 100644 index 0000000..1c143c2 --- /dev/null +++ b/libs/cgmath/cgmvec4.inl @@ -0,0 +1,153 @@ +/* gph-cmath - C graphics math library + * Copyright (C) 2018 John Tsiombikas + * + * This program is free software. Feel free to use, modify, and/or redistribute + * it under the terms of the MIT/X11 license. See LICENSE for details. + * If you intend to redistribute parts of the code without the LICENSE file + * replace this paragraph with the full contents of the LICENSE file. + */ +static inline void cgm_wcons(cgm_vec4 *v, float x, float y, float z, float w) +{ + v->x = x; + v->y = y; + v->z = z; + v->w = w; +} + +static inline void cgm_wadd(cgm_vec4 *a, const cgm_vec4 *b) +{ + a->x += b->x; + a->y += b->y; + a->z += b->z; + a->w += b->w; +} + +static inline void cgm_wsub(cgm_vec4 *a, const cgm_vec4 *b) +{ + a->x -= b->x; + a->y -= b->y; + a->z -= b->z; + a->w -= b->w; +} + +static inline void cgm_wmul(cgm_vec4 *a, const cgm_vec4 *b) +{ + a->x *= b->x; + a->y *= b->y; + a->z *= b->z; + a->w *= b->w; +} + +static inline void cgm_wscale(cgm_vec4 *v, float s) +{ + v->x *= s; + v->y *= s; + v->z *= s; + v->w *= s; +} + +static inline void cgm_wmul_m4v4(cgm_vec4 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + v->w * m[12]; + float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + v->w * m[13]; + float z = v->x * m[2] + v->y * m[6] + v->z * m[10] + v->w * m[14]; + v->w = v->x * m[3] + v->y * m[7] + v->z * m[11] + v->w * m[15]; + v->x = x; + v->y = y; + v->z = z; +} + +static inline void cgm_wmul_v4m4(cgm_vec4 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + v->w * m[3]; + float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + v->w * m[7]; + float z = v->x * m[8] + v->y * m[9] + v->z * m[10] + v->w * m[11]; + v->w = v->x * m[12] + v->y * m[13] + v->z * m[14] + v->w * m[15]; + v->x = x; + v->y = y; + v->z = z; +} + +static inline void cgm_wmul_m34v4(cgm_vec4 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + v->w * m[12]; + float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + v->w * m[13]; + v->z = v->x * m[2] + v->y * m[6] + v->z * m[10] + v->w * m[14]; + v->x = x; + v->y = y; +} + +static inline void cgm_wmul_v4m43(cgm_vec4 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + v->w * m[3]; + float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + v->w * m[7]; + v->z = v->x * m[8] + v->y * m[9] + v->z * m[10] + v->w * m[11]; + v->x = x; + v->y = y; +} + +static inline void cgm_wmul_m3v4(cgm_vec4 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[4] + v->z * m[8]; + float y = v->x * m[1] + v->y * m[5] + v->z * m[9]; + v->z = v->x * m[2] + v->y * m[6] + v->z * m[10]; + v->x = x; + v->y = y; +} + +static inline void cgm_wmul_v4m3(cgm_vec4 *v, const float *m) +{ + float x = v->x * m[0] + v->y * m[1] + v->z * m[2]; + float y = v->x * m[4] + v->y * m[5] + v->z * m[6]; + v->z = v->x * m[8] + v->y * m[9] + v->z * m[10]; + v->x = x; + v->y = y; +} + +static inline float cgm_wlength(const cgm_vec4 *v) +{ + return sqrt(v->x * v->x + v->y * v->y + v->z * v->z + v->w * v->w); +} + +static inline float cgm_wlength_sq(const cgm_vec4 *v) +{ + return v->x * v->x + v->y * v->y + v->z * v->z + v->w * v->w; +} + +static inline float cgm_wdist(const cgm_vec4 *a, const cgm_vec4 *b) +{ + float dx = a->x - b->x; + float dy = a->y - b->y; + float dz = a->z - b->z; + float dw = a->w - b->w; + return sqrt(dx * dx + dy * dy + dz * dz + dw * dw); +} + +static inline float cgm_wdist_sq(const cgm_vec4 *a, const cgm_vec4 *b) +{ + float dx = a->x - b->x; + float dy = a->y - b->y; + float dz = a->z - b->z; + float dw = a->w - b->w; + return dx * dx + dy * dy + dz * dz + dw * dw; +} + +static inline void cgm_wnormalize(cgm_vec4 *v) +{ + float len = cgm_wlength(v); + if(len != 0.0f) { + float s = 1.0f / len; + v->x *= s; + v->y *= s; + v->z *= s; + v->w *= s; + } +} + +static inline void cgm_wlerp(cgm_vec4 *res, const cgm_vec4 *a, const cgm_vec4 *b, float t) +{ + res->x = a->x + (b->x - a->x) * t; + res->y = a->y + (b->y - a->y) * t; + res->z = a->z + (b->z - a->z) * t; + res->w = a->w + (b->w - a->w) * t; +} diff --git a/src/cgmath/cgmath.h b/src/cgmath/cgmath.h deleted file mode 100644 index f8f776b..0000000 --- a/src/cgmath/cgmath.h +++ /dev/null @@ -1,238 +0,0 @@ -/* gph-cmath - C graphics math library - * Copyright (C) 2018 John Tsiombikas - * - * This program is free software. Feel free to use, modify, and/or redistribute - * it under the terms of the MIT/X11 license. See LICENSE for details. - * If you intend to redistribute parts of the code without the LICENSE file - * replace this paragraph with the full contents of the LICENSE file. - * - * Function prefixes signify the data type of their operand(s): - * - cgm_v... functions are operations on cgm_vec3 vectors - * - cgm_w... functions are operations on cgm_vec4 vectors - * - cgm_q... functions are operations on cgm_quat quaternions (w + xi + yj + zk) - * - cgm_m... functions are operations on 4x4 matrices (stored as linear 16 float arrays) - * - cgm_r... functions are operations on cgm_ray rays - * - * NOTE: *ALL* matrix arguments are pointers to 16 floats. Even the functions - * which operate on 3x3 matrices, actually use the upper 3x3 of a 4x4 matrix, - * and still expect an array of 16 floats. - * - * NOTE: matrices are treated by all operations as column-major, to match OpenGL - * conventions, so everything is pretty much transposed. -*/ -#ifndef CGMATH_H_ -#define CGMATH_H_ - -#include -#include - -typedef struct { - float x, y, z; -} cgm_vec3; - -typedef struct { - float x, y, z, w; -} cgm_vec4, cgm_quat; - -typedef struct { - cgm_vec3 origin, dir; -} cgm_ray; - -typedef enum cgm_euler_mode { - CGM_EULER_XYZ, - CGM_EULER_XZY, - CGM_EULER_YXZ, - CGM_EULER_YZX, - CGM_EULER_ZXY, - CGM_EULER_ZYX, - CGM_EULER_ZXZ, - CGM_EULER_ZYZ, - CGM_EULER_YXY, - CGM_EULER_YZY, - CGM_EULER_XYX, - CGM_EULER_XZX -} cgm_euler_mode; - -#ifdef __cplusplus -extern "C" { -#endif - -/* --- operations on cgm_vec3 --- */ -static inline void cgm_vcons(cgm_vec3 *v, float x, float y, float z); - -static inline void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b); -static inline void cgm_vsub(cgm_vec3 *a, const cgm_vec3 *b); -static inline void cgm_vmul(cgm_vec3 *a, const cgm_vec3 *b); -static inline void cgm_vscale(cgm_vec3 *v, float s); -static inline void cgm_vmul_m4v3(cgm_vec3 *v, const float *m); /* m4x4 * v */ -static inline void cgm_vmul_v3m4(cgm_vec3 *v, const float *m); /* v * m4x4 */ -static inline void cgm_vmul_m3v3(cgm_vec3 *v, const float *m); /* m3x3 * v (m still 16 floats) */ -static inline void cgm_vmul_v3m3(cgm_vec3 *v, const float *m); /* v * m3x3 (m still 16 floats) */ - -static inline float cgm_vdot(const cgm_vec3 *a, const cgm_vec3 *b); -static inline void cgm_vcross(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b); -static inline float cgm_vlength(const cgm_vec3 *v); -static inline float cgm_vlength_sq(const cgm_vec3 *v); -static inline float cgm_vdist(const cgm_vec3 *a, const cgm_vec3 *b); -static inline float cgm_vdist_sq(const cgm_vec3 *a, const cgm_vec3 *b); -static inline void cgm_vnormalize(cgm_vec3 *v); - -static inline void cgm_vreflect(cgm_vec3 *v, const cgm_vec3 *n); -static inline void cgm_vrefract(cgm_vec3 *v, const cgm_vec3 *n, float ior); - -static inline void cgm_vrotate_quat(cgm_vec3 *v, const cgm_quat *q); -static inline void cgm_vrotate_axis(cgm_vec3 *v, int axis, float angle); -static inline void cgm_vrotate(cgm_vec3 *v, float angle, float x, float y, float z); -static inline void cgm_vrotate_euler(cgm_vec3 *v, float a, float b, float c, enum cgm_euler_mode mode); - -static inline void cgm_vlerp(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b, float t); - -/* --- operations on cgm_vec4 --- */ -static inline void cgm_wcons(cgm_vec4 *v, float x, float y, float z, float w); - -static inline void cgm_wadd(cgm_vec4 *a, const cgm_vec4 *b); -static inline void cgm_wsub(cgm_vec4 *a, const cgm_vec4 *b); -static inline void cgm_wmul(cgm_vec4 *a, const cgm_vec4 *b); -static inline void cgm_wscale(cgm_vec4 *v, float s); - -static inline void cgm_wmul_m4v4(cgm_vec4 *v, const float *m); -static inline void cgm_wmul_v4m4(cgm_vec4 *v, const float *m); -static inline void cgm_wmul_m34v4(cgm_vec4 *v, const float *m); /* doesn't affect w */ -static inline void cgm_wmul_v4m43(cgm_vec4 *v, const float *m); /* doesn't affect w */ -static inline void cgm_wmul_m3v4(cgm_vec4 *v, const float *m); /* (m still 16 floats) */ -static inline void cgm_wmul_v4m3(cgm_vec4 *v, const float *m); /* (m still 16 floats) */ - -static inline float cgm_wlength(const cgm_vec4 *v); -static inline float cgm_wlength_sq(const cgm_vec4 *v); -static inline float cgm_wdist(const cgm_vec4 *a, const cgm_vec4 *b); -static inline float cgm_wdist_sq(const cgm_vec4 *a, const cgm_vec4 *b); -static inline void cgm_wnormalize(cgm_vec4 *v); - -static inline void cgm_wlerp(cgm_vec4 *res, const cgm_vec4 *a, const cgm_vec4 *b, float t); - -/* --- operations on quaternions --- */ -static inline void cgm_qcons(cgm_quat *q, float x, float y, float z, float w); - -static inline void cgm_qneg(cgm_quat *q); -static inline void cgm_qadd(cgm_quat *a, const cgm_quat *b); -static inline void cgm_qsub(cgm_quat *a, const cgm_quat *b); -static inline void cgm_qmul(cgm_quat *a, const cgm_quat *b); - -static inline float cgm_qlength(const cgm_quat *q); -static inline float cgm_qlength_sq(const cgm_quat *q); -static inline void cgm_qnormalize(cgm_quat *q); -static inline void cgm_qconjugate(cgm_quat *q); -static inline void cgm_qinvert(cgm_quat *q); - -static inline void cgm_qrotation(cgm_quat *q, const cgm_vec3 *axis, float angle); -static inline void cgm_qrotate(cgm_quat *q, const cgm_vec3 *axis, float angle); - -static inline void cgm_qslerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t); -static inline void cgm_qlerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t); - -/* --- operations on matrices --- */ -static inline void cgm_mcopy(float *dest, const float *src); -static inline void cgm_mzero(float *m); -static inline void cgm_midentity(float *m); - -static inline void cgm_mmul(float *a, const float *b); - -static inline void cgm_msubmatrix(float *m, int row, int col); -static inline void cgm_mupper3(float *m); -static inline float cgm_msubdet(const float *m, int row, int col); -static inline float cgm_mcofactor(const float *m, int row, int col); -static inline float cgm_mdet(const float *m); -static inline void cgm_mtranspose(float *m); -static inline void cgm_mcofmatrix(float *m); -static inline int cgm_minverse(float *m); /* returns 0 on success, -1 for singular */ - -static inline void cgm_mtranslation(float *m, float x, float y, float z); -static inline void cgm_mscaling(float *m, float sx, float sy, float sz); -static inline void cgm_mrotation_x(float *m, float angle); -static inline void cgm_mrotation_y(float *m, float angle); -static inline void cgm_mrotation_z(float *m, float angle); -static inline void cgm_mrotation_axis(float *m, int idx, float angle); -static inline void cgm_mrotation(float *m, float angle, float x, float y, float z); -static inline void cgm_mrotation_euler(float *m, float a, float b, float c, int mode); - -static inline void cgm_mtranslate(float *m, float x, float y, float z); -static inline void cgm_mscale(float *m, float sx, float sy, float sz); -static inline void cgm_mrotate_x(float *m, float angle); -static inline void cgm_mrotate_y(float *m, float angle); -static inline void cgm_mrotate_z(float *m, float angle); -static inline void cgm_mrotate_axis(float *m, int idx, float angle); -static inline void cgm_mrotate(float *m, float angle, float x, float y, float z); -static inline void cgm_mrotate_euler(float *m, float a, float b, float c, int mode); - -static inline void cgm_mpretranslate(float *m, float x, float y, float z); -static inline void cgm_mprescale(float *m, float sx, float sy, float sz); -static inline void cgm_mprerotate_x(float *m, float angle); -static inline void cgm_mprerotate_y(float *m, float angle); -static inline void cgm_mprerotate_z(float *m, float angle); -static inline void cgm_mprerotate_axis(float *m, int idx, float angle); -static inline void cgm_mprerotate(float *m, float angle, float x, float y, float z); -static inline void cgm_mprerotate_euler(float *m, float a, float b, float c, int mode); - -static inline void cgm_mget_translation(const float *m, cgm_vec3 *res); -static inline void cgm_mget_rotation(const float *m, cgm_quat *res); -static inline void cgm_mget_scaling(const float *m, cgm_vec3 *res); -static inline void cgm_mget_frustum_plane(const float *m, int p, cgm_vec4 *res); - -static inline void cgm_mlookat(float *m, const cgm_vec3 *pos, const cgm_vec3 *targ, - const cgm_vec3 *up); -static inline void cgm_minv_lookat(float *m, const cgm_vec3 *pos, const cgm_vec3 *targ, - const cgm_vec3 *up); -static inline void cgm_mortho(float *m, float left, float right, float bot, float top, - float znear, float zfar); -static inline void cgm_mfrustum(float *m, float left, float right, float bot, float top, - float znear, float zfar); -static inline void cgm_mperspective(float *m, float vfov, float aspect, float znear, float zfar); - -static inline void cgm_mmirror(float *m, float a, float b, float c, float d); - -/* --- operations on rays --- */ -static inline void cgm_rcons(cgm_ray *r, float x, float y, float z, float dx, float dy, float dz); - -static inline void cgm_rmul_mr(cgm_ray *ray, const float *m); /* m4x4 * ray */ -static inline void cgm_rmul_rm(cgm_ray *ray, const float *m); /* ray * m4x4 */ - -static inline void cgm_rreflect(cgm_ray *ray, const cgm_vec3 *n); -static inline void cgm_rrefract(cgm_ray *ray, const cgm_vec3 *n, float ior); - -/* --- miscellaneous utility functions --- */ -static inline float cgm_deg_to_rad(float deg); -static inline float cgm_rad_to_deg(float rad); - -static inline float cgm_smoothstep(float a, float b, float x); -static inline float cgm_bezier(float a, float b, float c, float d, float t); - -static inline void cgm_discrand(cgm_vec3 *v, float rad); -static inline void cgm_sphrand(cgm_vec3 *v, float rad); - -static inline void cgm_unproject(cgm_vec3 *res, const cgm_vec3 *norm_scrpos, - const float *inv_viewproj); -static inline void cgm_glu_unproject(float winx, float winy, float winz, - const float *view, const float *proj, const int *vp, - float *objx, float *objy, float *objz); - -static inline void cgm_pick_ray(cgm_ray *ray, float nx, float ny, - const float *viewmat, const float *projmat); - -static inline void cgm_raypos(cgm_vec3 *p, const cgm_ray *ray, float t); - -/* calculate barycentric coordinates of point pt in triangle (a, b, c) */ -static inline void cgm_bary(cgm_vec3 *bary, const cgm_vec3 *a, - const cgm_vec3 *b, const cgm_vec3 *c, const cgm_vec3 *pt); - -#include "cgmvec3.inl" -#include "cgmvec4.inl" -#include "cgmquat.inl" -#include "cgmmat.inl" -#include "cgmray.inl" -#include "cgmmisc.inl" - -#ifdef __cplusplus -} -#endif - -#endif /* CGMATH_H_ */ diff --git a/src/cgmath/cgmmat.inl b/src/cgmath/cgmmat.inl deleted file mode 100644 index 62edc8b..0000000 --- a/src/cgmath/cgmmat.inl +++ /dev/null @@ -1,577 +0,0 @@ -/* gph-cmath - C graphics math library - * Copyright (C) 2018 John Tsiombikas - * - * This program is free software. Feel free to use, modify, and/or redistribute - * it under the terms of the MIT/X11 license. See LICENSE for details. - * If you intend to redistribute parts of the code without the LICENSE file - * replace this paragraph with the full contents of the LICENSE file. - */ -static inline void cgm_mcopy(float *dest, const float *src) -{ - memcpy(dest, src, 16 * sizeof(float)); -} - -static inline void cgm_mzero(float *m) -{ - static float z[16]; - cgm_mcopy(m, z); -} - -static inline void cgm_midentity(float *m) -{ - static float id[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; - cgm_mcopy(m, id); -} - -static inline void cgm_mmul(float *a, const float *b) -{ - int i, j; - float res[16]; - float *resptr = res; - float *arow = a; - - for(i=0; i<4; i++) { - for(j=0; j<4; j++) { - *resptr++ = arow[0] * b[j] + arow[1] * b[4 + j] + - arow[2] * b[8 + j] + arow[3] * b[12 + j]; - } - arow += 4; - } - cgm_mcopy(a, res); -} - -static inline void cgm_msubmatrix(float *m, int row, int col) -{ - float orig[16]; - int i, j, subi, subj; - - cgm_mcopy(orig, m); - - subi = 0; - for(i=0; i<4; i++) { - if(i == row) continue; - - subj = 0; - for(j=0; j<4; j++) { - if(j == col) continue; - - m[subi * 4 + subj++] = orig[i * 4 + j]; - } - subi++; - } - - cgm_mupper3(m); -} - -static inline void cgm_mupper3(float *m) -{ - m[3] = m[7] = m[11] = m[12] = m[13] = m[14] = 0.0f; - m[15] = 1.0f; -} - -static inline float cgm_msubdet(const float *m, int row, int col) -{ - float tmp[16]; - float subdet00, subdet01, subdet02; - - cgm_mcopy(tmp, m); - cgm_msubmatrix(tmp, row, col); - - subdet00 = tmp[5] * tmp[10] - tmp[6] * tmp[9]; - subdet01 = tmp[4] * tmp[10] - tmp[6] * tmp[8]; - subdet02 = tmp[4] * tmp[9] - tmp[5] * tmp[8]; - - return tmp[0] * subdet00 - tmp[1] * subdet01 + tmp[2] * subdet02; -} - -static inline float cgm_mcofactor(const float *m, int row, int col) -{ - float min = cgm_msubdet(m, row, col); - return (row + col) & 1 ? -min : min; -} - -static inline float cgm_mdet(const float *m) -{ - return m[0] * cgm_msubdet(m, 0, 0) - m[1] * cgm_msubdet(m, 0, 1) + - m[2] * cgm_msubdet(m, 0, 2) - m[3] * cgm_msubdet(m, 0, 3); -} - -static inline void cgm_mtranspose(float *m) -{ - int i, j; - for(i=0; i<4; i++) { - for(j=0; jx = m[12]; - res->y = m[13]; - res->z = m[14]; -} - -/* Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes - * article "Quaternion Calculus and Fast Animation". - * adapted from: http://www.geometrictools.com/LibMathematics/Algebra/Wm5Quaternion.inl - */ -static inline void cgm_mget_rotation(const float *m, cgm_quat *res) -{ - static const int next[3] = {1, 2, 0}; - float quat[4]; - int i, j, k; - - float trace = m[0] + m[5] + m[10]; - float root; - - if(trace > 0.0f) { - // |w| > 1/2 - root = sqrt(trace + 1.0f); // 2w - res->w = 0.5f * root; - root = 0.5f / root; // 1 / 4w - res->x = (m[6] - m[9]) * root; - res->y = (m[8] - m[2]) * root; - res->z = (m[1] - m[4]) * root; - } else { - // |w| <= 1/2 - i = 0; - if(m[5] > m[0]) { - i = 1; - } - if(m[10] > m[i * 4 + i]) { - i = 2; - } - j = next[i]; - k = next[j]; - - root = sqrt(m[i * 4 + i] - m[j * 4 + j] - m[k * 4 + k] + 1.0f); - quat[i + 1] = 0.5f * root; - root = 0.5f / root; - quat[0] = (m[j + 4 + k] - m[k * 4 + j]) * root; - quat[j + 1] = (m[i * 4 + j] - m[j * 4 + i]) * root; - quat[k + 1] = (m[i * 4 + k] - m[k * 4 + i]) * root; - res->w = quat[0]; - res->x = quat[1]; - res->y = quat[2]; - res->z = quat[3]; - } -} - -static inline void cgm_mget_scaling(const float *m, cgm_vec3 *res) -{ - res->x = sqrt(m[0] * m[0] + m[4] * m[4] + m[8] * m[8]); - res->y = sqrt(m[1] * m[1] + m[5] * m[5] + m[9] * m[9]); - res->z = sqrt(m[2] * m[2] + m[6] * m[6] + m[10] * m[10]); -} - -static inline void cgm_mget_frustum_plane(const float *m, int p, cgm_vec4 *res) -{ - int row = p >> 1; - const float *rowptr = m + row * 4; - - if((p & 1) == 0) { - res->x = m[12] + rowptr[0]; - res->y = m[13] + rowptr[1]; - res->z = m[14] + rowptr[2]; - res->w = m[15] + rowptr[3]; - } else { - res->x = m[12] - rowptr[0]; - res->y = m[13] - rowptr[1]; - res->z = m[14] - rowptr[2]; - res->w = m[15] - rowptr[3]; - } -} - -static inline void cgm_mlookat(float *m, const cgm_vec3 *pos, const cgm_vec3 *targ, - const cgm_vec3 *up) -{ - float trans[16]; - cgm_vec3 dir = *targ, right, vup; - - cgm_vsub(&dir, pos); - cgm_vnormalize(&dir); - cgm_vcross(&right, &dir, up); - cgm_vnormalize(&right); - cgm_vcross(&vup, &right, &dir); - cgm_vnormalize(&vup); - - cgm_midentity(m); - m[0] = right.x; - m[1] = right.y; - m[2] = right.z; - m[4] = vup.x; - m[5] = vup.y; - m[6] = vup.z; - m[8] = -dir.x; - m[9] = -dir.y; - m[10] = -dir.z; - - cgm_mtranslation(trans, pos->x, pos->y, pos->z); - cgm_mmul(m, trans); -} - -static inline void cgm_minv_lookat(float *m, const cgm_vec3 *pos, const cgm_vec3 *targ, - const cgm_vec3 *up) -{ - float rot[16]; - cgm_vec3 dir = *targ, right, vup; - - cgm_vsub(&dir, pos); - cgm_vnormalize(&dir); - cgm_vcross(&right, &dir, up); - cgm_vnormalize(&right); - cgm_vcross(&vup, &right, &dir); - cgm_vnormalize(&vup); - - cgm_midentity(rot); - rot[0] = right.x; - rot[4] = right.y; - rot[8] = right.z; - rot[1] = vup.x; - rot[5] = vup.y; - rot[9] = vup.z; - rot[2] = -dir.x; - rot[6] = -dir.y; - rot[10] = -dir.z; - - cgm_mtranslation(m, -pos->x, -pos->y, -pos->z); - cgm_mmul(m, rot); -} - -static inline void cgm_mortho(float *m, float left, float right, float bot, float top, - float znear, float zfar) -{ - float dx = right - left; - float dy = top - bot; - float dz = zfar - znear; - - cgm_midentity(m); - m[0] = 2.0f / dx; - m[5] = 2.0f / dy; - m[10] = -2.0f / dz; - m[12] = -(right + left) / dx; - m[13] = -(top + bot) / dy; - m[14] = -(zfar + znear) / dz; -} - -static inline void cgm_mfrustum(float *m, float left, float right, float bot, float top, - float znear, float zfar) -{ - float dx = right - left; - float dy = top - bot; - float dz = zfar - znear; - - cgm_mzero(m); - m[0] = 2.0f * znear / dx; - m[5] = 2.0f * znear / dy; - m[8] = (right + left) / dx; - m[9] = (top + bot) / dy; - m[10] = -(zfar + znear) / dz; - m[14] = -2.0f * zfar * znear / dz; - m[11] = -1.0f; -} - -static inline void cgm_mperspective(float *m, float vfov, float aspect, float znear, float zfar) -{ - float s = 1.0f / (float)tan(vfov / 2.0f); - float range = znear - zfar; - - cgm_mzero(m); - m[0] = s / aspect; - m[5] = s; - m[10] = (znear + zfar) / range; - m[14] = 2.0f * znear * zfar / range; - m[11] = -1.0f; -} - -static inline void cgm_mmirror(float *m, float a, float b, float c, float d) -{ - m[0] = 1.0f - 2.0f * a * a; - m[5] = 1.0f - 2.0f * b * b; - m[10] = 1.0f - 2.0f * c * c; - m[15] = 1.0f; - - m[1] = m[4] = -2.0f * a * b; - m[2] = m[8] = -2.0f * a * c; - m[6] = m[9] = -2.0f * b * c; - - m[12] = -2.0f * a * d; - m[13] = -2.0f * b * d; - m[14] = -2.0f * c * d; - - m[3] = m[7] = m[11] = 0.0f; -} diff --git a/src/cgmath/cgmmisc.inl b/src/cgmath/cgmmisc.inl deleted file mode 100644 index 6cfa37d..0000000 --- a/src/cgmath/cgmmisc.inl +++ /dev/null @@ -1,154 +0,0 @@ -/* gph-cmath - C graphics math library - * Copyright (C) 2018 John Tsiombikas - * - * This program is free software. Feel free to use, modify, and/or redistribute - * it under the terms of the MIT/X11 license. See LICENSE for details. - * If you intend to redistribute parts of the code without the LICENSE file - * replace this paragraph with the full contents of the LICENSE file. - */ -#include - -static inline float cgm_deg_to_rad(float deg) -{ - return M_PI * deg / 180.0f; -} - -static inline float cgm_rad_to_deg(float rad) -{ - return 180.0f * rad / M_PI; -} - -static inline float cgm_smoothstep(float a, float b, float x) -{ - if(x < a) return 0.0f; - if(x >= b) return 1.0f; - - x = (x - a) / (b - a); - return x * x * (3.0f - 2.0f * x); -} - -static inline float cgm_lerp(float a, float b, float t) -{ - return a + (b - a) * t; -} - -static inline float cgm_bezier(float a, float b, float c, float d, float t) -{ - float omt, omt3, t3, f; - t3 = t * t * t; - omt = 1.0f - t; - omt3 = omt * omt * omt; - f = 3.0f * t * omt; - - return (a * omt3) + (b * f * omt) + (c * f * t) + (d * t3); -} - -static inline void cgm_discrand(cgm_vec3 *pt, float rad) -{ - float theta = 2.0f * M_PI * (float)rand() / RAND_MAX; - float r = sqrt((float)rand() / RAND_MAX) * rad; - pt->x = cos(theta) * r; - pt->y = sin(theta) * r; - pt->z = 0.0f; -} - -static inline void cgm_sphrand(cgm_vec3 *pt, float rad) -{ - float u, v, theta, phi; - - u = (float)rand() / RAND_MAX; - v = (float)rand() / RAND_MAX; - - theta = 2.0f * M_PI * u; - phi = acos(2.0f * v - 1.0f); - - pt->x = cos(theta) * sin(phi) * rad; - pt->y = sin(theta) * sin(phi) * rad; - pt->z = cos(phi) * rad; -} - -static inline void cgm_unproject(cgm_vec3 *res, const cgm_vec3 *norm_scrpos, - const float *inv_viewproj) -{ - cgm_vec4 pos; - - pos.x = 2.0f * norm_scrpos->x - 1.0f; - pos.y = 2.0f * norm_scrpos->y - 1.0f; - pos.z = 2.0f * norm_scrpos->z - 1.0f; - pos.w = 1.0f; - - cgm_wmul_m4v4(&pos, inv_viewproj); - - res->x = pos.x / pos.w; - res->y = pos.y / pos.w; - res->z = pos.z / pos.w; -} - -static inline void cgm_glu_unproject(float winx, float winy, float winz, - const float *view, const float *proj, const int *vp, - float *objx, float *objy, float *objz) -{ - cgm_vec3 npos, res; - float inv_pv[16]; - - cgm_mcopy(inv_pv, proj); - cgm_mmul(inv_pv, view); - - npos.x = (winx - vp[0]) / vp[2]; - npos.y = (winy - vp[1]) / vp[4]; - npos.z = winz; - - cgm_unproject(&res, &npos, inv_pv); - - *objx = res.x; - *objy = res.y; - *objz = res.z; -} - -static inline void cgm_pick_ray(cgm_ray *ray, float nx, float ny, - const float *viewmat, const float *projmat) -{ - cgm_vec3 npos, farpt; - float inv_pv[16]; - - cgm_mcopy(inv_pv, projmat); - cgm_mmul(inv_pv, viewmat); - - cgm_vcons(&npos, nx, ny, 0.0f); - cgm_unproject(&ray->origin, &npos, inv_pv); - npos.z = 1.0f; - cgm_unproject(&farpt, &npos, inv_pv); - - ray->dir.x = farpt.x - ray->origin.x; - ray->dir.y = farpt.y - ray->origin.y; - ray->dir.z = farpt.z - ray->origin.z; -} - -static inline void cgm_raypos(cgm_vec3 *p, const cgm_ray *ray, float t) -{ - p->x = ray->origin.x + ray->dir.x * t; - p->y = ray->origin.y + ray->dir.y * t; - p->z = ray->origin.z + ray->dir.z * t; -} - -static inline void cgm_bary(cgm_vec3 *bary, const cgm_vec3 *a, - const cgm_vec3 *b, const cgm_vec3 *c, const cgm_vec3 *pt) -{ - float d00, d01, d11, d20, d21, denom; - cgm_vec3 v0 = *b, v1 = *c, v2 = *pt; - - cgm_vsub(&v0, a); - cgm_vsub(&v1, a); - cgm_vsub(&v2, a); - - d00 = cgm_vdot(&v0, &v0); - d01 = cgm_vdot(&v0, &v1); - d11 = cgm_vdot(&v1, &v1); - d20 = cgm_vdot(&v2, &v0); - d21 = cgm_vdot(&v2, &v1); - denom = d00 * d11 - d01 * d01; - - bary->y = (d11 * d20 - d01 * d21) / denom; - bary->z = (d00 * d21 - d01 * d20) / denom; - bary->x = 1.0f - bary->y - bary->z; -} diff --git a/src/cgmath/cgmquat.inl b/src/cgmath/cgmquat.inl deleted file mode 100644 index 4b29fd2..0000000 --- a/src/cgmath/cgmquat.inl +++ /dev/null @@ -1,159 +0,0 @@ -/* gph-cmath - C graphics math library - * Copyright (C) 2018 John Tsiombikas - * - * This program is free software. Feel free to use, modify, and/or redistribute - * it under the terms of the MIT/X11 license. See LICENSE for details. - * If you intend to redistribute parts of the code without the LICENSE file - * replace this paragraph with the full contents of the LICENSE file. - */ -static inline void cgm_qcons(cgm_quat *q, float x, float y, float z, float w) -{ - q->x = x; - q->y = y; - q->z = z; - q->w = w; -} - - -static inline void cgm_qneg(cgm_quat *q) -{ - q->x = -q->x; - q->y = -q->y; - q->z = -q->z; - q->w = -q->w; -} - -static inline void cgm_qadd(cgm_quat *a, const cgm_quat *b) -{ - a->x += b->x; - a->y += b->y; - a->z += b->z; - a->w += b->w; -} - -static inline void cgm_qsub(cgm_quat *a, const cgm_quat *b) -{ - a->x -= b->x; - a->y -= b->y; - a->z -= b->z; - a->w -= b->w; -} - -static inline void cgm_qmul(cgm_quat *a, const cgm_quat *b) -{ - float x, y, z, dot; - cgm_vec3 cross; - - dot = a->x * b->x + a->y * b->y + a->z * b->z; - cgm_vcross(&cross, (cgm_vec3*)a, (cgm_vec3*)b); - - x = a->w * b->x + b->w * a->x + cross.x; - y = a->w * b->y + b->w * a->y + cross.y; - z = a->w * b->z + b->w * a->z + cross.z; - a->w = a->w * b->w - dot; - a->x = x; - a->y = y; - a->z = z; -} - -static inline float cgm_qlength(const cgm_quat *q) -{ - return sqrt(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w); -} - -static inline float cgm_qlength_sq(const cgm_quat *q) -{ - return q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w; -} - -static inline void cgm_qnormalize(cgm_quat *q) -{ - float len = cgm_qlength(q); - if(len != 0.0f) { - float s = 1.0f / len; - q->x *= s; - q->y *= s; - q->z *= s; - q->w *= s; - } -} - -static inline void cgm_qconjugate(cgm_quat *q) -{ - q->x = -q->x; - q->y = -q->y; - q->z = -q->z; -} - -static inline void cgm_qinvert(cgm_quat *q) -{ - float len_sq = cgm_qlength_sq(q); - cgm_qconjugate(q); - if(len_sq != 0.0f) { - float s = 1.0f / len_sq; - q->x *= s; - q->y *= s; - q->z *= s; - q->w *= s; - } -} - -static inline void cgm_qrotation(cgm_quat *q, const cgm_vec3 *axis, float angle) -{ - float hangle = angle * 0.5f; - float sin_ha = sin(hangle); - q->w = cos(hangle); - q->x = axis->x * sin_ha; - q->y = axis->y * sin_ha; - q->z = axis->z * sin_ha; -} - -static inline void cgm_qrotate(cgm_quat *q, const cgm_vec3 *axis, float angle) -{ - cgm_quat qrot; - cgm_qrotation(&qrot, axis, angle); - cgm_qmul(q, &qrot); -} - -static inline void cgm_qslerp(cgm_quat *res, const cgm_quat *quat1, const cgm_quat *q2, float t) -{ - float angle, dot, a, b, sin_angle; - cgm_quat q1 = *quat1; - - dot = quat1->x * q2->x + quat1->y * q2->y + quat1->z * q2->z + quat1->w * q2->w; - if(dot < 0.0f) { - /* make sure we inteprolate across the shortest arc */ - cgm_qneg(&q1); - dot = -dot; - } - - /* clamp dot to [-1, 1] in order to avoid domain errors in acos due to - * floating point imprecisions - */ - if(dot < -1.0f) dot = -1.0f; - if(dot > 1.0f) dot = 1.0f; - angle = acos(dot); - - sin_angle = sin(angle); - if(sin_angle == 0.0f) { - /* use linear interpolation to avoid div/zero */ - a = 1.0f; - b = t; - } else { - a = sin((1.0f - t) * angle) / sin_angle; - b = sin(t * angle) / sin_angle; - } - - res->x = q1.x * a + q2->x * b; - res->y = q1.y * a + q2->y * b; - res->z = q1.z * a + q2->z * b; - res->w = q1.w * a + q2->w * b; -} - -static inline void cgm_qlerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t) -{ - res->x = a->x + (b->x - a->x) * t; - res->y = a->y + (b->y - a->y) * t; - res->z = a->z + (b->z - a->z) * t; - res->w = a->w + (b->w - a->w) * t; -} diff --git a/src/cgmath/cgmray.inl b/src/cgmath/cgmray.inl deleted file mode 100644 index 063a7e0..0000000 --- a/src/cgmath/cgmray.inl +++ /dev/null @@ -1,39 +0,0 @@ -/* gph-cmath - C graphics math library - * Copyright (C) 2018 John Tsiombikas - * - * This program is free software. Feel free to use, modify, and/or redistribute - * it under the terms of the MIT/X11 license. See LICENSE for details. - * If you intend to redistribute parts of the code without the LICENSE file - * replace this paragraph with the full contents of the LICENSE file. - */ -static inline void cgm_rcons(cgm_ray *r, float x, float y, float z, float dx, float dy, float dz) -{ - r->origin.x = x; - r->origin.y = y; - r->origin.z = z; - r->dir.x = dx; - r->dir.y = dy; - r->dir.z = dz; -} - -static inline void cgm_rmul_mr(cgm_ray *ray, const float *m) -{ - cgm_vmul_m4v3(&ray->origin, m); - cgm_vmul_m3v3(&ray->dir, m); -} - -static inline void cgm_rmul_rm(cgm_ray *ray, const float *m) -{ - cgm_vmul_v3m4(&ray->origin, m); - cgm_vmul_v3m3(&ray->dir, m); -} - -static inline void cgm_rreflect(cgm_ray *ray, const cgm_vec3 *n) -{ - cgm_vreflect(&ray->dir, n); -} - -static inline void cgm_rrefract(cgm_ray *ray, const cgm_vec3 *n, float ior) -{ - cgm_vrefract(&ray->dir, n, ior); -} diff --git a/src/cgmath/cgmvec3.inl b/src/cgmath/cgmvec3.inl deleted file mode 100644 index 88211c4..0000000 --- a/src/cgmath/cgmvec3.inl +++ /dev/null @@ -1,188 +0,0 @@ -/* gph-cmath - C graphics math library - * Copyright (C) 2018 John Tsiombikas - * - * This program is free software. Feel free to use, modify, and/or redistribute - * it under the terms of the MIT/X11 license. See LICENSE for details. - * If you intend to redistribute parts of the code without the LICENSE file - * replace this paragraph with the full contents of the LICENSE file. - */ -static inline void cgm_vcons(cgm_vec3 *v, float x, float y, float z) -{ - v->x = x; - v->y = y; - v->z = z; -} - -static inline void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b) -{ - a->x += b->x; - a->y += b->y; - a->z += b->z; -} - -static inline void cgm_vsub(cgm_vec3 *a, const cgm_vec3 *b) -{ - a->x -= b->x; - a->y -= b->y; - a->z -= b->z; -} - -static inline void cgm_vmul(cgm_vec3 *a, const cgm_vec3 *b) -{ - a->x *= b->x; - a->y *= b->y; - a->z *= b->z; -} - -static inline void cgm_vscale(cgm_vec3 *v, float s) -{ - v->x *= s; - v->y *= s; - v->z *= s; -} - -static inline void cgm_vmul_m4v3(cgm_vec3 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + m[12]; - float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + m[13]; - v->z = v->x * m[2] + v->y * m[6] + v->z * m[10] + m[14]; - v->x = x; - v->y = y; -} - -static inline void cgm_vmul_v3m4(cgm_vec3 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + m[3]; - float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + m[7]; - v->z = v->x * m[8] + v->y * m[9] + v->z * m[10] + m[11]; - v->x = x; - v->y = y; -} - -static inline void cgm_vmul_m3v3(cgm_vec3 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[4] + v->z * m[8]; - float y = v->x * m[1] + v->y * m[5] + v->z * m[9]; - v->z = v->x * m[2] + v->y * m[6] + v->z * m[10]; - v->x = x; - v->y = y; -} - -static inline void cgm_vmul_v3m3(cgm_vec3 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[1] + v->z * m[2]; - float y = v->x * m[4] + v->y * m[5] + v->z * m[6]; - v->z = v->x * m[8] + v->y * m[9] + v->z * m[10]; - v->x = x; - v->y = y; -} - -static inline float cgm_vdot(const cgm_vec3 *a, const cgm_vec3 *b) -{ - return a->x * b->x + a->y * b->y + a->z * b->z; -} - -static inline void cgm_vcross(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b) -{ - res->x = a->y * b->z - a->z * b->y; - res->y = a->z * b->x - a->x * b->z; - res->z = a->x * b->y - a->y * b->x; -} - -static inline float cgm_vlength(const cgm_vec3 *v) -{ - return sqrt(v->x * v->x + v->y * v->y + v->z * v->z); -} - -static inline float cgm_vlength_sq(const cgm_vec3 *v) -{ - return v->x * v->x + v->y * v->y + v->z * v->z; -} - -static inline float cgm_vdist(const cgm_vec3 *a, const cgm_vec3 *b) -{ - float dx = a->x - b->x; - float dy = a->y - b->y; - float dz = a->z - b->z; - return sqrt(dx * dx + dy * dy + dz * dz); -} - -static inline float cgm_vdist_sq(const cgm_vec3 *a, const cgm_vec3 *b) -{ - float dx = a->x - b->x; - float dy = a->y - b->y; - float dz = a->z - b->z; - return dx * dx + dy * dy + dz * dz; -} - -static inline void cgm_vnormalize(cgm_vec3 *v) -{ - float len = cgm_vlength(v); - if(len != 0.0f) { - float s = 1.0f / len; - v->x *= s; - v->y *= s; - v->z *= s; - } -} - -static inline void cgm_vreflect(cgm_vec3 *v, const cgm_vec3 *n) -{ - float ndotv2 = cgm_vdot(v, n) * 2.0f; - v->x -= n->x * ndotv2; - v->y -= n->y * ndotv2; - v->z -= n->z * ndotv2; -} - -static inline void cgm_vrefract(cgm_vec3 *v, const cgm_vec3 *n, float ior) -{ - float ndotv = cgm_vdot(v, n); - float k = 1.0f - ior * ior * (1.0f - ndotv * ndotv); - if(k < 0.0f) { - cgm_vreflect(v, n); /* TIR */ - } else { - float sqrt_k = sqrt(k); - v->x = ior * v->x - (ior * ndotv + sqrt_k) * n->x; - v->y = ior * v->y - (ior * ndotv + sqrt_k) * n->y; - v->z = ior * v->z - (ior * ndotv + sqrt_k) * n->z; - } -} - -static inline void cgm_vrotate_quat(cgm_vec3 *v, const cgm_quat *q) -{ - cgm_quat vq, inv_q = *q, tmp_q = *q; - - cgm_qcons(&vq, v->x, v->y, v->z, 0.0f); - cgm_qinvert(&inv_q); - cgm_qmul(&tmp_q, &vq); - cgm_qmul(&vq, &inv_q); - cgm_vcons(v, vq.x, vq.y, vq.z); -} - -static inline void cgm_vrotate_axis(cgm_vec3 *v, int axis, float angle) -{ - float m[16]; - cgm_mrotation_axis(m, axis, angle); - cgm_vmul_m3v3(v, m); -} - -static inline void cgm_vrotate(cgm_vec3 *v, float angle, float x, float y, float z) -{ - float m[16]; - cgm_mrotation(m, angle, x, y, z); - cgm_vmul_m3v3(v, m); -} - -static inline void cgm_vrotate_euler(cgm_vec3 *v, float a, float b, float c, enum cgm_euler_mode mode) -{ - float m[16]; - cgm_mrotation_euler(m, a, b, c, mode); - cgm_vmul_m3v3(v, m); -} - -static inline void cgm_vlerp(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b, float t) -{ - res->x = a->x + (b->x - a->x) * t; - res->y = a->y + (b->y - a->y) * t; - res->z = a->z + (b->z - a->z) * t; -} diff --git a/src/cgmath/cgmvec4.inl b/src/cgmath/cgmvec4.inl deleted file mode 100644 index 1c143c2..0000000 --- a/src/cgmath/cgmvec4.inl +++ /dev/null @@ -1,153 +0,0 @@ -/* gph-cmath - C graphics math library - * Copyright (C) 2018 John Tsiombikas - * - * This program is free software. Feel free to use, modify, and/or redistribute - * it under the terms of the MIT/X11 license. See LICENSE for details. - * If you intend to redistribute parts of the code without the LICENSE file - * replace this paragraph with the full contents of the LICENSE file. - */ -static inline void cgm_wcons(cgm_vec4 *v, float x, float y, float z, float w) -{ - v->x = x; - v->y = y; - v->z = z; - v->w = w; -} - -static inline void cgm_wadd(cgm_vec4 *a, const cgm_vec4 *b) -{ - a->x += b->x; - a->y += b->y; - a->z += b->z; - a->w += b->w; -} - -static inline void cgm_wsub(cgm_vec4 *a, const cgm_vec4 *b) -{ - a->x -= b->x; - a->y -= b->y; - a->z -= b->z; - a->w -= b->w; -} - -static inline void cgm_wmul(cgm_vec4 *a, const cgm_vec4 *b) -{ - a->x *= b->x; - a->y *= b->y; - a->z *= b->z; - a->w *= b->w; -} - -static inline void cgm_wscale(cgm_vec4 *v, float s) -{ - v->x *= s; - v->y *= s; - v->z *= s; - v->w *= s; -} - -static inline void cgm_wmul_m4v4(cgm_vec4 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + v->w * m[12]; - float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + v->w * m[13]; - float z = v->x * m[2] + v->y * m[6] + v->z * m[10] + v->w * m[14]; - v->w = v->x * m[3] + v->y * m[7] + v->z * m[11] + v->w * m[15]; - v->x = x; - v->y = y; - v->z = z; -} - -static inline void cgm_wmul_v4m4(cgm_vec4 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + v->w * m[3]; - float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + v->w * m[7]; - float z = v->x * m[8] + v->y * m[9] + v->z * m[10] + v->w * m[11]; - v->w = v->x * m[12] + v->y * m[13] + v->z * m[14] + v->w * m[15]; - v->x = x; - v->y = y; - v->z = z; -} - -static inline void cgm_wmul_m34v4(cgm_vec4 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + v->w * m[12]; - float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + v->w * m[13]; - v->z = v->x * m[2] + v->y * m[6] + v->z * m[10] + v->w * m[14]; - v->x = x; - v->y = y; -} - -static inline void cgm_wmul_v4m43(cgm_vec4 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + v->w * m[3]; - float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + v->w * m[7]; - v->z = v->x * m[8] + v->y * m[9] + v->z * m[10] + v->w * m[11]; - v->x = x; - v->y = y; -} - -static inline void cgm_wmul_m3v4(cgm_vec4 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[4] + v->z * m[8]; - float y = v->x * m[1] + v->y * m[5] + v->z * m[9]; - v->z = v->x * m[2] + v->y * m[6] + v->z * m[10]; - v->x = x; - v->y = y; -} - -static inline void cgm_wmul_v4m3(cgm_vec4 *v, const float *m) -{ - float x = v->x * m[0] + v->y * m[1] + v->z * m[2]; - float y = v->x * m[4] + v->y * m[5] + v->z * m[6]; - v->z = v->x * m[8] + v->y * m[9] + v->z * m[10]; - v->x = x; - v->y = y; -} - -static inline float cgm_wlength(const cgm_vec4 *v) -{ - return sqrt(v->x * v->x + v->y * v->y + v->z * v->z + v->w * v->w); -} - -static inline float cgm_wlength_sq(const cgm_vec4 *v) -{ - return v->x * v->x + v->y * v->y + v->z * v->z + v->w * v->w; -} - -static inline float cgm_wdist(const cgm_vec4 *a, const cgm_vec4 *b) -{ - float dx = a->x - b->x; - float dy = a->y - b->y; - float dz = a->z - b->z; - float dw = a->w - b->w; - return sqrt(dx * dx + dy * dy + dz * dz + dw * dw); -} - -static inline float cgm_wdist_sq(const cgm_vec4 *a, const cgm_vec4 *b) -{ - float dx = a->x - b->x; - float dy = a->y - b->y; - float dz = a->z - b->z; - float dw = a->w - b->w; - return dx * dx + dy * dy + dz * dz + dw * dw; -} - -static inline void cgm_wnormalize(cgm_vec4 *v) -{ - float len = cgm_wlength(v); - if(len != 0.0f) { - float s = 1.0f / len; - v->x *= s; - v->y *= s; - v->z *= s; - v->w *= s; - } -} - -static inline void cgm_wlerp(cgm_vec4 *res, const cgm_vec4 *a, const cgm_vec4 *b, float t) -{ - res->x = a->x + (b->x - a->x) * t; - res->y = a->y + (b->y - a->y) * t; - res->z = a->z + (b->z - a->z) * t; - res->w = a->w + (b->w - a->w) * t; -}