initial commit
[retroray] / src / gaw / gawswtnl.c
1 /*
2 Deep Runner - 6dof shooter game for the SGI O2.
3 Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
4
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.
9
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.
14
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/>.
17 */
18 #include <stdio.h>
19 #include <string.h>
20 #include <math.h>
21 #include "cgmath/cgmath.h"
22 #include "gaw.h"
23 #include "gawswtnl.h"
24 #include "polyfill.h"
25 #include "polyclip.h"
26 #include "../darray.h"
27
28 #define NORMALIZE(v) \
29         do { \
30                 float len = sqrt((v)[0] * (v)[0] + (v)[1] * (v)[1] + (v)[2] * (v)[2]); \
31                 if(len != 0.0) { \
32                         float s = 1.0 / len; \
33                         (v)[0] *= s; \
34                         (v)[1] *= s; \
35                         (v)[2] *= s; \
36                 } \
37         } while(0)
38
39
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);
44
45 static struct gaw_state st;
46 struct gaw_state *gaw_state;
47
48 static const float idmat[] = {
49         1, 0, 0, 0,
50         0, 1, 0, 0,
51         0, 0, 1, 0,
52         0, 0, 0, 1
53 };
54
55
56 void gaw_swtnl_reset(void)
57 {
58         int i;
59
60         memset(&st, 0, sizeof st);
61
62         st.polymode = POLYFILL_GOURAUD;
63
64         for(i=0; i<NUM_MATRICES; i++) {
65                 gaw_matrix_mode(i);
66                 gaw_load_identity();
67         }
68
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);
72         }
73         gaw_ambient(0.1, 0.1, 0.1);
74         gaw_mtl_diffuse(1, 1, 1, 1);
75
76         st.clear_depth = 0xffffff;
77
78         st.cur_comp = -1;
79         st.cur_tex = -1;
80
81         gaw_color3f(1, 1, 1);
82
83         gaw_state = &st;
84 }
85
86 void gaw_swtnl_init(void)
87 {
88         gaw_swtnl_reset();
89 }
90
91 void gaw_swtnl_destroy(void)
92 {
93 }
94
95 void gaw_viewport(int x, int y, int w, int h)
96 {
97         st.vport[0] = x;
98         st.vport[1] = y;
99         st.vport[2] = w;
100         st.vport[3] = h;
101 }
102
103 void gaw_matrix_mode(int mode)
104 {
105         st.mmode = mode;
106 }
107
108 void gaw_load_identity(void)
109 {
110         int top = st.mtop[st.mmode];
111         memcpy(st.mat[st.mmode][top], idmat, 16 * sizeof(float));
112 }
113
114 void gaw_load_matrix(const float *m)
115 {
116         int top = st.mtop[st.mmode];
117         memcpy(st.mat[st.mmode][top], m, 16 * sizeof(float));
118 }
119
120 #define M(i,j)  (((i) << 2) + (j))
121 void gaw_mult_matrix(const float *m2)
122 {
123         int i, j, top = st.mtop[st.mmode];
124         float m1[16];
125         float *dest = st.mat[st.mmode][top];
126
127         memcpy(m1, dest, sizeof m1);
128
129         for(i=0; i<4; i++) {
130                 for(j=0; j<4; j++) {
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)];
135                 }
136         }
137 }
138
139 void gaw_push_matrix(void)
140 {
141         int top = st.mtop[st.mmode];
142         if(top >= STACK_SIZE) {
143                 fprintf(stderr, "push_matrix overflow\n");
144                 return;
145         }
146         memcpy(st.mat[st.mmode][top + 1], st.mat[st.mmode][top], 16 * sizeof(float));
147         st.mtop[st.mmode] = top + 1;
148 }
149
150 void gaw_pop_matrix(void)
151 {
152         if(st.mtop[st.mmode] <= 0) {
153                 fprintf(stderr, "pop_matrix underflow\n");
154                 return;
155         }
156         --st.mtop[st.mmode];
157 }
158
159 void gaw_get_modelview(float *m)
160 {
161         int top = st.mtop[GAW_MODELVIEW];
162         memcpy(m, st.mat[GAW_MODELVIEW][top], 16 * sizeof(float));
163 }
164
165 void gaw_get_projection(float *m)
166 {
167         int top = st.mtop[GAW_PROJECTION];
168         memcpy(m, st.mat[GAW_PROJECTION][top], 16 * sizeof(float));
169 }
170
171 void gaw_translate(float x, float y, float z)
172 {
173         static float m[16];
174         m[0] = m[5] = m[10] = m[15] = 1.0f;
175         m[12] = x;
176         m[13] = y;
177         m[14] = z;
178         gaw_mult_matrix(m);
179 }
180
181 void gaw_rotate(float deg, float x, float y, float z)
182 {
183         static float m[16];
184
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;
189         float nxsq = x * x;
190         float nysq = y * y;
191         float nzsq = z * z;
192
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;
202         m[15] = 1.0f;
203
204         gaw_mult_matrix(m);
205 }
206
207 void gaw_scale(float sx, float sy, float sz)
208 {
209         static float m[16];
210         m[0] = sx;
211         m[5] = sy;
212         m[10] = sz;
213         m[15] = 1.0f;
214         gaw_mult_matrix(m);
215 }
216
217 void gaw_ortho(float l, float r, float b, float t, float n, float f)
218 {
219         static float m[16];
220
221         float dx = r - l;
222         float dy = t - b;
223         float dz = f - n;
224
225         m[0] = 2.0 / dx;
226         m[5] = 2.0 / dy;
227         m[10] = -2.0 / dz;
228         m[12] = -(r + l) / dx;
229         m[13] = -(t + b) / dy;
230         m[14] = -(f + n) / dz;
231         m[15] = 1.0f;
232
233         gaw_mult_matrix(m);
234 }
235
236 void gaw_frustum(float left, float right, float bottom, float top, float zn, float zf)
237 {
238         static float m[16];
239
240         float dx = right - left;
241         float dy = top - bottom;
242         float dz = zf - zn;
243
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;
248
249         m[0] = 2.0 * zn / dx;
250         m[5] = 2.0 * zn / dy;
251         m[8] = a;
252         m[9] = b;
253         m[10] = c;
254         m[11] = -1.0f;
255         m[14] = d;
256
257         gaw_mult_matrix(m);
258 }
259
260 void gaw_perspective(float vfov_deg, float aspect, float znear, float zfar)
261 {
262         static float m[16];
263
264         float vfov = M_PI * vfov_deg / 180.0f;
265         float s = 1.0f / tan(vfov * 0.5f);
266         float range = znear - zfar;
267
268         m[0] = s / aspect;
269         m[5] = s;
270         m[10] = (znear + zfar) / range;
271         m[11] = -1.0f;
272         m[14] = 2.0f * znear * zfar / range;
273
274         gaw_mult_matrix(m);
275 }
276
277 void gaw_save(void)
278 {
279         if(st.savopt_top >= STACK_SIZE) {
280                 return;
281         }
282         st.savopt[st.savopt_top++] = st.opt;
283 }
284
285 void gaw_restore(void)
286 {
287         if(st.savopt_top <= 0) {
288                 return;
289         }
290         st.opt = st.savopt[--st.savopt_top];
291 }
292
293 void gaw_swtnl_enable(int what)
294 {
295         st.opt |= 1 << what;
296 }
297
298 void gaw_swtnl_disable(int what)
299 {
300         st.opt &= ~(1 << what);
301 }
302
303 void gaw_depth_func(int func)
304 {
305         /* TODO */
306 }
307
308 void gaw_blend_func(int src, int dest)
309 {
310         st.bsrc = src;
311         st.bdst = dest;
312 }
313
314 void gaw_alpha_func(int func, float ref)
315 {
316         /* TODO */
317 }
318
319 #define CLAMP(x, a, b)          ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
320
321 void gaw_clear_color(float r, float g, float b, float a)
322 {
323         int ir = (int)(r * 255.0f);
324         int ig = (int)(g * 255.0f);
325         int ib = (int)(b * 255.0f);
326
327         ir = CLAMP(ir, 0, 255);
328         ig = CLAMP(ig, 0, 255);
329         ib = CLAMP(ib, 0, 255);
330
331         st.clear_color = PACK_RGB(ir, ig, ib);
332 }
333
334 void gaw_clear_depth(float z)
335 {
336         int iz = (int)(z * (float)0xffffff);
337         st.clear_depth = CLAMP(iz, 0, 0xffffff);
338 }
339
340 void gaw_swtnl_color_mask(int rmask, int gmask, int bmask, int amask)
341 {
342         /* TODO */
343 }
344
345 void gaw_swtnl_depth_mask(int mask)
346 {
347         /* TODO */
348 }
349
350 void gaw_vertex_array(int nelem, int stride, const void *ptr)
351 {
352         if(stride <= 0) {
353                 stride = nelem * sizeof(float);
354         }
355         st.vertex_nelem = nelem;
356         st.vertex_stride = stride;
357         st.vertex_ptr = ptr;
358 }
359
360 void gaw_normal_array(int stride, const void *ptr)
361 {
362         if(stride <= 0) {
363                 stride = 3 * sizeof(float);
364         }
365         st.normal_stride = stride;
366         st.normal_ptr = ptr;
367 }
368
369 void gaw_texcoord_array(int nelem, int stride, const void *ptr)
370 {
371         if(stride <= 0) {
372                 stride = nelem * sizeof(float);
373         }
374         st.texcoord_nelem = nelem;
375         st.texcoord_stride = stride;
376         st.texcoord_ptr = ptr;
377 }
378
379 void gaw_color_array(int nelem, int stride, const void *ptr)
380 {
381         if(stride <= 0) {
382                 stride = nelem * sizeof(float);
383         }
384         st.color_nelem = nelem;
385         st.color_stride = stride;
386         st.color_ptr = ptr;
387 }
388
389 void gaw_draw(int prim, int nverts)
390 {
391         gaw_draw_indexed(prim, 0, nverts);
392 }
393
394
395 #define NEED_NORMALS \
396         (st.opt & ((1 << GAW_LIGHTING) | (1 << GAW_SPHEREMAP)))
397
398 static int prim_vcount[] = {1, 2, 3, 4, 0};
399
400 void gaw_draw_indexed(int prim, const unsigned int *idxarr, int nidx)
401 {
402         int i, j, vidx, vnum, nfaces;
403         struct vertex v[16];
404         int mvtop = st.mtop[GAW_MODELVIEW];
405         int ptop = st.mtop[GAW_PROJECTION];
406         struct vertex *tmpv;
407         const float *vptr;
408
409         if(prim == GAW_QUAD_STRIP) return;      /* TODO */
410
411         if(st.cur_comp >= 0) {
412                 st.comp[st.cur_comp].prim = prim;
413         }
414
415         tmpv = alloca(prim * 6 * sizeof *tmpv);
416
417         /* calc the normal matrix */
418         if(NEED_NORMALS) {
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;
421         }
422
423         vidx = 0;
424         nfaces = nidx / prim_vcount[prim];
425
426         for(j=0; j<nfaces; j++) {
427                 vnum = prim_vcount[prim];       /* reset vnum for each iteration */
428
429                 for(i=0; i<vnum; i++) {
430                         if(idxarr) {
431                                 vidx = *idxarr++;
432                         }
433                         vptr = (const float*)((char*)st.vertex_ptr + vidx * st.vertex_stride);
434                         v[i].x = vptr[0];
435                         v[i].y = vptr[1];
436                         v[i].z = st.vertex_nelem > 2 ? vptr[2] : 0.0f;
437                         v[i].w = st.vertex_nelem > 3 ? vptr[3] : 1.0f;
438
439                         if(st.normal_ptr) {
440                                 vptr = (const float*)((char*)st.normal_ptr + vidx * st.normal_stride);
441                         } else {
442                                 vptr = &st.imm_curv.nx;
443                         }
444                         v[i].nx = vptr[0];
445                         v[i].ny = vptr[1];
446                         v[i].nz = vptr[2];
447
448                         if(st.texcoord_ptr) {
449                                 vptr = (const float*)((char*)st.texcoord_ptr + vidx * st.texcoord_stride);
450                         } else {
451                                 vptr = &st.imm_curv.u;
452                         }
453                         v[i].u = vptr[0];
454                         v[i].v = vptr[1];
455
456                         if(st.color_ptr) {
457                                 vptr = (const float*)((char*)st.color_ptr + vidx * st.color_stride);
458                         } else {
459                                 vptr = st.imm_curcol;
460                         }
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;
465
466                         vidx++;
467
468                         if(st.cur_comp >= 0) {
469                                 /* currently compiling geometry */
470                                 struct comp_geom *cg = st.comp + st.cur_comp;
471                                 float col[4];
472
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;
477
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 */
491                         }
492
493                         xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &v[i].x);
494
495                         if(NEED_NORMALS) {
496                                 xform3_vec3(st.norm_mat, &v[i].nx);
497                                 if(st.opt & (1 << GAW_LIGHTING)) {
498                                         shade(v + i);
499                                 }
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;
503                                 }
504                         }
505                         {
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];
510                                 v[i].u = x / w;
511                                 v[i].v = y / w;
512                         }
513                         xform4_vec3(st.mat[GAW_PROJECTION][ptop], &v[i].x);
514                 }
515
516                 if(st.cur_comp >= 0) {
517                         /* compiling geometry, don't draw, skip to the next primitive */
518                         continue;
519                 }
520
521                 /* clipping */
522                 for(i=0; i<6; i++) {
523                         memcpy(tmpv, v, vnum * sizeof *v);
524
525                         if(clip_frustum(v, &vnum, tmpv, vnum, i) < 0) {
526                                 /* polygon completely outside of view volume. discard */
527                                 vnum = 0;
528                                 break;
529                         }
530                 }
531
532                 if(!vnum) continue;
533
534                 for(i=0; i<vnum; i++) {
535                         if(v[i].w != 0.0f) {
536                                 v[i].x /= v[i].w;
537                                 v[i].y /= v[i].w;
538                                 if(st.opt & (1 << GAW_DEPTH_TEST)) {
539                                         v[i].z /= v[i].w;
540                                 }
541                         }
542                 }
543
544                 gaw_swtnl_drawprim(prim, v, vnum);
545         }
546 }
547
548 void gaw_begin(int prim)
549 {
550         st.imm_prim = prim;
551         st.imm_pcount = prim;
552         st.imm_numv = 0;
553 }
554
555 void gaw_end(void)
556 {
557         imm_flush();
558 }
559
560 static void imm_flush(void)
561 {
562         int numv = st.imm_numv;
563         st.imm_numv = 0;
564
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);
569
570         gaw_draw_indexed(st.imm_prim, 0, numv);
571
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);
576 }
577
578 void gaw_color3f(float r, float g, float b)
579 {
580         gaw_color4f(r, g, b, 1.0f);
581 }
582
583 void gaw_color4f(float r, float g, float b, float a)
584 {
585         st.imm_curcol[0] = r;
586         st.imm_curcol[1] = g;
587         st.imm_curcol[2] = b;
588         st.imm_curcol[3] = a;
589 }
590
591 void gaw_color3ub(int r, int g, int b)
592 {
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;
597 }
598
599 void gaw_normal(float x, float y, float z)
600 {
601         st.imm_curv.nx = x;
602         st.imm_curv.ny = y;
603         st.imm_curv.nz = z;
604 }
605
606 void gaw_texcoord1f(float u)
607 {
608         st.imm_curv.u = u;
609         st.imm_curv.v = 0.0f;
610 }
611
612 void gaw_texcoord2f(float u, float v)
613 {
614         st.imm_curv.u = u;
615         st.imm_curv.v = v;
616 }
617
618 void gaw_vertex2f(float x, float y)
619 {
620         gaw_vertex3f(x, y, 0);
621 }
622
623 void gaw_vertex3f(float x, float y, float z)
624 {
625         float *cptr = st.imm_cbuf + st.imm_numv * 4;
626         struct vertex *vptr = st.imm_vbuf + st.imm_numv++;
627         *vptr = st.imm_curv;
628         vptr->x = x;
629         vptr->y = y;
630         vptr->z = z;
631         vptr->w = 1.0f;
632
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];
637
638         if(!--st.imm_pcount) {
639                 if(st.imm_numv >= IMM_VBUF_SIZE - prim_vcount[st.imm_prim]) {
640                         imm_flush();
641                 }
642                 st.imm_pcount = prim_vcount[st.imm_prim];
643         }
644 }
645
646 void gaw_rect(float x1, float y1, float x2, float y2)
647 {
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);
653         gaw_end();
654 }
655
656
657 void gaw_pointsize(float sz)
658 {
659         /* TODO */
660 }
661
662 void gaw_linewidth(float w)
663 {
664         /* TODO */
665 }
666
667 int gaw_compile_begin(void)
668 {
669         int i;
670
671         st.cur_comp = -1;
672         for(i=0; i<MAX_COMPILED; i++) {
673                 if(st.comp[i].varr == 0) {
674                         st.cur_comp = i;
675                         break;
676                 }
677         }
678         if(st.cur_comp < 0) {
679                 return 0;
680         }
681
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));
687
688         return st.cur_comp + 1;
689 }
690
691 void gaw_compile_end(void)
692 {
693         st.cur_comp = -1;
694 }
695
696 void gaw_draw_compiled(int id)
697 {
698         int idx = id - 1;
699
700         if(!st.comp[idx].varr || st.comp[idx].prim == -1) {
701                 return;
702         }
703
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);
708
709         gaw_draw(st.comp[idx].prim, darr_size(st.comp[idx].varr) / 3);
710
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);
715 }
716
717 void gaw_free_compiled(int id)
718 {
719         int idx = id - 1;
720
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);
726 }
727
728 void gaw_mtl_diffuse(float r, float g, float b, float a)
729 {
730         st.mtl.kd[0] = r;
731         st.mtl.kd[1] = g;
732         st.mtl.kd[2] = b;
733         st.mtl.kd[3] = a;
734 }
735
736 void gaw_mtl_specular(float r, float g, float b, float shin)
737 {
738         st.mtl.ks[0] = r;
739         st.mtl.ks[1] = g;
740         st.mtl.ks[2] = b;
741         st.mtl.shin = shin;
742 }
743
744 void gaw_mtl_emission(float r, float g, float b)
745 {
746         st.mtl.ke[0] = r;
747         st.mtl.ke[1] = g;
748         st.mtl.ke[2] = b;
749 }
750
751 void gaw_texenv_sphmap(int enable)
752 {
753         if(enable) {
754                 st.opt |= 1 << GAW_SPHEREMAP;
755         } else {
756                 st.opt &= ~(1 << GAW_SPHEREMAP);
757         }
758 }
759
760 void gaw_set_tex1d(unsigned int texid)
761 {
762         if(texid > 0) {
763                 gaw_bind_tex1d(texid);
764                 gaw_enable(GAW_TEXTURE_1D);
765         } else {
766                 st.cur_tex = -1;
767                 gaw_disable(GAW_TEXTURE_1D);
768         }
769 }
770
771 void gaw_set_tex2d(unsigned int texid)
772 {
773         if(texid > 0) {
774                 gaw_bind_tex2d(texid);
775                 gaw_enable(GAW_TEXTURE_2D);
776         } else {
777                 st.cur_tex = -1;
778                 gaw_disable(GAW_TEXTURE_2D);
779         }
780 }
781
782 void gaw_ambient(float r, float g, float b)
783 {
784         st.ambient[0] = r;
785         st.ambient[1] = g;
786         st.ambient[2] = b;
787 }
788
789 void gaw_light_pos(int idx, float x, float y, float z)
790 {
791         int mvtop = st.mtop[GAW_MODELVIEW];
792
793         st.lt[idx].type = LT_POS;
794         st.lt[idx].x = x;
795         st.lt[idx].y = y;
796         st.lt[idx].z = z;
797
798         xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &st.lt[idx].x);
799 }
800
801 void gaw_light_dir(int idx, float x, float y, float z)
802 {
803         int mvtop = st.mtop[GAW_MODELVIEW];
804
805         st.lt[idx].type = LT_DIR;
806         st.lt[idx].x = x;
807         st.lt[idx].y = y;
808         st.lt[idx].z = z;
809
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;
813
814         xform4_vec3(st.norm_mat, &st.lt[idx].x);
815
816         NORMALIZE(&st.lt[idx].x);
817 }
818
819 void gaw_light_color(int idx, float r, float g, float b, float s)
820 {
821         st.lt[idx].r = r;
822         st.lt[idx].g = g;
823         st.lt[idx].b = b;
824 }
825
826 void gaw_lighting_fast(void)
827 {
828 }
829
830 void gaw_fog_color(float r, float g, float b)
831 {
832 }
833
834 void gaw_fog_linear(float z0, float z1)
835 {
836 }
837
838 void gaw_fog_fast(void)
839 {
840 }
841
842
843 void gaw_poly_wire(void)
844 {
845         st.polymode = POLYFILL_WIRE;
846 }
847
848 void gaw_poly_flat(void)
849 {
850         st.polymode = POLYFILL_FLAT;
851 }
852
853 void gaw_poly_gouraud(void)
854 {
855         st.polymode = POLYFILL_GOURAUD;
856 }
857
858
859 static __inline void xform4_vec3(const float *mat, float *vec)
860 {
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];
865         vec[2] = z;
866         vec[1] = y;
867         vec[0] = x;
868 }
869
870 static __inline void xform3_vec3(const float *mat, float *vec)
871 {
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];
875         vec[1] = y;
876         vec[0] = x;
877 }
878
879 static void shade(struct vertex *v)
880 {
881         int i, r, g, b;
882         float color[3];
883
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];
887
888         for(i=0; i<MAX_LIGHTS; i++) {
889                 float ldir[3];
890                 float ndotl;
891
892                 if(!(st.opt & (GAW_LIGHT0 << i))) {
893                         continue;
894                 }
895
896                 ldir[0] = st.lt[i].x;
897                 ldir[1] = st.lt[i].y;
898                 ldir[2] = st.lt[i].z;
899
900                 if(st.lt[i].type != LT_DIR) {
901                         ldir[0] -= v->x;
902                         ldir[1] -= v->y;
903                         ldir[2] -= v->z;
904                         NORMALIZE(ldir);
905                 }
906
907                 if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
908                         ndotl = 0.0f;
909                 }
910
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;
914
915                 /*
916                 if(st.opt & (1 << GAW_SPECULAR)) {
917                         float ndoth;
918                         ldir[2] += 1.0f;
919                         NORMALIZE(ldir);
920                         if((ndoth = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
921                                 ndoth = 0.0f;
922                         }
923                         ndoth = pow(ndoth, st.mtl.shin);
924
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;
928                 }
929                 */
930         }
931
932         r = cround64(color[0] * 255.0);
933         g = cround64(color[1] * 255.0);
934         b = cround64(color[2] * 255.0);
935
936         v->r = r > 255 ? 255 : r;
937         v->g = g > 255 ? 255 : g;
938         v->b = b > 255 ? 255 : b;
939 }