added libanim, and moved gph-cmath into libs/cgmath
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 10 Dec 2018 17:42:58 +0000 (19:42 +0200)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 10 Dec 2018 17:42:58 +0000 (19:42 +0200)
22 files changed:
libs/anim/GNUmakefile [new file with mode: 0644]
libs/anim/Makefile [new file with mode: 0644]
libs/anim/Makefile.dj [new file with mode: 0644]
libs/anim/src/anim.c [new file with mode: 0644]
libs/anim/src/anim.h [new file with mode: 0644]
libs/anim/src/config.h [new file with mode: 0644]
libs/anim/src/track.c [new file with mode: 0644]
libs/anim/src/track.h [new file with mode: 0644]
libs/cgmath/cgmath.h [new file with mode: 0644]
libs/cgmath/cgmmat.inl [new file with mode: 0644]
libs/cgmath/cgmmisc.inl [new file with mode: 0644]
libs/cgmath/cgmquat.inl [new file with mode: 0644]
libs/cgmath/cgmray.inl [new file with mode: 0644]
libs/cgmath/cgmvec3.inl [new file with mode: 0644]
libs/cgmath/cgmvec4.inl [new file with mode: 0644]
src/cgmath/cgmath.h [deleted file]
src/cgmath/cgmmat.inl [deleted file]
src/cgmath/cgmmisc.inl [deleted file]
src/cgmath/cgmquat.inl [deleted file]
src/cgmath/cgmray.inl [deleted file]
src/cgmath/cgmvec3.inl [deleted file]
src/cgmath/cgmvec4.inl [deleted file]

