2 Deep Runner - 6dof shooter game for the SGI O2.
3 Copyright (C) 2023 John Tsiombikas <nuclear@mutantstargoat.com>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
21 #include "cgmath/cgmath.h"
26 #include "../darray.h"
28 #define NORMALIZE(v) \
30 float len = sqrt((v)[0] * (v)[0] + (v)[1] * (v)[1] + (v)[2] * (v)[2]); \
32 float s = 1.0 / len; \
40 static void imm_flush(void);
41 static __inline void xform4_vec3(const float *mat, float *vec);
42 static __inline void xform3_vec3(const float *mat, float *vec);
43 static void shade(struct vertex *v);
45 static struct gaw_state st;
46 struct gaw_state *gaw_state;
48 static const float idmat[] = {
56 void gaw_swtnl_reset(void)
60 memset(&st, 0, sizeof st);
62 st.polymode = POLYFILL_GOURAUD;
64 for(i=0; i<NUM_MATRICES; i++) {
69 for(i=0; i<MAX_LIGHTS; i++) {
70 gaw_light_dir(i, 0, 0, 1);
71 gaw_light_color(i, 1, 1, 1, 1);
73 gaw_ambient(0.1, 0.1, 0.1);
74 gaw_mtl_diffuse(1, 1, 1, 1);
76 st.clear_depth = 0xffffff;
86 void gaw_swtnl_init(void)
91 void gaw_swtnl_destroy(void)
95 void gaw_viewport(int x, int y, int w, int h)
103 void gaw_matrix_mode(int mode)
108 void gaw_load_identity(void)
110 int top = st.mtop[st.mmode];
111 memcpy(st.mat[st.mmode][top], idmat, 16 * sizeof(float));
114 void gaw_load_matrix(const float *m)
116 int top = st.mtop[st.mmode];
117 memcpy(st.mat[st.mmode][top], m, 16 * sizeof(float));
120 #define M(i,j) (((i) << 2) + (j))
121 void gaw_mult_matrix(const float *m2)
123 int i, j, top = st.mtop[st.mmode];
125 float *dest = st.mat[st.mmode][top];
127 memcpy(m1, dest, sizeof m1);
131 *dest++ = m1[M(0,j)] * m2[M(i,0)] +
132 m1[M(1,j)] * m2[M(i,1)] +
133 m1[M(2,j)] * m2[M(i,2)] +
134 m1[M(3,j)] * m2[M(i,3)];
139 void gaw_push_matrix(void)
141 int top = st.mtop[st.mmode];
142 if(top >= STACK_SIZE) {
143 fprintf(stderr, "push_matrix overflow\n");
146 memcpy(st.mat[st.mmode][top + 1], st.mat[st.mmode][top], 16 * sizeof(float));
147 st.mtop[st.mmode] = top + 1;
150 void gaw_pop_matrix(void)
152 if(st.mtop[st.mmode] <= 0) {
153 fprintf(stderr, "pop_matrix underflow\n");
159 void gaw_get_modelview(float *m)
161 int top = st.mtop[GAW_MODELVIEW];
162 memcpy(m, st.mat[GAW_MODELVIEW][top], 16 * sizeof(float));
165 void gaw_get_projection(float *m)
167 int top = st.mtop[GAW_PROJECTION];
168 memcpy(m, st.mat[GAW_PROJECTION][top], 16 * sizeof(float));
171 void gaw_translate(float x, float y, float z)
174 m[0] = m[5] = m[10] = m[15] = 1.0f;
181 void gaw_rotate(float deg, float x, float y, float z)
185 float angle = M_PI * deg / 180.0f;
186 float sina = sin(angle);
187 float cosa = cos(angle);
188 float one_minus_cosa = 1.0f - cosa;
193 m[0] = nxsq + (1.0f - nxsq) * cosa;
194 m[4] = x * y * one_minus_cosa - z * sina;
195 m[8] = x * z * one_minus_cosa + y * sina;
196 m[1] = x * y * one_minus_cosa + z * sina;
197 m[5] = nysq + (1.0 - nysq) * cosa;
198 m[9] = y * z * one_minus_cosa - x * sina;
199 m[2] = x * z * one_minus_cosa - y * sina;
200 m[6] = y * z * one_minus_cosa + x * sina;
201 m[10] = nzsq + (1.0 - nzsq) * cosa;
207 void gaw_scale(float sx, float sy, float sz)
217 void gaw_ortho(float l, float r, float b, float t, float n, float f)
228 m[12] = -(r + l) / dx;
229 m[13] = -(t + b) / dy;
230 m[14] = -(f + n) / dz;
236 void gaw_frustum(float left, float right, float bottom, float top, float zn, float zf)
240 float dx = right - left;
241 float dy = top - bottom;
244 float a = (right + left) / dx;
245 float b = (top + bottom) / dy;
246 float c = -(zf + zn) / dz;
247 float d = -2.0 * zf * zn / dz;
249 m[0] = 2.0 * zn / dx;
250 m[5] = 2.0 * zn / dy;
260 void gaw_perspective(float vfov_deg, float aspect, float znear, float zfar)
264 float vfov = M_PI * vfov_deg / 180.0f;
265 float s = 1.0f / tan(vfov * 0.5f);
266 float range = znear - zfar;
270 m[10] = (znear + zfar) / range;
272 m[14] = 2.0f * znear * zfar / range;
279 if(st.savopt_top >= STACK_SIZE) {
282 st.savopt[st.savopt_top++] = st.opt;
285 void gaw_restore(void)
287 if(st.savopt_top <= 0) {
290 st.opt = st.savopt[--st.savopt_top];
293 void gaw_swtnl_enable(int what)
298 void gaw_swtnl_disable(int what)
300 st.opt &= ~(1 << what);
303 void gaw_depth_func(int func)
308 void gaw_blend_func(int src, int dest)
314 void gaw_alpha_func(int func, float ref)
319 #define CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
321 void gaw_clear_color(float r, float g, float b, float a)
323 int ir = (int)(r * 255.0f);
324 int ig = (int)(g * 255.0f);
325 int ib = (int)(b * 255.0f);
327 ir = CLAMP(ir, 0, 255);
328 ig = CLAMP(ig, 0, 255);
329 ib = CLAMP(ib, 0, 255);
331 st.clear_color = PACK_RGB(ir, ig, ib);
334 void gaw_clear_depth(float z)
336 int iz = (int)(z * (float)0xffffff);
337 st.clear_depth = CLAMP(iz, 0, 0xffffff);
340 void gaw_swtnl_color_mask(int rmask, int gmask, int bmask, int amask)
345 void gaw_swtnl_depth_mask(int mask)
350 void gaw_vertex_array(int nelem, int stride, const void *ptr)
353 stride = nelem * sizeof(float);
355 st.vertex_nelem = nelem;
356 st.vertex_stride = stride;
360 void gaw_normal_array(int stride, const void *ptr)
363 stride = 3 * sizeof(float);
365 st.normal_stride = stride;
369 void gaw_texcoord_array(int nelem, int stride, const void *ptr)
372 stride = nelem * sizeof(float);
374 st.texcoord_nelem = nelem;
375 st.texcoord_stride = stride;
376 st.texcoord_ptr = ptr;
379 void gaw_color_array(int nelem, int stride, const void *ptr)
382 stride = nelem * sizeof(float);
384 st.color_nelem = nelem;
385 st.color_stride = stride;
389 void gaw_draw(int prim, int nverts)
391 gaw_draw_indexed(prim, 0, nverts);
395 #define NEED_NORMALS \
396 (st.opt & ((1 << GAW_LIGHTING) | (1 << GAW_SPHEREMAP)))
398 static int prim_vcount[] = {1, 2, 3, 4, 0};
400 void gaw_draw_indexed(int prim, const unsigned int *idxarr, int nidx)
402 int i, j, vidx, vnum, nfaces;
404 int mvtop = st.mtop[GAW_MODELVIEW];
405 int ptop = st.mtop[GAW_PROJECTION];
409 if(prim == GAW_QUAD_STRIP) return; /* TODO */
411 if(st.cur_comp >= 0) {
412 st.comp[st.cur_comp].prim = prim;
415 tmpv = alloca(prim * 6 * sizeof *tmpv);
417 /* calc the normal matrix */
419 memcpy(st.norm_mat, st.mat[GAW_MODELVIEW][mvtop], 16 * sizeof(float));
420 st.norm_mat[12] = st.norm_mat[13] = st.norm_mat[14] = 0.0f;
424 nfaces = nidx / prim_vcount[prim];
426 for(j=0; j<nfaces; j++) {
427 vnum = prim_vcount[prim]; /* reset vnum for each iteration */
429 for(i=0; i<vnum; i++) {
433 vptr = (const float*)((char*)st.vertex_ptr + vidx * st.vertex_stride);
436 v[i].z = st.vertex_nelem > 2 ? vptr[2] : 0.0f;
437 v[i].w = st.vertex_nelem > 3 ? vptr[3] : 1.0f;
440 vptr = (const float*)((char*)st.normal_ptr + vidx * st.normal_stride);
442 vptr = &st.imm_curv.nx;
448 if(st.texcoord_ptr) {
449 vptr = (const float*)((char*)st.texcoord_ptr + vidx * st.texcoord_stride);
451 vptr = &st.imm_curv.u;
457 vptr = (const float*)((char*)st.color_ptr + vidx * st.color_stride);
459 vptr = st.imm_curcol;
461 v[i].r = (int)(vptr[0] * 255.0f);
462 v[i].g = (int)(vptr[1] * 255.0f);
463 v[i].b = (int)(vptr[2] * 255.0f);
464 v[i].a = st.color_nelem > 3 ? (int)(vptr[3] * 255.0f) : 255;
468 if(st.cur_comp >= 0) {
469 /* currently compiling geometry */
470 struct comp_geom *cg = st.comp + st.cur_comp;
473 col[0] = v[i].r / 255.0f;
474 col[1] = v[i].g / 255.0f;
475 col[2] = v[i].b / 255.0f;
476 col[3] = v[i].a / 255.0f;
478 darr_push(cg->varr, &v[i].x);
479 darr_push(cg->varr, &v[i].y);
480 darr_push(cg->varr, &v[i].z);
481 darr_push(cg->narr, &v[i].nx);
482 darr_push(cg->narr, &v[i].ny);
483 darr_push(cg->narr, &v[i].nz);
484 darr_push(cg->uvarr, &v[i].u);
485 darr_push(cg->uvarr, &v[i].v);
486 darr_push(cg->carr, col);
487 darr_push(cg->carr, col + 1);
488 darr_push(cg->carr, col + 2);
489 darr_push(cg->carr, col + 3);
490 continue; /* don't transform, just skip to the next vertex */
493 xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &v[i].x);
496 xform3_vec3(st.norm_mat, &v[i].nx);
497 if(st.opt & (1 << GAW_LIGHTING)) {
500 if(st.opt & (1 << GAW_SPHEREMAP)) {
501 v[i].u = v[i].nx * 0.5 + 0.5;
502 v[i].v = 0.5 - v[i].ny * 0.5;
506 float *mat = st.mat[GAW_TEXTURE][st.mtop[GAW_TEXTURE]];
507 float x = mat[0] * v[i].u + mat[4] * v[i].v + mat[12];
508 float y = mat[1] * v[i].u + mat[5] * v[i].v + mat[13];
509 float w = mat[3] * v[i].u + mat[7] * v[i].v + mat[15];
513 xform4_vec3(st.mat[GAW_PROJECTION][ptop], &v[i].x);
516 if(st.cur_comp >= 0) {
517 /* compiling geometry, don't draw, skip to the next primitive */
523 memcpy(tmpv, v, vnum * sizeof *v);
525 if(clip_frustum(v, &vnum, tmpv, vnum, i) < 0) {
526 /* polygon completely outside of view volume. discard */
534 for(i=0; i<vnum; i++) {
538 if(st.opt & (1 << GAW_DEPTH_TEST)) {
544 gaw_swtnl_drawprim(prim, v, vnum);
548 void gaw_begin(int prim)
551 st.imm_pcount = prim;
560 static void imm_flush(void)
562 int numv = st.imm_numv;
565 gaw_vertex_array(3, sizeof(struct vertex), &st.imm_vbuf->x);
566 gaw_normal_array(sizeof(struct vertex), &st.imm_vbuf->nx);
567 gaw_texcoord_array(2, sizeof(struct vertex), &st.imm_vbuf->u);
568 gaw_color_array(4, 0, st.imm_cbuf);
570 gaw_draw_indexed(st.imm_prim, 0, numv);
572 gaw_vertex_array(0, 0, 0);
573 gaw_normal_array(0, 0);
574 gaw_texcoord_array(0, 0, 0);
575 gaw_color_array(0, 0, 0);
578 void gaw_color3f(float r, float g, float b)
580 gaw_color4f(r, g, b, 1.0f);
583 void gaw_color4f(float r, float g, float b, float a)
585 st.imm_curcol[0] = r;
586 st.imm_curcol[1] = g;
587 st.imm_curcol[2] = b;
588 st.imm_curcol[3] = a;
591 void gaw_color3ub(int r, int g, int b)
593 st.imm_curcol[0] = r / 255.0f;
594 st.imm_curcol[1] = g / 255.0f;
595 st.imm_curcol[2] = b / 255.0f;
596 st.imm_curcol[3] = 1.0f;
599 void gaw_normal(float x, float y, float z)
606 void gaw_texcoord1f(float u)
609 st.imm_curv.v = 0.0f;
612 void gaw_texcoord2f(float u, float v)
618 void gaw_vertex2f(float x, float y)
620 gaw_vertex3f(x, y, 0);
623 void gaw_vertex3f(float x, float y, float z)
625 float *cptr = st.imm_cbuf + st.imm_numv * 4;
626 struct vertex *vptr = st.imm_vbuf + st.imm_numv++;
633 cptr[0] = st.imm_curcol[0];
634 cptr[1] = st.imm_curcol[1];
635 cptr[2] = st.imm_curcol[2];
636 cptr[3] = st.imm_curcol[3];
638 if(!--st.imm_pcount) {
639 if(st.imm_numv >= IMM_VBUF_SIZE - prim_vcount[st.imm_prim]) {
642 st.imm_pcount = prim_vcount[st.imm_prim];
646 void gaw_rect(float x1, float y1, float x2, float y2)
648 gaw_begin(GAW_QUADS);
649 gaw_vertex2f(x1, y1);
650 gaw_vertex2f(x2, y1);
651 gaw_vertex2f(x2, y2);
652 gaw_vertex2f(x1, y2);
657 void gaw_pointsize(float sz)
662 void gaw_linewidth(float w)
667 int gaw_compile_begin(void)
672 for(i=0; i<MAX_COMPILED; i++) {
673 if(st.comp[i].varr == 0) {
678 if(st.cur_comp < 0) {
682 st.comp[i].prim = -1;
683 st.comp[i].varr = darr_alloc(0, sizeof(float));
684 st.comp[i].narr = darr_alloc(0, sizeof(float));
685 st.comp[i].uvarr = darr_alloc(0, sizeof(float));
686 st.comp[i].carr = darr_alloc(0, sizeof(float));
688 return st.cur_comp + 1;
691 void gaw_compile_end(void)
696 void gaw_draw_compiled(int id)
700 if(!st.comp[idx].varr || st.comp[idx].prim == -1) {
704 gaw_vertex_array(3, 0, st.comp[idx].varr);
705 gaw_normal_array(0, st.comp[idx].narr);
706 gaw_texcoord_array(2, 0, st.comp[idx].uvarr);
707 gaw_color_array(4, 0, st.comp[idx].carr);
709 gaw_draw(st.comp[idx].prim, darr_size(st.comp[idx].varr) / 3);
711 gaw_vertex_array(0, 0, 0);
712 gaw_normal_array(0, 0);
713 gaw_texcoord_array(0, 0, 0);
714 gaw_color_array(0, 0, 0);
717 void gaw_free_compiled(int id)
721 darr_free(st.comp[idx].varr);
722 darr_free(st.comp[idx].narr);
723 darr_free(st.comp[idx].uvarr);
724 darr_free(st.comp[idx].carr);
725 memset(st.comp + idx, 0, sizeof *st.comp);
728 void gaw_mtl_diffuse(float r, float g, float b, float a)
736 void gaw_mtl_specular(float r, float g, float b, float shin)
744 void gaw_mtl_emission(float r, float g, float b)
751 void gaw_texenv_sphmap(int enable)
754 st.opt |= 1 << GAW_SPHEREMAP;
756 st.opt &= ~(1 << GAW_SPHEREMAP);
760 void gaw_set_tex1d(unsigned int texid)
763 gaw_bind_tex1d(texid);
764 gaw_enable(GAW_TEXTURE_1D);
767 gaw_disable(GAW_TEXTURE_1D);
771 void gaw_set_tex2d(unsigned int texid)
774 gaw_bind_tex2d(texid);
775 gaw_enable(GAW_TEXTURE_2D);
778 gaw_disable(GAW_TEXTURE_2D);
782 void gaw_ambient(float r, float g, float b)
789 void gaw_light_pos(int idx, float x, float y, float z)
791 int mvtop = st.mtop[GAW_MODELVIEW];
793 st.lt[idx].type = LT_POS;
798 xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &st.lt[idx].x);
801 void gaw_light_dir(int idx, float x, float y, float z)
803 int mvtop = st.mtop[GAW_MODELVIEW];
805 st.lt[idx].type = LT_DIR;
810 /* calc the normal matrix */
811 memcpy(st.norm_mat, st.mat[GAW_MODELVIEW][mvtop], 16 * sizeof(float));
812 st.norm_mat[12] = st.norm_mat[13] = st.norm_mat[14] = 0.0f;
814 xform4_vec3(st.norm_mat, &st.lt[idx].x);
816 NORMALIZE(&st.lt[idx].x);
819 void gaw_light_color(int idx, float r, float g, float b, float s)
826 void gaw_lighting_fast(void)
830 void gaw_fog_color(float r, float g, float b)
834 void gaw_fog_linear(float z0, float z1)
838 void gaw_fog_fast(void)
843 void gaw_poly_wire(void)
845 st.polymode = POLYFILL_WIRE;
848 void gaw_poly_flat(void)
850 st.polymode = POLYFILL_FLAT;
853 void gaw_poly_gouraud(void)
855 st.polymode = POLYFILL_GOURAUD;
859 static __inline void xform4_vec3(const float *mat, float *vec)
861 float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12];
862 float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13];
863 float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
864 vec[3] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
870 static __inline void xform3_vec3(const float *mat, float *vec)
872 float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2];
873 float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2];
874 vec[2] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2];
879 static void shade(struct vertex *v)
884 color[0] = st.ambient[0] * st.mtl.kd[0];
885 color[1] = st.ambient[1] * st.mtl.kd[1];
886 color[2] = st.ambient[2] * st.mtl.kd[2];
888 for(i=0; i<MAX_LIGHTS; i++) {
892 if(!(st.opt & (GAW_LIGHT0 << i))) {
896 ldir[0] = st.lt[i].x;
897 ldir[1] = st.lt[i].y;
898 ldir[2] = st.lt[i].z;
900 if(st.lt[i].type != LT_DIR) {
907 if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
911 color[0] += st.mtl.kd[0] * st.lt[i].r * ndotl;
912 color[1] += st.mtl.kd[1] * st.lt[i].g * ndotl;
913 color[2] += st.mtl.kd[2] * st.lt[i].b * ndotl;
916 if(st.opt & (1 << GAW_SPECULAR)) {
920 if((ndoth = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
923 ndoth = pow(ndoth, st.mtl.shin);
925 color[0] += st.mtl.ks[0] * st.lt[i].r * ndoth;
926 color[1] += st.mtl.ks[1] * st.lt[i].g * ndoth;
927 color[2] += st.mtl.ks[2] * st.lt[i].b * ndoth;
932 r = cround64(color[0] * 255.0);
933 g = cround64(color[1] * 255.0);
934 b = cround64(color[2] * 255.0);
936 v->r = r > 255 ? 255 : r;
937 v->g = g > 255 ? 255 : g;
938 v->b = b > 255 ? 255 : b;