first render
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 3 Apr 2024 07:43:52 +0000 (10:43 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 3 Apr 2024 07:43:52 +0000 (10:43 +0300)
14 files changed:
Makefile
src/cgmath2/cgmath2.h
src/cgmath2/cgmmat.inl [new file with mode: 0644]
src/cgmath2/cgmmisc.inl [new file with mode: 0644]
src/cgmath2/cgmquat.inl [new file with mode: 0644]
src/cgmath2/cgmvec3.inl
src/cgmath2/cgmvec4.inl [new file with mode: 0644]
src/gfx.h
src/gl/gfx_gl.c
src/nexus3d.h
src/wsys/wsys_fglut.c
test.c
test.p.glsl
test.v.glsl

index 203d578..72340f8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ LDFLAGS = -lGL -lglut -lGLEW -lm
 GLSLANG = glslangValidator
 
 
-test: test.o $(liba)
+test: test.o $(liba) $(spirv)
        $(CC) -o $@ test.o $(obj) $(liba) $(LDFLAGS)
 
 $(liba): $(obj)
index 0e34f38..ea6be7a 100644 (file)
@@ -4,7 +4,10 @@
 #include <math.h>
 #include <string.h>
 
-#define CGM_PI 3.141592653589793
+#define CGM_PI 3.141592653589793f
+#define CGM_HPI        (CGM_PI / 2.0f)
+#define CGM_QPI        (CGM_PI / 4.0f)
+#define CGM_2PI        (CGM_PI * 2.0f)
 
 typedef struct {
        float x, y;
@@ -71,7 +74,7 @@ static CGM_INLINE float cgm_vlength_sq(cgm_vec3 v);
 static CGM_INLINE float cgm_vdist(cgm_vec3 a, cgm_vec3 b);
 static CGM_INLINE float cgm_vdist_sq(cgm_vec3 a, cgm_vec3 b);
 
-static CGM_INLINE cgm_vec3 cgm_normalize(cgm_vec3 v);
+static CGM_INLINE cgm_vec3 cgm_vnormalize(cgm_vec3 v);
 
 static CGM_INLINE cgm_vec3 cgm_vreflect(cgm_vec3 v, cgm_vec3 n);
 static CGM_INLINE cgm_vec3 cgm_vrefract(cgm_vec3 v, cgm_vec3 n, float ior);
@@ -86,6 +89,53 @@ static CGM_INLINE cgm_vec3 cgm_vblend(cgm_vec3 a, float fa, cgm_vec3 b, float fb
 
 #define cgm_velem(v, idx)      ((&(v).x)[idx])
 
+/* --- operations on cgm_vec4 --- */
+static CGM_INLINE cgm_vec4 cgm_wcons(float x, float y, float z, float w);
+
+static CGM_INLINE cgm_vec4 cgm_wadd(cgm_vec4 a, cgm_vec4 b);
+static CGM_INLINE cgm_vec4 cgm_wsub(cgm_vec4 a, cgm_vec4 b);
+static CGM_INLINE cgm_vec4 cgm_wmul(cgm_vec4 a, cgm_vec4 b);
+static CGM_INLINE cgm_vec4 cgm_wscale(cgm_vec4 v, float s);
+
+static CGM_INLINE cgm_vec4 cgm_wmul_m4v4(const float *m, cgm_vec4 v);
+static CGM_INLINE cgm_vec4 cgm_wmul_v4m4(cgm_vec4 v, const float *m);
+static CGM_INLINE cgm_vec4 cgm_wmul_m34v4(const float *m, cgm_vec4 v); /* doesn't affect w */
+static CGM_INLINE cgm_vec4 cgm_wmul_v4m34(cgm_vec4 v, const float *m); /* doesn't affect w */
+static CGM_INLINE cgm_vec4 cgm_wmul_m3v4(const float *m, cgm_vec4 v); /* (m still 16 floats) */
+static CGM_INLINE cgm_vec4 cgm_wmul_v4m3(cgm_vec4 v, const float *m); /* (m still 16 floats) */
+
+static CGM_INLINE float cgm_wdot(cgm_vec4 a, cgm_vec4 b);
+
+static CGM_INLINE float cgm_wlength(cgm_vec4 v);
+static CGM_INLINE float cgm_wlength_sq(cgm_vec4 v);
+static CGM_INLINE float cgm_wdist(cgm_vec4 a, cgm_vec4 b);
+static CGM_INLINE float cgm_wdist_sq(cgm_vec4 a, cgm_vec4 b);
+static CGM_INLINE cgm_vec4 cgm_wnormalize(cgm_vec4 v);
+
+static CGM_INLINE cgm_vec4 cgm_wlerp(cgm_vec4 a, cgm_vec4 b, float t);
+
+#define cgm_welem(v, idx)      ((&(v).x)[idx])
+
+/* --- operations on quaternions --- */
+static CGM_INLINE cgm_quat cgm_qcons(float x, float y, float z, float w);
+
+static CGM_INLINE cgm_quat cgm_qneg(cgm_quat q);
+static CGM_INLINE cgm_quat cgm_qadd(cgm_quat a, cgm_quat b);
+static CGM_INLINE cgm_quat cgm_qsub(cgm_quat a, cgm_quat b);
+static CGM_INLINE cgm_quat cgm_qmul(cgm_quat a, cgm_quat b);
+
+static CGM_INLINE float cgm_qlength(cgm_quat q);
+static CGM_INLINE float cgm_qlength_sq(cgm_quat q);
+static CGM_INLINE cgm_quat cgm_qnormalize(cgm_quat q);
+static CGM_INLINE cgm_quat cgm_qconjugate(cgm_quat q);
+static CGM_INLINE cgm_quat cgm_qinvert(cgm_quat q);
+
+static CGM_INLINE cgm_quat cgm_qrotation(float angle, float x, float y, float z);
+static CGM_INLINE void cgm_qrotate(cgm_quat *q, float angle, float x, float y, float z);
+
+static CGM_INLINE cgm_quat cgm_qslerp(cgm_quat a, cgm_quat b, float t);
+static CGM_INLINE cgm_quat cgm_qlerp(cgm_quat a, cgm_quat b, float t);
+
 /* --- operations on matrices --- */
 static CGM_INLINE void cgm_mcopy(float *dest, const float *src);
 static CGM_INLINE void cgm_mzero(float *m);
@@ -182,8 +232,8 @@ static CGM_INLINE cgm_vec3 cgm_uvec_to_sph(cgm_vec3 v);
 static CGM_INLINE cgm_vec3 cgm_sph_to_uvec(float theta, float phi);
 
 #include "cgmvec3.inl"
-/*#include "cgmvec4.inl"
-#include "cgmquat.inl"*/
+#include "cgmvec4.inl"
+#include "cgmquat.inl"
 #include "cgmmat.inl"
 /*#include "cgmray.inl"*/
 #include "cgmmisc.inl"
diff --git a/src/cgmath2/cgmmat.inl b/src/cgmath2/cgmmat.inl
new file mode 100644 (file)
index 0000000..952cfed
--- /dev/null
@@ -0,0 +1,668 @@
+static CGM_INLINE void cgm_mcopy(float *dest, const float *src)
+{
+       memcpy(dest, src, 16 * sizeof(float));
+}
+
+static CGM_INLINE void cgm_mzero(float *m)
+{
+       static float z[16];
+       cgm_mcopy(m, z);
+}
+
+static CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_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 CGM_INLINE void cgm_mrotation_quat(float *m, 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 CGM_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 CGM_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 CGM_INLINE void cgm_mrotate_x(float *m, float angle)
+{
+       float rm[16];
+       cgm_mrotation_x(rm, angle);
+       cgm_mmul(m, rm);
+}
+
+static CGM_INLINE void cgm_mrotate_y(float *m, float angle)
+{
+       float rm[16];
+       cgm_mrotation_y(rm, angle);
+       cgm_mmul(m, rm);
+}
+
+static CGM_INLINE void cgm_mrotate_z(float *m, float angle)
+{
+       float rm[16];
+       cgm_mrotation_z(rm, angle);
+       cgm_mmul(m, rm);
+}
+
+static CGM_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 CGM_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 CGM_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 CGM_INLINE void cgm_mrotate_quat(float *m, cgm_quat q)
+{
+       float rm[16];
+       cgm_mrotation_quat(rm, q);
+       cgm_mmul(m, rm);
+}
+
+
+static CGM_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 CGM_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 CGM_INLINE void cgm_mprerotate_x(float *m, float angle)
+{
+       float rm[16];
+       cgm_mrotation_x(rm, angle);
+       cgm_mpremul(m, rm);
+}
+
+static CGM_INLINE void cgm_mprerotate_y(float *m, float angle)
+{
+       float rm[16];
+       cgm_mrotation_y(rm, angle);
+       cgm_mpremul(m, rm);
+}
+
+static CGM_INLINE void cgm_mprerotate_z(float *m, float angle)
+{
+       float rm[16];
+       cgm_mrotation_z(rm, angle);
+       cgm_mpremul(m, rm);
+}
+
+static CGM_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 CGM_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 CGM_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 CGM_INLINE void cgm_mprerotate_quat(float *m, const cgm_quat q)
+{
+       float rm[16];
+       cgm_mrotation_quat(rm, q);
+       cgm_mpremul(m, rm);
+}
+
+
+static CGM_INLINE cgm_vec3 cgm_mget_translation(const float *m)
+{
+       cgm_vec3 res;
+       res.x = m[12];
+       res.y = m[13];
+       res.z = m[14];
+       return res;
+}
+
+/* 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 CGM_INLINE cgm_quat cgm_mget_rotation(const float *m)
+{
+       static const int next[3] = {1, 2, 0};
+       cgm_quat res;
+       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];
+       }
+
+       return res;
+}
+
+static CGM_INLINE cgm_vec3 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]);
+       return res;
+}
+
+static CGM_INLINE cgm_vec4 cgm_mget_frustum_plane(const float *m, int p)
+{
+       cgm_vec4 res;
+
+       switch(p) {
+       case 0:
+               res.x = m[3] + m[0];
+               res.y = m[7] + m[4];
+               res.z = m[11] + m[8];
+               res.w = m[15] + m[12];
+               break;
+
+       case 1:
+               res.x = m[3] - m[0];
+               res.y = m[7] - m[4];
+               res.z = m[11] - m[8];
+               res.w = m[15] - m[12];
+               break;
+
+       case 2:
+               res.x = m[3] + m[1];
+               res.y = m[7] + m[5];
+               res.z = m[11] + m[9];
+               res.w = m[15] + m[13];
+               break;
+
+       case 3:
+               res.x = m[3] - m[1];
+               res.y = m[7] - m[5];
+               res.z = m[11] - m[9];
+               res.w = m[15] - m[13];
+               break;
+
+       case 4:
+               res.x = m[3] + m[2];
+               res.y = m[7] + m[6];
+               res.z = m[11] + m[10];
+               res.w = m[15] + m[14];
+               break;
+
+       case 5:
+               res.x = m[3] - m[2];
+               res.y = m[7] - m[6];
+               res.z = m[11] - m[10];
+               res.w = m[15] - m[14];
+               break;
+
+       default:
+               res.x = res.y = res.z = res.w = 0.0f;
+               break;
+       }
+
+       return res;
+}
+
+static CGM_INLINE cgm_vec4 cgm_normalize_plane(cgm_vec4 p)
+{
+       cgm_vec4 res;
+       float len, s;
+
+       len = cgm_vlength(cgm_vcons(p.x, p.y, p.z));
+       if(len == 0.0f) {
+               return p;
+       }
+       s = 1.0f / len;
+       res.x = p.x * s;
+       res.y = p.y * s;
+       res.z = p.z * s;
+       res.w = p.w * s;
+       return res;
+}
+
+static CGM_INLINE void cgm_mlookat(float *m, cgm_vec3 pos, cgm_vec3 targ, cgm_vec3 up)
+{
+       float trans[16];
+       cgm_vec3 dir, right, vup;
+
+       dir = cgm_vnormalize(cgm_vsub(targ, pos));
+       right = cgm_vnormalize(cgm_vcross(dir, up));
+       vup = cgm_vnormalize(cgm_vcross(right, dir));
+
+       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 CGM_INLINE void cgm_minv_lookat(float *m, cgm_vec3 pos, cgm_vec3 targ, cgm_vec3 up)
+{
+       float rot[16];
+       cgm_vec3 dir, right, vup;
+
+       dir = cgm_vnormalize(cgm_vsub(targ, pos));
+       right = cgm_vnormalize(cgm_vcross(dir, up));
+       vup = cgm_vnormalize(cgm_vcross(right, dir));
+
+       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 CGM_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 CGM_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 CGM_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 CGM_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/cgmath2/cgmmisc.inl b/src/cgmath2/cgmmisc.inl
new file mode 100644 (file)
index 0000000..21d34c4
--- /dev/null
@@ -0,0 +1,213 @@
+/* gph-cmath - C graphics math library
+ * Copyright (C) 2018-2023 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 CGM_INLINE float cgm_deg_to_rad(float deg)
+{
+       return M_PI * deg / 180.0f;
+}
+
+static CGM_INLINE float cgm_rad_to_deg(float rad)
+{
+       return 180.0f * rad / M_PI;
+}
+
+static CGM_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 CGM_INLINE float cgm_lerp(float a, float b, float t)
+{
+       return a + (b - a) * t;
+}
+
+static CGM_INLINE float cgm_logerp(float a, float b, float t)
+{
+       if(a == 0.0f) return 0.0f;
+       return a * pow(b / a, t);
+}
+
+static CGM_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 CGM_INLINE float cgm_bspline(float a, float b, float c, float d, float t)
+{
+       static const float mat[] = {
+               -1, 3, -3, 1,
+               3, -6, 0, 4,
+               -3, 3, 3, 1,
+               1, 0, 0, 0
+       };
+       float tsq = t * t;
+       cgm_vec4 tmp = cgm_wmul_m4v4(mat, cgm_wcons(a, b, c, d));
+       return cgm_wdot(cgm_wscale(tmp, 1.0f / 6.0f), cgm_wcons(tsq * t, tsq, t, 1.0f));
+}
+
+static CGM_INLINE float cgm_spline(float a, float b, float c, float d, float t)
+{
+       static const float mat[] = {
+               -1, 2, -1, 0,
+               3, -5, 0, 2,
+               -3, 4, 1, 0,
+               1, -1, 0, 0
+       };
+       float tsq = t * t;
+       cgm_vec4 tmp = cgm_wmul_m4v4(mat, cgm_wcons(a, b, c, d));
+       return cgm_wdot(cgm_wscale(tmp, 1.0f / 6.0f), cgm_wcons(tsq * t, tsq, t, 1.0f));
+}
+
+static CGM_INLINE cgm_vec3 cgm_discrand(float rad)
+{
+       cgm_vec3 res;
+       float theta = 2.0f * M_PI * (float)rand() / RAND_MAX;
+       float r = sqrt((float)rand() / RAND_MAX) * rad;
+       res.x = cos(theta) * r;
+       res.y = sin(theta) * r;
+       res.z = 0.0f;
+       return res;
+}
+
+static CGM_INLINE cgm_vec3 cgm_sphrand(float rad)
+{
+       cgm_vec3 res;
+       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);
+
+       res.x = cos(theta) * sin(phi) * rad;
+       res.y = sin(theta) * sin(phi) * rad;
+       res.z = cos(phi) * rad;
+       return res;
+}
+
+static CGM_INLINE cgm_vec3 cgm_unproject(cgm_vec3 norm_scrpos, const float *inv_viewproj)
+{
+       cgm_vec3 res;
+       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(inv_viewproj, pos);
+
+       res.x = pos.x / pos.w;
+       res.y = pos.y / pos.w;
+       res.z = pos.z / pos.w;
+       return res;
+}
+
+static CGM_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, view);
+       cgm_mmul(inv_pv, proj);
+       cgm_minverse(inv_pv);
+
+       npos.x = (winx - vp[0]) / vp[2];
+       npos.y = (winy - vp[1]) / vp[4];
+       npos.z = winz;
+
+       res = cgm_unproject(npos, inv_pv);
+
+       *objx = res.x;
+       *objy = res.y;
+       *objz = res.z;
+}
+
+static CGM_INLINE cgm_ray cgm_pick_ray(float nx, float ny, const float *viewmat,
+               const float *projmat)
+{
+       cgm_ray ray;
+       cgm_vec3 farpt;
+       float inv_pv[16];
+
+       cgm_mcopy(inv_pv, viewmat);
+       cgm_mmul(inv_pv, projmat);
+       cgm_minverse(inv_pv);
+
+       ray.origin = cgm_unproject(cgm_vcons(nx, ny, 0.0f), inv_pv);
+       farpt = cgm_unproject(cgm_vcons(nx, ny, 1.0f), 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;
+       return ray;
+}
+
+static CGM_INLINE cgm_vec3 cgm_raypos(cgm_ray ray, float t)
+{
+       cgm_vec3 res;
+       res.x = ray.origin.x + ray.dir.x * t;
+       res.y = ray.origin.y + ray.dir.y * t;
+       res.z = ray.origin.z + ray.dir.z * t;
+       return res;
+}
+
+static CGM_INLINE cgm_vec3 cgm_bary(cgm_vec3 a, cgm_vec3 b, cgm_vec3 c, cgm_vec3 pt)
+{
+       float d00, d01, d11, d20, d21, denom;
+       cgm_vec3 res, v0, v1, v2;
+
+       v0 = cgm_vsub(b, a);
+       v1 = cgm_vsub(c, a);
+       v2 = cgm_vsub(pt, 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;
+
+       res.y = (d11 * d20 - d01 * d21) / denom;
+       res.z = (d00 * d21 - d01 * d20) / denom;
+       res.x = 1.0f - res.y - res.z;
+       return res;
+}
+
+static CGM_INLINE cgm_vec3 cgm_uvec_to_sph(cgm_vec3 v)
+{
+       cgm_vec3 res;
+       res.x = atan2(v.z, v.x);
+       res.y = acos(v.y);
+       res.z = 1.0f;
+       return res;
+}
+
+static CGM_INLINE cgm_vec3 cgm_sph_to_uvec(float theta, float phi)
+{
+       cgm_vec3 res;
+       res.x = sin(theta) * cos(phi);
+       res.y = sin(phi);
+       res.z = cos(theta) * cos(phi);
+       return res;
+}
diff --git a/src/cgmath2/cgmquat.inl b/src/cgmath2/cgmquat.inl
new file mode 100644 (file)
index 0000000..e238006
--- /dev/null
@@ -0,0 +1,151 @@
+static CGM_INLINE cgm_quat cgm_qcons(float x, float y, float z, float w)
+{
+       cgm_quat q;
+       q.x = x;
+       q.y = y;
+       q.z = z;
+       q.w = w;
+       return q;
+}
+
+static CGM_INLINE cgm_quat cgm_qneg(cgm_quat q)
+{
+       return cgm_qcons(-q.x, -q.y, -q.z, -q.w);
+}
+
+static CGM_INLINE cgm_quat cgm_qadd(cgm_quat a, cgm_quat b)
+{
+       return cgm_qcons(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+}
+
+static CGM_INLINE cgm_quat cgm_qsub(cgm_quat a, cgm_quat b)
+{
+       return cgm_qcons(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
+}
+
+static CGM_INLINE cgm_quat cgm_qmul(cgm_quat a, cgm_quat b)
+{
+       cgm_quat res;
+       float dot;
+       cgm_vec3 cross;
+
+       dot = a.x * b.x + a.y * b.y + a.z * b.z;
+       cross = cgm_vcross(cgm_vcons(a.x, a.y, a.z), cgm_vcons(b.x, b.y, b.z));
+       res.x = a.w * b.x + b.w * a.x + cross.x;
+       res.y = a.w * b.y + b.w * a.y + cross.y;
+       res.z = a.w * b.z + b.w * a.z + cross.z;
+       res.w = a.w * b.w - dot;
+       return res;
+}
+
+static CGM_INLINE float cgm_qlength(cgm_quat q)
+{
+       return sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
+}
+
+static CGM_INLINE float cgm_qlength_sq(cgm_quat q)
+{
+       return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
+}
+
+static CGM_INLINE cgm_quat cgm_qnormalize(cgm_quat q)
+{
+       cgm_quat res;
+       float len, s;
+
+       len = cgm_qlength(q);
+       if(len == 0.0f) {
+               return q;
+       }
+       s = 1.0f / len;
+       res.x = q.x * s;
+       res.y = q.y * s;
+       res.z = q.z * s;
+       res.w = q.w * s;
+       return res;
+}
+
+static CGM_INLINE cgm_quat cgm_qconjugate(cgm_quat q)
+{
+       return cgm_qcons(-q.x, -q.y, -q.z, q.w);
+}
+
+static CGM_INLINE cgm_quat cgm_qinvert(cgm_quat q)
+{
+       cgm_quat res;
+       float len_sq, s;
+
+       if((len_sq = cgm_qlength_sq(q)) == 0.0f) {
+               return q;
+       }
+       s = 1.0f / len_sq;
+       res.x = -q.x * s;
+       res.y = -q.y * s;
+       res.z = -q.z * s;
+       res.w = q.w * s;
+       return res;
+}
+
+static CGM_INLINE cgm_quat cgm_qrotation(float angle, float x, float y, float z)
+{
+       cgm_quat res;
+       float hangle = angle * 0.5f;
+       float sin_ha = sin(hangle);
+       res.w = cos(hangle);
+       res.x = x * sin_ha;
+       res.y = y * sin_ha;
+       res.z = z * sin_ha;
+       return res;
+}
+
+static CGM_INLINE void cgm_qrotate(cgm_quat *q, float angle, float x, float y, float z)
+{
+       cgm_quat qrot = cgm_qrotation(angle, x, y, z);
+       *q = cgm_qmul(*q, qrot);
+}
+
+static CGM_INLINE cgm_quat cgm_qslerp(cgm_quat q1, cgm_quat q2, float t)
+{
+       cgm_quat res;
+       float angle, dot, a, b, sin_angle;
+
+       dot = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
+       if(dot < 0.0f) {
+               /* make sure we inteprolate across the shortest arc */
+               q1 = 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;
+       return res;
+}
+
+static CGM_INLINE cgm_quat cgm_qlerp(cgm_quat a, cgm_quat b, float t)
+{
+       cgm_quat res;
+       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;
+       return res;
+}
index d6a50f2..c6b6675 100644 (file)
@@ -24,7 +24,7 @@ static CGM_INLINE cgm_vec3 cgm_vmul(cgm_vec3 a, cgm_vec3 b)
 
 static CGM_INLINE cgm_vec3 cgm_vscale(cgm_vec3 v, float s)
 {
-       return cgm_vcons(a.x * s, a.y * s, a.z * s);
+       return cgm_vcons(v.x * s, v.y * s, v.z * s);
 }
 
 
@@ -106,7 +106,7 @@ static CGM_INLINE float cgm_vdist_sq(cgm_vec3 a, cgm_vec3 b)
 }
 
 
-static CGM_INLINE cgm_vec3 cgm_normalize(cgm_vec3 v)
+static CGM_INLINE cgm_vec3 cgm_vnormalize(cgm_vec3 v)
 {
        cgm_vec3 res;
        float len = cgm_vlength(v);
@@ -149,7 +149,7 @@ static CGM_INLINE cgm_vec3 cgm_vrotate_quat(cgm_vec3 v, cgm_quat q)
 {
        cgm_quat vq, inv_q, tmp_q;
 
-       vq = cgm_qcons(v->x, v->y, v->z, 0.0f);
+       vq = cgm_qcons(v.x, v.y, v.z, 0.0f);
        inv_q = cgm_qinvert(q);
        tmp_q = cgm_qmul(q, vq);
        tmp_q = cgm_qmul(tmp_q, inv_q);
@@ -160,21 +160,21 @@ static CGM_INLINE cgm_vec3 cgm_vrotate_axis(cgm_vec3 v, int axis, float angle)
 {
        float m[16];
        cgm_mrotation_axis(m, axis, angle);
-       cgm_vmul_m3v3(v, m);
+       return cgm_vmul_m3v3(m, v);
 }
 
 static CGM_INLINE cgm_vec3 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);
+       return cgm_vmul_m3v3(m, v);
 }
 
 static CGM_INLINE cgm_vec3 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);
+       return cgm_vmul_m3v3(m, v);
 }
 
 