diff --git a/libs/anim/GNUmakefile b/libs/anim/GNUmakefile
new file mode 100644 (file)
index 0000000..b795392
--- /dev/null
@@ -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 (file)
index 0000000..657e083
--- /dev/null
@@ -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 (file)
index 0000000..e73b990
--- /dev/null
@@ -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 (file)
index 0000000..a2f1944
--- /dev/null
@@ -0,0 +1,1020 @@
+/*
+libanim - hierarchical keyframe animation library
+Copyright (C) 2012-2018 John Tsiombikas <nuclear@member.fsf.org>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+#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; i<ANM_NUM_TRACKS; i++) {
+               if(anm_init_track(anim->tracks + i) == -1) {
+                       for(j=0; j<i; j++) {
+                               anm_destroy_track(anim->tracks + 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; i<ANM_NUM_TRACKS; i++) {
+               anm_destroy_track(anim->tracks + 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; i<num_anim; i++) {
+               anm_destroy_animation(node->animations + 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; i<count; i++) {
+               if(strcmp(node->animations[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; i<ANM_NUM_TRACKS; i++) {
+               anm_set_track_interpolator(anim->tracks + 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; i<ANM_NUM_TRACKS; i++) {
+               anm_set_track_extrapolator(anim->tracks + 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; i<ANM_NUM_TRACKS; i++) {
+                       if(anim->tracks[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; i<ANM_NUM_TRACKS; i++) {
+                       if(anim->tracks[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 (file)
index 0000000..e5433f7
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+libanim - hierarchical keyframe animation library
+Copyright (C) 2012-2018 John Tsiombikas <nuclear@member.fsf.org>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+#ifndef LIBANIM_H_
+#define LIBANIM_H_
+
+#include "config.h"
+
+#if _MSC_VER >= 1900
+#define _TIMESPEC_DEFINED
+#endif
+
+#ifdef ANIM_THREAD_SAFE
+#include <pthread.h>
+#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 (file)
index 0000000..f00310c
--- /dev/null
@@ -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 (file)
index 0000000..a144efd
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+libanim - hierarchical keyframe animation library
+Copyright (C) 2012-2015 John Tsiombikas <nuclear@member.fsf.org>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#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 (file)
index 0000000..89749dd
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+libanim - hierarchical keyframe animation library
+Copyright (C) 2012-2014 John Tsiombikas <nuclear@member.fsf.org>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+
+/* 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 <limits.h>
+#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 (file)
index 0000000..e660437
--- /dev/null
@@ -0,0 +1,243 @@
+/* gph-cmath - C graphics math library
+ * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * 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 <math.h>
+#include <string.h>
+
+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 (file)
index 0000000..c369b84
--- /dev/null
@@ -0,0 +1,623 @@
+/* gph-cmath - C graphics math library
+ * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * 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; j<i; j++) {
+                       int a = i * 4 + j;
+                       int b = j * 4 + i;
+                       float tmp = m[a];
+                       m[a] = m[b];
+                       m[b] = tmp;
+               }
+       }
+}
+
+static inline void cgm_mcofmatrix(float *m)
+{
+       float tmp[16];
+       int i, j;
+
+       cgm_mcopy(tmp, m);
+
+       for(i=0; i<4; i++) {
+               for(j=0; j<4; j++) {
+                       m[i * 4 + j] = cgm_mcofactor(tmp, i, j);
+               }
+       }
+}
+
+static inline int cgm_minverse(float *m)
+{
+       int i, j;
+       float tmp[16];
+       float inv_det;
+       float det = cgm_mdet(m);
+       if(det == 0.0f) return -1;
+       inv_det = 1.0f / det;
+
+       cgm_mcopy(tmp, m);
+
+       for(i=0; i<4; i++) {
+               for(j=0; j<4; j++) {
+                       m[i * 4 + j] = cgm_mcofactor(tmp, j, i) * inv_det;      /* transposed */
+               }
+       }
+       return 0;
+}
+
+static inline void cgm_mtranslation(float *m, float x, float y, float z)
+{
+       cgm_midentity(m);
+       m[12] = x;
+       m[13] = y;
+       m[14] = z;
+}
+
+static inline void cgm_mscaling(float *m, float sx, float sy, float sz)
+{
+       cgm_mzero(m);
+       m[0] = sx;
+       m[5] = sy;
+       m[10] = sz;
+       m[15] = 1.0f;
+}
+
+static inline void cgm_mrotation_x(float *m, float angle)
+{
+       float sa = sin(angle);
+       float ca = cos(angle);
+
+       cgm_midentity(m);
+       m[5] = ca;
+       m[6] = sa;
+       m[9] = -sa;
+       m[10] = ca;
+}
+
+static inline void cgm_mrotation_y(float *m, float angle)
+{
+       float sa = sin(angle);
+       float ca = cos(angle);
+
+       cgm_midentity(m);
+       m[0] = ca;
+       m[2] = -sa;
+       m[8] = sa;
+       m[10] = ca;
+}
+
+static inline void cgm_mrotation_z(float *m, float angle)
+{
+       float sa = sin(angle);
+       float ca = cos(angle);
+
+       cgm_midentity(m);
+       m[0] = ca;
+       m[1] = sa;
+       m[4] = -sa;
+       m[5] = ca;
+}
+
+static inline void cgm_mrotation_axis(float *m, int idx, float angle)
+{
+       switch(idx) {
+       case 0:
+               cgm_mrotation_x(m, angle);
+               break;
+       case 1:
+               cgm_mrotation_y(m, angle);
+               break;
+       case 2:
+               cgm_mrotation_z(m, angle);
+               break;
+       }
+}
+
+static inline void cgm_mrotation(float *m, float angle, float x, float y, float z)
+{
+       float sa = sin(angle);
+       float ca = cos(angle);
+       float invca = 1.0f - ca;
+       float xsq = x * x;
+       float ysq = y * y;
+       float zsq = z * z;
+
+       cgm_mzero(m);
+       m[15] = 1.0f;
+
+       m[0] = xsq + (1.0f - xsq) * ca;
+       m[4] = x * y * invca - z * sa;
+       m[8] = x * z * invca + y * sa;
+
+       m[1] = x * y * invca + z * sa;
+       m[5] = ysq + (1.0f - ysq) * ca;
+       m[9] = y * z * invca - x * sa;
+
+       m[2] = x * z * invca - y * sa;
+       m[6] = y * z * invca + x * sa;
+       m[10] = zsq + (1.0f - zsq) * ca;
+}
+
+static inline void cgm_mrotation_euler(float *m, float a, float b, float c, int mode)
+{
+       /* this array must match the EulerMode enum */
+       static const int axis[][3] = {
+               {0, 1, 2}, {0, 2, 1},
+               {1, 0, 2}, {1, 2, 0},
+               {2, 0, 1}, {2, 1, 0},
+               {2, 0, 2}, {2, 1, 2},
+               {1, 0, 1}, {1, 2, 1},
+               {0, 1, 0}, {0, 2, 0}
+       };
+
+       float ma[16], mb[16];
+       cgm_mrotation_axis(ma, axis[mode][0], a);
+       cgm_mrotation_axis(mb, axis[mode][1], b);
+       cgm_mrotation_axis(m, axis[mode][2], c);
+       cgm_mmul(m, mb);
+       cgm_mmul(m, ma);
+}
+
+static inline void cgm_mrotation_quat(float *m, const cgm_quat *q)
+{
+       float xsq2 = 2.0f * q->x * 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 (file)
index 0000000..6cfa37d
--- /dev/null
@@ -0,0 +1,154 @@
+/* gph-cmath - C graphics math library
+ * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * 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 <stdlib.h>
+
+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 (file)
index 0000000..4b29fd2
--- /dev/null
@@ -0,0 +1,159 @@
+/* gph-cmath - C graphics math library
+ * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * 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 (file)
index 0000000..063a7e0
--- /dev/null
@@ -0,0 +1,39 @@
+/* gph-cmath - C graphics math library
+ * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * 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 (file)
index 0000000..88211c4
--- /dev/null
@@ -0,0 +1,188 @@
+/* gph-cmath - C graphics math library
+ * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * 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 (file)
index 0000000..1c143c2
--- /dev/null
@@ -0,0 +1,153 @@
+/* gph-cmath - C graphics math library
+ * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * 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 (file)
index f8f776b..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/* gph-cmath - C graphics math library
- * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
- *
- * 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 <math.h>
-#include <string.h>
-
-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 (file)
index 62edc8b..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-/* gph-cmath - C graphics math library
- * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
- *
- * 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; j<i; j++) {
-                       int a = i * 4 + j;
-                       int b = j * 4 + i;
-                       float tmp = m[a];
-                       m[a] = m[b];
-                       m[b] = tmp;
-               }
-       }
-}
-
-static inline void cgm_mcofmatrix(float *m)
-{
-       float tmp[16];
-       int i, j;
-
-       cgm_mcopy(tmp, m);
-
-       for(i=0; i<4; i++) {
-               for(j=0; j<4; j++) {
-                       m[i * 4 + j] = cgm_mcofactor(tmp, i, j);
-               }
-       }
-}
-
-static inline int cgm_minverse(float *m)
-{
-       int i, j;
-       float tmp[16];
-       float inv_det;
-       float det = cgm_mdet(m);
-       if(det == 0.0f) return -1;
-       inv_det = 1.0f / det;
-
-       cgm_mcopy(tmp, m);
-
-       for(i=0; i<4; i++) {
-               for(j=0; j<4; j++) {
-                       m[i * 4 + j] = cgm_mcofactor(tmp, j, i) * inv_det;      /* transposed */
-               }
-       }
-       return 0;
-}
-
-static inline void cgm_mtranslation(float *m, float x, float y, float z)
-{
-       cgm_midentity(m);
-       m[12] = x;
-       m[13] = y;
-       m[14] = z;
-}
-
-static inline void cgm_mscaling(float *m, float sx, float sy, float sz)
-{
-       cgm_mzero(m);
-       m[0] = sx;
-       m[5] = sy;
-       m[10] = sz;
-       m[15] = 1.0f;
-}
-
-static inline void cgm_mrotation_x(float *m, float angle)
-{
-       float sa = sin(angle);
-       float ca = cos(angle);
-
-       cgm_midentity(m);
-       m[5] = ca;
-       m[6] = sa;
-       m[9] = -sa;
-       m[10] = ca;
-}
-
-static inline void cgm_mrotation_y(float *m, float angle)
-{
-       float sa = sin(angle);
-       float ca = cos(angle);
-
-       cgm_midentity(m);
-       m[0] = ca;
-       m[2] = -sa;
-       m[8] = sa;
-       m[10] = ca;
-}
-
-static inline void cgm_mrotation_z(float *m, float angle)
-{
-       float sa = sin(angle);
-       float ca = cos(angle);
-
-       cgm_midentity(m);
-       m[0] = ca;
-       m[1] = sa;
-       m[4] = -sa;
-       m[5] = ca;
-}
-
-static inline void cgm_mrotation_axis(float *m, int idx, float angle)
-{
-       switch(idx) {
-       case 0:
-               cgm_mrotation_x(m, angle);
-               break;
-       case 1:
-               cgm_mrotation_y(m, angle);
-               break;
-       case 2:
-               cgm_mrotation_z(m, angle);
-               break;
-       }
-}
-
-static inline void cgm_mrotation(float *m, float angle, float x, float y, float z)
-{
-       float sa = sin(angle);
-       float ca = cos(angle);
-       float invca = 1.0f - ca;
-       float xsq = x * x;
-       float ysq = y * y;
-       float zsq = z * z;
-
-       cgm_mzero(m);
-       m[15] = 1.0f;
-
-       m[0] = xsq + (1.0f - xsq) * ca;
-       m[4] = x * y * invca - z * sa;
-       m[8] = x * z * invca + y * sa;
-
-       m[1] = x * y * invca + z * sa;
-       m[5] = ysq + (1.0f - ysq) * ca;
-       m[9] = y * z * invca - x * sa;
-
-       m[2] = x * z * invca - y * sa;
-       m[6] = y * z * invca + x * sa;
-       m[10] = zsq + (1.0f - zsq) * ca;
-}
-
-static inline void cgm_mrotation_euler(float *m, float a, float b, float c, int mode)
-{
-       /* this array must match the EulerMode enum */
-       static const int axis[][3] = {
-               {0, 1, 2}, {0, 2, 1},
-               {1, 0, 2}, {1, 2, 0},
-               {2, 0, 1}, {2, 1, 0},
-               {2, 0, 2}, {2, 1, 2},
-               {1, 0, 1}, {1, 2, 1},
-               {0, 1, 0}, {0, 2, 0}
-       };
-
-       float ma[16], mb[16];
-       cgm_mrotation_axis(ma, axis[mode][0], a);
-       cgm_mrotation_axis(mb, axis[mode][1], b);
-       cgm_mrotation_axis(m, axis[mode][2], c);
-       cgm_mmul(m, mb);
-       cgm_mmul(m, ma);
-}
-
-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_mpretranslate(float *m, float x, float y, float z)
-{
-       float tmp[16];
-       cgm_mcopy(tmp, m);
-       cgm_mtranslation(m, x, y, z);
-       cgm_mmul(m, tmp);
-}
-
-static inline void cgm_mprescale(float *m, float sx, float sy, float sz)
-{
-       float tmp[16];
-       cgm_mcopy(tmp, m);
-       cgm_mscaling(m, sx, sy, sz);
-       cgm_mmul(m, tmp);
-}
-
-static inline void cgm_mprerotate_x(float *m, float angle)
-{
-       float tmp[16];
-       cgm_mcopy(tmp, m);
-       cgm_mrotation_x(m, angle);
-       cgm_mmul(m, tmp);
-}
-
-static inline void cgm_mprerotate_y(float *m, float angle)
-{
-       float tmp[16];
-       cgm_mcopy(tmp, m);
-       cgm_mrotation_y(m, angle);
-       cgm_mmul(m, tmp);
-}
-
-static inline void cgm_mprerotate_z(float *m, float angle)
-{
-       float tmp[16];
-       cgm_mcopy(tmp, m);
-       cgm_mrotation_z(m, angle);
-       cgm_mmul(m, tmp);
-}
-
-static inline void cgm_mprerotate_axis(float *m, int idx, float angle)
-{
-       float tmp[16];
-       cgm_mcopy(tmp, m);
-       cgm_mrotation_axis(m, idx, angle);
-       cgm_mmul(m, tmp);
-}
-
-static inline void cgm_mprerotate(float *m, float angle, float x, float y, float z)
-{
-       float tmp[16];
-       cgm_mcopy(tmp, m);
-       cgm_mrotation(m, angle, x, y, z);
-       cgm_mmul(m, tmp);
-}
-
-static inline void cgm_mprerotate_euler(float *m, float a, float b, float c, int mode)
-{
-       float tmp[16];
-       cgm_mcopy(tmp, m);
-       cgm_mrotation_euler(m, a, b, c, mode);
-       cgm_mmul(m, tmp);
-}
-
-
-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/src/cgmath/cgmmisc.inl b/src/cgmath/cgmmisc.inl
deleted file mode 100644 (file)
index 6cfa37d..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/* gph-cmath - C graphics math library
- * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
- *
- * 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 <stdlib.h>
-
-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 (file)
index 4b29fd2..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/* gph-cmath - C graphics math library
- * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
- *
- * 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 (file)
index 063a7e0..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* gph-cmath - C graphics math library
- * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
- *
- * 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 (file)
index 88211c4..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* gph-cmath - C graphics math library
- * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
- *
- * 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 (file)
index 1c143c2..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/* gph-cmath - C graphics math library
- * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
- *
- * 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;
-}