From 1def4f7b1423b13a1ef0ee3298bb37828c5c9df2 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 3 Apr 2024 10:43:52 +0300 Subject: [PATCH] first render --- Makefile | 2 +- src/cgmath2/cgmath2.h | 58 +++- src/cgmath2/cgmmat.inl | 668 +++++++++++++++++++++++++++++++++++++++++++++++ src/cgmath2/cgmmisc.inl | 213 +++++++++++++++ src/cgmath2/cgmquat.inl | 151 +++++++++++ src/cgmath2/cgmvec3.inl | 12 +- src/cgmath2/cgmvec4.inl | 151 +++++++++++ src/gfx.h | 17 +- src/gl/gfx_gl.c | 71 ++++- src/nexus3d.h | 2 +- src/wsys/wsys_fglut.c | 2 +- test.c | 62 ++++- test.p.glsl | 2 +- test.v.glsl | 7 +- 14 files changed, 1391 insertions(+), 27 deletions(-) create mode 100644 src/cgmath2/cgmmat.inl create mode 100644 src/cgmath2/cgmmisc.inl create mode 100644 src/cgmath2/cgmquat.inl create mode 100644 src/cgmath2/cgmvec4.inl diff --git a/Makefile b/Makefile index 203d578..72340f8 100644 --- 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) diff --git a/src/cgmath2/cgmath2.h b/src/cgmath2/cgmath2.h index 0e34f38..ea6be7a 100644 --- a/src/cgmath2/cgmath2.h +++ b/src/cgmath2/cgmath2.h @@ -4,7 +4,10 @@ #include #include -#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 index 0000000..952cfed --- /dev/null +++ b/src/cgmath2/cgmmat.inl @@ -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 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 index 0000000..21d34c4 --- /dev/null +++ b/src/cgmath2/cgmmisc.inl @@ -0,0 +1,213 @@ +/* gph-cmath - C graphics math library + * Copyright (C) 2018-2023 John Tsiombikas + * + * This program is free software. Feel free to use, modify, and/or redistribute + * it under the terms of the MIT/X11 license. See LICENSE for details. + * If you intend to redistribute parts of the code without the LICENSE file + * replace this paragraph with the full contents of the LICENSE file. + */ +#include + +static 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 index 0000000..e238006 --- /dev/null +++ b/src/cgmath2/cgmquat.inl @@ -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; +} diff --git a/src/cgmath2/cgmvec3.inl b/src/cgmath2/cgmvec3.inl index d6a50f2..c6b6675 100644 --- a/src/cgmath2/cgmvec3.inl +++ b/src/cgmath2/cgmvec3.inl @@ -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 index 0000000..307fbd5 --- /dev/null +++ b/src/cgmath2/cgmvec4.inl @@ -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; +} diff --git a/src/gfx.h b/src/gfx.h index 5faf474..61eac33 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -3,10 +3,11 @@ #include -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); diff --git a/src/gl/gfx_gl.c b/src/gl/gfx_gl.c index c0a830d..a735f28 100644 --- a/src/gl/gfx_gl.c +++ b/src/gl/gfx_gl.c @@ -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); -} diff --git a/src/nexus3d.h b/src/nexus3d.h index 1de3560..f1ad71b 100644 --- a/src/nexus3d.h +++ b/src/nexus3d.h @@ -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, diff --git a/src/wsys/wsys_fglut.c b/src/wsys/wsys_fglut.c index 8ed49de..2e7640b 100644 --- a/src/wsys/wsys_fglut.c +++ b/src/wsys/wsys_fglut.c @@ -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 --- 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(); + } } diff --git a/test.p.glsl b/test.p.glsl index aecbf05..d383b54 100644 --- a/test.p.glsl +++ b/test.p.glsl @@ -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() { diff --git a/test.v.glsl b/test.v.glsl index 0ecd84a..4f8bc8e 100644 --- a/test.v.glsl +++ b/test.v.glsl @@ -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; } -- 1.7.10.4