diff --git a/src/cgmath2/cgmvec4.inl b/src/cgmath2/cgmvec4.inl
new file mode 100644 (file)
index 0000000..307fbd5
--- /dev/null
@@ -0,0 +1,151 @@
+/* --- operations on cgm_vec4 --- */
+static CGM_INLINE cgm_vec4 cgm_wcons(float x, float y, float z, float w)
+{
+       cgm_vec4 res;
+       res.x = x;
+       res.y = y;
+       res.z = z;
+       res.w = w;
+       return res;
+}
+
+
+static CGM_INLINE cgm_vec4 cgm_wadd(cgm_vec4 a, cgm_vec4 b)
+{
+       return cgm_wcons(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+}
+
+static CGM_INLINE cgm_vec4 cgm_wsub(cgm_vec4 a, cgm_vec4 b)
+{
+       return cgm_wcons(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
+}
+
+static CGM_INLINE cgm_vec4 cgm_wmul(cgm_vec4 a, cgm_vec4 b)
+{
+       return cgm_wcons(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
+}
+
+static CGM_INLINE cgm_vec4 cgm_wscale(cgm_vec4 v, float s)
+{
+       return cgm_wcons(v.x * s, v.y * s, v.z * s, v.w * s);
+}
+
+
+static CGM_INLINE cgm_vec4 cgm_wmul_m4v4(const float *m, cgm_vec4 v)
+{
+       cgm_vec4 res;
+       res.x = v.x * m[0] + v.y * m[4] + v.z * m[8] + v.w * m[12];
+       res.y = v.x * m[1] + v.y * m[5] + v.z * m[9] + v.w * m[13];
+       res.z = v.x * m[2] + v.y * m[6] + v.z * m[10] + v.w * m[14];
+       res.w = v.x * m[3] + v.y * m[7] + v.z * m[11] + v.w * m[15];
+       return res;
+}
+
+static CGM_INLINE cgm_vec4 cgm_wmul_v4m4(cgm_vec4 v, const float *m)
+{
+       cgm_vec4 res;
+       res.x = v.x * m[0] + v.y * m[1] + v.z * m[2] + v.w * m[3];
+       res.y = v.x * m[4] + v.y * m[5] + v.z * m[6] + v.w * m[7];
+       res.z = v.x * m[8] + v.y * m[9] + v.z * m[10] + v.w * m[11];
+       res.w = v.x * m[12] + v.y * m[13] + v.z * m[14] + v.w * m[15];
+       return res;
+}
+
+static CGM_INLINE cgm_vec4 cgm_wmul_m34v4(const float *m, cgm_vec4 v)
+{
+       cgm_vec4 res;
+       res.x = v.x * m[0] + v.y * m[4] + v.z * m[8] + v.w * m[12];
+       res.y = v.x * m[1] + v.y * m[5] + v.z * m[9] + v.w * m[13];
+       res.z = v.x * m[2] + v.y * m[6] + v.z * m[10] + v.w * m[14];
+       res.w = v.w;
+       return res;
+}
+
+static CGM_INLINE cgm_vec4 cgm_wmul_v4m34(cgm_vec4 v, const float *m)
+{
+       cgm_vec4 res;
+       res.x = v.x * m[0] + v.y * m[1] + v.z * m[2] + v.w * m[3];
+       res.y = v.x * m[4] + v.y * m[5] + v.z * m[6] + v.w * m[7];
+       res.z = v.x * m[8] + v.y * m[9] + v.z * m[10] + v.w * m[11];
+       return res;
+}
+
+static CGM_INLINE cgm_vec4 cgm_wmul_m3v4(const float *m, cgm_vec4 v)
+{
+       cgm_vec4 res;
+       res.x = v.x * m[0] + v.y * m[4] + v.z * m[8];
+       res.y = v.x * m[1] + v.y * m[5] + v.z * m[9];
+       res.z = v.x * m[2] + v.y * m[6] + v.z * m[10];
+       return res;
+}
+
+static CGM_INLINE cgm_vec4 cgm_wmul_v4m3(cgm_vec4 v, const float *m)
+{
+       cgm_vec4 res;
+       res.x = v.x * m[0] + v.y * m[1] + v.z * m[2];
+       res.y = v.x * m[4] + v.y * m[5] + v.z * m[6];
+       res.z = v.x * m[8] + v.y * m[9] + v.z * m[10];
+       return res;
+}
+
+
+static CGM_INLINE float cgm_wdot(cgm_vec4 a, cgm_vec4 b)
+{
+       return a.x * b.x + a.y * b.y + a.z * b.z + a.w + b.w;
+}
+
+
+static CGM_INLINE float cgm_wlength(cgm_vec4 v)
+{
+       return sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
+}
+
+static CGM_INLINE float cgm_wlength_sq(cgm_vec4 v)
+{
+       return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;
+}
+
+static CGM_INLINE float cgm_wdist(cgm_vec4 a, 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 CGM_INLINE float cgm_wdist_sq(cgm_vec4 a, 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 CGM_INLINE cgm_vec4 cgm_wnormalize(cgm_vec4 v)
+{
+       cgm_vec4 res;
+       float len, s;
+       len = cgm_wlength(v);
+       if(len == 0.0f) {
+               return v;
+       }
+       s = 1.0f / len;
+       res.x = v.x * s;
+       res.y = v.y * s;
+       res.z = v.z * s;
+       res.w = v.w * s;
+       return res;
+}
+
+
+static CGM_INLINE cgm_vec4 cgm_wlerp(cgm_vec4 a, cgm_vec4 b, float t)
+{
+       cgm_vec4 res;
+       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;
+       return res;
+}
index 5faf474..61eac33 100644 (file)
--- a/src/gfx.h
+++ b/src/gfx.h
@@ -3,10 +3,11 @@
 
 #include <stddef.h>
 
-enum nex_state_flags {
-       NEX_DEPTH_TEST          = 0x0001,
-       NEX_STENCIL_TEST        = 0x0002,
-       NEX_BLEND                       = 0x0004,
+enum nex_state_opt {
+       NEX_DEPTH_TEST,
+       NEX_STENCIL_TEST,
+       NEX_BLEND,
+       NEX_CULL_FACE
 };
 
 enum nex_vattr_type {
@@ -41,6 +42,10 @@ void nex_clearstencil(unsigned int s);
 
 void nex_viewport(int x, int y, int w, int h);
 
+void nex_enable(enum nex_state_opt opt);
+void nex_disable(enum nex_state_opt opt);
+int nex_is_enabled(enum nex_state_opt opt);
+
 /* --- buffers and geometry --- */
 nex_buffer *nex_alloc_buffer(size_t sz, const void *data);
 void nex_free_buffer(nex_buffer *buf);
@@ -74,6 +79,10 @@ void nex_attach_shader(nex_sdrprog *prog, nex_shader *sdr);
 int nex_build_sdrprog(nex_sdrprog *prog);
 void nex_bind_sdrprog(nex_sdrprog *prog);
 
+int nex_find_uniform(nex_sdrprog *prog, const char *name);
+void nex_uniform_mat4(nex_sdrprog *prog, int loc, const float *mat);
+void nex_uniform_mat4_name(nex_sdrprog *prog, const char *name, const float *mat);
+
 nex_shader *nex_load_shader(const char *path, enum nex_sdr_type type);
 nex_sdrprog *nex_load_sdrprog(const char *vpath, const char *ppath);
 
index c0a830d..a735f28 100644 (file)
@@ -7,6 +7,8 @@
 #include "nexus3d_impl.h"
 #include "gfx_gl.h"
 
+static unsigned int cur_state;
+
 void nex_clear(void)
 {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@@ -32,6 +34,46 @@ void nex_viewport(int x, int y, int w, int h)
        glViewport(x, y, w, h);
 }
 
+static unsigned int glstateopt(enum nex_state_opt opt)
+{
+       switch(opt) {
+       case NEX_DEPTH_TEST:
+               return GL_DEPTH_TEST;
+       case NEX_STENCIL_TEST:
+               return GL_STENCIL_TEST;
+       case NEX_BLEND:
+               return GL_BLEND;
+       case NEX_CULL_FACE:
+               return GL_CULL_FACE;
+       default:
+               break;
+       }
+       return 0;
+}
+
+void nex_enable(enum nex_state_opt opt)
+{
+       unsigned int glst = glstateopt(opt);
+       if(glst > 0) {
+               glEnable(glst);
+               cur_state |= (1 << opt);
+       }
+}
+
+void nex_disable(enum nex_state_opt opt)
+{
+       unsigned int glst = glstateopt(opt);
+       if(glst > 0) {
+               glDisable(glst);
+               cur_state &= ~(1 << opt);
+       }
+}
+
+int nex_is_enabled(enum nex_state_opt opt)
+{
+       return cur_state & (1 << opt) ? 1 : 0;
+}
+
 nex_buffer *nex_alloc_buffer(size_t sz, const void *data)
 {
        nex_buffer *buf;
@@ -351,6 +393,30 @@ int nex_build_sdrprog(nex_sdrprog *prog)
        return status ? 0 : -1;
 }
 
+void nex_bind_sdrprog(nex_sdrprog *prog)
+{
+       glUseProgram(prog->prog);
+}
+
+int nex_find_uniform(nex_sdrprog *prog, const char *name)
+{
+       return glGetUniformLocation(prog->prog, name);
+}
+
+void nex_uniform_mat4(nex_sdrprog *prog, int loc, const float *mat)
+{
+       if(loc < 0) return;
+       glProgramUniformMatrix4fv(prog->prog, loc, 1, 0, mat);
+}
+
+void nex_uniform_mat4_name(nex_sdrprog *prog, const char *name, const float *mat)
+{
+       int loc = glGetUniformLocation(prog->prog, name);
+       if(loc >= 0) {
+               glProgramUniformMatrix4fv(prog->prog, loc, 1, 0, mat);
+       }
+}
+
 #define SPIRV_MAGIC            0x07230203
 #define SPIRV_CIGAM            0x03022307
 struct spirv_header {
@@ -440,8 +506,3 @@ err:
        }
        return 0;
 }
-
-void nex_bind_sdrprog(nex_sdrprog *prog)
-{
-       glUseProgram(prog->prog);
-}
index 1de3560..f1ad71b 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "gfx.h"
 #include "wsys/wsys.h"
-/*#include "cgmath2/cgmath2.h"*/
+#include "cgmath2/cgmath2.h"
 
 enum nex_apiflags_gl {
        NEX_OPENGL_COMPAT       = 1,
index 8ed49de..2e7640b 100644 (file)
@@ -196,7 +196,7 @@ static void mouse(int bn, int st, int x, int y)
 {
        if(nex_cb.mousebn) {
                int idx = bn - GLUT_LEFT_BUTTON;
-               int press = bn == GLUT_DOWN;
+               int press = st == GLUT_DOWN;
                nex_cb.mousebn(idx, press, x, y, nex_cb.mousebn_cls);
        }
 }
diff --git a/test.c b/test.c
index e3aa026..579cbe2 100644 (file)
--- a/test.c
+++ b/test.c
@@ -14,8 +14,8 @@ static void mmove(int x, int y, void *cls);
 #define ATTR_COL       1
 
 static const float vdata[] = {
-       -0.25f, -0.25f, 0.25f, 0.25f, -0.25f, 0.25f, 0.25f, -0.25f, -0.25f, -0.25f, -0.25f, -0.25f,
-       -0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, -0.25f, -0.25f, 0.25f, -0.25f
+       -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1,
+       -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1
 };
 static const float vcolors[] = {
        1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0,
@@ -37,6 +37,9 @@ static nex_buffer *vbuf, *ibuf, *cbuf;
 static nex_geometry *geom;
 static nex_sdrprog *sdrprog;
 
+static float cam_theta, cam_phi = 0.5, cam_dist = 8;
+static float view_matrix[16], proj_matrix[16];
+
 int main(void)
 {
        nex_gfxapi_opengl(3, 3, NEX_OPENGL_DEBUG);
@@ -79,6 +82,9 @@ static int init(void)
        if(!(sdrprog = nex_load_sdrprog("test.v.spv", "test.p.spv"))) {
                return -1;
        }
+
+       nex_enable(NEX_DEPTH_TEST);
+       nex_enable(NEX_CULL_FACE);
        return 0;
 }
 
@@ -93,8 +99,19 @@ static void cleanup(void)
 
 static void display(void *cls)
 {
+       float mvp_matrix[16];
+
        nex_clear();
 
+       cgm_midentity(view_matrix);
+       cgm_mpretranslate(view_matrix, 0, 0, -cam_dist);
+       cgm_mprerotate(view_matrix, cam_phi, 1, 0, 0);
+       cgm_mprerotate(view_matrix, cam_theta, 0, 1, 0);
+
+       cgm_mcopy(mvp_matrix, view_matrix);
+       cgm_mmul(mvp_matrix, proj_matrix);
+       nex_uniform_mat4(sdrprog, 0, mvp_matrix);
+
        nex_bind_sdrprog(sdrprog);
        nex_draw_geometry(geom, NEX_TRIANGLES, 0);
 
@@ -104,6 +121,8 @@ static void display(void *cls)
 static void reshape(int x, int y, void *cls)
 {
        nex_viewport(0, 0, x, y);
+
+       cgm_mperspective(proj_matrix, cgm_deg_to_rad(50), (float)x / (float)y, 0.5, 500.0);
 }
 
 static void keyb(int key, int pressed, void *cls)
@@ -117,10 +136,49 @@ static void keyb(int key, int pressed, void *cls)
        }
 }
 
+static int prev_x, prev_y;
+static int bnstate[8];
+
 static void mbutton(int bn, int pressed, int x, int y, void *cls)
 {
+       if(bn < 8) bnstate[bn] = pressed;
+       prev_x = x;
+       prev_y = y;
+
+       if(pressed) {
+               if(bn == 3) {
+                       cam_dist -= 0.5f;
+                       nex_redisplay();
+               } else if(bn == 4) {
+                       cam_dist += 0.5f;
+                       nex_redisplay();
+               }
+       }
 }
 
 static void mmove(int x, int y, void *cls)
 {
+       int dx = x - prev_x;
+       int dy = y - prev_y;
+       prev_x = x;
+       prev_y = y;
+
+       if((dx | dy) == 0) return;
+
+       if(bnstate[0]) {
+               cam_theta += cgm_deg_to_rad(dx * 0.5f);
+               cam_phi += cgm_deg_to_rad(dy * 0.5f);
+
+               if(cam_phi < -CGM_HPI) cam_phi = -CGM_HPI;
+               if(cam_phi > CGM_HPI) cam_phi = CGM_HPI;
+
+               nex_redisplay();
+       }
+       if(bnstate[2]) {
+               cam_dist += dy * 0.1f;
+
+               if(cam_dist < 0) cam_dist = 0;
+
+               nex_redisplay();
+       }
 }
index aecbf05..d383b54 100644 (file)
@@ -1,7 +1,7 @@
 #version 410
 
 layout(location = 0) out vec4 ocol;
-layout(location = 3) in vec4 vcol;
+layout(location = 0) in vec4 vcol;
 
 void main()
 {
index 0ecd84a..4f8bc8e 100644 (file)
@@ -1,11 +1,14 @@
 #version 410
+#extension GL_ARB_explicit_uniform_location: require
 
 layout(location = 0) in vec4 attr_vertex;
 layout(location = 1) in vec4 attr_color;
-layout(location = 3) out vec4 vcol;
+layout(location = 0) out vec4 vcol;
+
+layout(location = 0) uniform mat4 mvp_matrix;
 
 void main()
 {
-       gl_Position = attr_vertex;
+       gl_Position = mvp_matrix * attr_vertex;
        vcol = attr_color;
 }