toggle buttons and tools
[retroray] / src / gaw / gawswtnl.c
1 /*
2 RetroRay - integrated standalone vintage modeller/renderer
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 void gaw_zoffset(float offs)
320 {
321         st.zoffs = offs;
322 }
323
324 #define CLAMP(x, a, b)          ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
325
326 void gaw_clear_color(float r, float g, float b, float a)
327 {
328         int ir = (int)(r * 255.0f);
329         int ig = (int)(g * 255.0f);
330         int ib = (int)(b * 255.0f);
331
332         ir = CLAMP(ir, 0, 255);
333         ig = CLAMP(ig, 0, 255);
334         ib = CLAMP(ib, 0, 255);
335
336         st.clear_color = PACK_RGB(ir, ig, ib);
337 }
338
339 void gaw_clear_depth(float z)
340 {
341         int iz = (int)(z * (float)0xffffff);
342         st.clear_depth = CLAMP(iz, 0, 0xffffff);
343 }
344
345 void gaw_swtnl_color_mask(int rmask, int gmask, int bmask, int amask)
346 {
347         /* TODO */
348 }
349
350 void gaw_swtnl_depth_mask(int mask)
351 {
352         /* TODO */
353 }
354
355 void gaw_vertex_array(int nelem, int stride, const void *ptr)
356 {
357         if(stride <= 0) {
358                 stride = nelem * sizeof(float);
359         }
360         st.vertex_nelem = nelem;
361         st.vertex_stride = stride;
362         st.vertex_ptr = ptr;
363 }
364
365 void gaw_normal_array(int stride, const void *ptr)
366 {
367         if(stride <= 0) {
368                 stride = 3 * sizeof(float);
369         }
370         st.normal_stride = stride;
371         st.normal_ptr = ptr;
372 }
373
374 void gaw_texcoord_array(int nelem, int stride, const void *ptr)
375 {
376         if(stride <= 0) {
377                 stride = nelem * sizeof(float);
378         }
379         st.texcoord_nelem = nelem;
380         st.texcoord_stride = stride;
381         st.texcoord_ptr = ptr;
382 }
383
384 void gaw_color_array(int nelem, int stride, const void *ptr)
385 {
386         if(stride <= 0) {
387                 stride = nelem * sizeof(float);
388         }
389         st.color_nelem = nelem;
390         st.color_stride = stride;
391         st.color_ptr = ptr;
392 }
393
394 void gaw_draw(int prim, int nverts)
395 {
396         gaw_draw_indexed(prim, 0, nverts);
397 }
398
399
400 #define NEED_NORMALS \
401         (st.opt & ((1 << GAW_LIGHTING) | (1 << GAW_SPHEREMAP)))
402
403 static int prim_vcount[] = {1, 2, 3, 4, 0};
404
405 void gaw_draw_indexed(int prim, const unsigned int *idxarr, int nidx)
406 {
407         int i, j, vidx, vnum, nfaces;
408         struct vertex v[16];
409         int mvtop = st.mtop[GAW_MODELVIEW];
410         int ptop = st.mtop[GAW_PROJECTION];
411         struct vertex *tmpv;
412         const float *vptr;
413
414         if(prim == GAW_QUAD_STRIP) return;      /* TODO */
415
416         if(st.cur_comp >= 0) {
417                 st.comp[st.cur_comp].prim = prim;
418         }
419
420         tmpv = alloca(prim * 6 * sizeof *tmpv);
421
422         /* calc the normal matrix */
423         if(NEED_NORMALS) {
424                 memcpy(st.norm_mat, st.mat[GAW_MODELVIEW][mvtop], 16 * sizeof(float));
425                 st.norm_mat[12] = st.norm_mat[13] = st.norm_mat[14] = 0.0f;
426         }
427
428         vidx = 0;
429         nfaces = nidx / prim_vcount[prim];
430
431         for(j=0; j<nfaces; j++) {
432                 vnum = prim_vcount[prim];       /* reset vnum for each iteration */
433
434                 for(i=0; i<vnum; i++) {
435                         if(idxarr) {
436                                 vidx = *idxarr++;
437                         }
438                         vptr = (const float*)((char*)st.vertex_ptr + vidx * st.vertex_stride);
439                         v[i].x = vptr[0];
440                         v[i].y = vptr[1];
441                         v[i].z = st.vertex_nelem > 2 ? vptr[2] : 0.0f;
442                         v[i].w = st.vertex_nelem > 3 ? vptr[3] : 1.0f;
443
444                         if(st.normal_ptr) {
445                                 vptr = (const float*)((char*)st.normal_ptr + vidx * st.normal_stride);
446                         } else {
447                                 vptr = &st.imm_curv.nx;
448                         }
449                         v[i].nx = vptr[0];
450                         v[i].ny = vptr[1];
451                         v[i].nz = vptr[2];
452
453                         if(st.texcoord_ptr) {
454                                 vptr = (const float*)((char*)st.texcoord_ptr + vidx * st.texcoord_stride);
455                         } else {
456                                 vptr = &st.imm_curv.u;
457                         }
458                         v[i].u = vptr[0];
459                         v[i].v = vptr[1];
460
461                         if(st.color_ptr) {
462                                 vptr = (const float*)((char*)st.color_ptr + vidx * st.color_stride);
463                         } else {
464                                 vptr = st.imm_curcol;
465                         }
466                         v[i].r = (int)(vptr[0] * 255.0f);
467                         v[i].g = (int)(vptr[1] * 255.0f);
468                         v[i].b = (int)(vptr[2] * 255.0f);
469                         v[i].a = st.color_nelem > 3 ? (int)(vptr[3] * 255.0f) : 255;
470
471                         vidx++;
472
473                         if(st.cur_comp >= 0) {
474                                 /* currently compiling geometry */
475                                 struct comp_geom *cg = st.comp + st.cur_comp;
476                                 float col[4];
477
478                                 col[0] = v[i].r / 255.0f;
479                                 col[1] = v[i].g / 255.0f;
480                                 col[2] = v[i].b / 255.0f;
481                                 col[3] = v[i].a / 255.0f;
482
483                                 darr_push(cg->varr, &v[i].x);
484                                 darr_push(cg->varr, &v[i].y);
485                                 darr_push(cg->varr, &v[i].z);
486                                 darr_push(cg->narr, &v[i].nx);
487                                 darr_push(cg->narr, &v[i].ny);
488                                 darr_push(cg->narr, &v[i].nz);
489                                 darr_push(cg->uvarr, &v[i].u);
490                                 darr_push(cg->uvarr, &v[i].v);
491                                 darr_push(cg->carr, col);
492                                 darr_push(cg->carr, col + 1);
493                                 darr_push(cg->carr, col + 2);
494                                 darr_push(cg->carr, col + 3);
495                                 continue;       /* don't transform, just skip to the next vertex */
496                         }
497
498                         xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &v[i].x);
499
500                         if(NEED_NORMALS) {
501                                 xform3_vec3(st.norm_mat, &v[i].nx);
502                                 if(st.opt & (1 << GAW_LIGHTING)) {
503                                         shade(v + i);
504                                 }
505                                 if(st.opt & (1 << GAW_SPHEREMAP)) {
506                                         v[i].u = v[i].nx * 0.5 + 0.5;
507                                         v[i].v = 0.5 - v[i].ny * 0.5;
508                                 }
509                         }
510                         {
511                                 float *mat = st.mat[GAW_TEXTURE][st.mtop[GAW_TEXTURE]];
512                                 float x = mat[0] * v[i].u + mat[4] * v[i].v + mat[12];
513                                 float y = mat[1] * v[i].u + mat[5] * v[i].v + mat[13];
514                                 float w = mat[3] * v[i].u + mat[7] * v[i].v + mat[15];
515                                 v[i].u = x / w;
516                                 v[i].v = y / w;
517                         }
518                         xform4_vec3(st.mat[GAW_PROJECTION][ptop], &v[i].x);
519                 }
520
521                 if(st.cur_comp >= 0) {
522                         /* compiling geometry, don't draw, skip to the next primitive */
523                         continue;
524                 }
525
526                 /* clipping */
527                 for(i=0; i<6; i++) {
528                         memcpy(tmpv, v, vnum * sizeof *v);
529
530                         if(clip_frustum(v, &vnum, tmpv, vnum, i) < 0) {
531                                 /* polygon completely outside of view volume. discard */
532                                 vnum = 0;
533                                 break;
534                         }
535                 }
536
537                 if(!vnum) continue;
538
539                 for(i=0; i<vnum; i++) {
540                         float oow = 1.0f / v[i].w;
541                         v[i].x *= oow;
542                         v[i].y *= oow;
543                         v[i].z += st.zoffs;
544                         if(st.opt & (1 << GAW_DEPTH_TEST)) {
545                                 v[i].z *= oow;
546                         }
547                 }
548
549                 gaw_swtnl_drawprim(prim, v, vnum);
550         }
551 }
552
553 void gaw_begin(int prim)
554 {
555         st.imm_prim = prim;
556         st.imm_pcount = prim_vcount[st.imm_prim];
557         st.imm_numv = 0;
558 }
559
560 void gaw_end(void)
561 {
562         imm_flush();
563 }
564
565 static void imm_flush(void)
566 {
567         int numv = st.imm_numv;
568         st.imm_numv = 0;
569
570         gaw_vertex_array(3, sizeof(struct vertex), &st.imm_vbuf->x);
571         gaw_normal_array(sizeof(struct vertex), &st.imm_vbuf->nx);
572         gaw_texcoord_array(2, sizeof(struct vertex), &st.imm_vbuf->u);
573         gaw_color_array(4, 0, st.imm_cbuf);
574
575         gaw_draw_indexed(st.imm_prim, 0, numv);
576
577         gaw_vertex_array(0, 0, 0);
578         gaw_normal_array(0, 0);
579         gaw_texcoord_array(0, 0, 0);
580         gaw_color_array(0, 0, 0);
581 }
582
583 void gaw_color3f(float r, float g, float b)
584 {
585         gaw_color4f(r, g, b, 1.0f);
586 }
587
588 void gaw_color4f(float r, float g, float b, float a)
589 {
590         st.imm_curcol[0] = r;
591         st.imm_curcol[1] = g;
592         st.imm_curcol[2] = b;
593         st.imm_curcol[3] = a;
594 }
595
596 void gaw_color3ub(int r, int g, int b)
597 {
598         st.imm_curcol[0] = r / 255.0f;
599         st.imm_curcol[1] = g / 255.0f;
600         st.imm_curcol[2] = b / 255.0f;
601         st.imm_curcol[3] = 1.0f;
602 }
603
604 void gaw_normal(float x, float y, float z)
605 {
606         st.imm_curv.nx = x;
607         st.imm_curv.ny = y;
608         st.imm_curv.nz = z;
609 }
610
611 void gaw_texcoord1f(float u)
612 {
613         st.imm_curv.u = u;
614         st.imm_curv.v = 0.0f;
615 }
616
617 void gaw_texcoord2f(float u, float v)
618 {
619         st.imm_curv.u = u;
620         st.imm_curv.v = v;
621 }
622
623 void gaw_vertex2f(float x, float y)
624 {
625         gaw_vertex4f(x, y, 0, 1);
626 }
627
628 void gaw_vertex3f(float x, float y, float z)
629 {
630         gaw_vertex4f(x, y, z, 1);
631 }
632
633 void gaw_vertex4f(float x, float y, float z, float w)
634 {
635         float *cptr = st.imm_cbuf + st.imm_numv * 4;
636         struct vertex *vptr = st.imm_vbuf + st.imm_numv++;
637         *vptr = st.imm_curv;
638         vptr->x = x;
639         vptr->y = y;
640         vptr->z = z;
641         vptr->w = w;
642
643         cptr[0] = st.imm_curcol[0];
644         cptr[1] = st.imm_curcol[1];
645         cptr[2] = st.imm_curcol[2];
646         cptr[3] = st.imm_curcol[3];
647
648         if(!--st.imm_pcount) {
649                 if(st.imm_numv >= IMM_VBUF_SIZE - prim_vcount[st.imm_prim]) {
650                         imm_flush();
651                 }
652                 st.imm_pcount = prim_vcount[st.imm_prim];
653         }
654 }
655
656 void gaw_rect(float x1, float y1, float x2, float y2)
657 {
658         gaw_begin(GAW_QUADS);
659         gaw_vertex2f(x1, y1);
660         gaw_vertex2f(x2, y1);
661         gaw_vertex2f(x2, y2);
662         gaw_vertex2f(x1, y2);
663         gaw_end();
664 }
665
666
667 void gaw_pointsize(float sz)
668 {
669         /* TODO */
670 }
671
672 void gaw_linewidth(float w)
673 {
674         /* TODO */
675 }
676
677 int gaw_compile_begin(void)
678 {
679         int i;
680
681         st.cur_comp = -1;
682         for(i=0; i<MAX_COMPILED; i++) {
683                 if(st.comp[i].varr == 0) {
684                         st.cur_comp = i;
685                         break;
686                 }
687         }
688         if(st.cur_comp < 0) {
689                 return 0;
690         }
691
692         st.comp[i].prim = -1;
693         st.comp[i].varr = darr_alloc(0, sizeof(float));
694         st.comp[i].narr = darr_alloc(0, sizeof(float));
695         st.comp[i].uvarr = darr_alloc(0, sizeof(float));
696         st.comp[i].carr = darr_alloc(0, sizeof(float));
697
698         return st.cur_comp + 1;
699 }
700
701 void gaw_compile_end(void)
702 {
703         st.cur_comp = -1;
704 }
705
706 void gaw_draw_compiled(int id)
707 {
708         int idx = id - 1;
709
710         if(!st.comp[idx].varr || st.comp[idx].prim == -1) {
711                 return;
712         }
713
714         gaw_vertex_array(3, 0, st.comp[idx].varr);
715         gaw_normal_array(0, st.comp[idx].narr);
716         gaw_texcoord_array(2, 0, st.comp[idx].uvarr);
717         gaw_color_array(4, 0, st.comp[idx].carr);
718
719         gaw_draw(st.comp[idx].prim, darr_size(st.comp[idx].varr) / 3);
720
721         gaw_vertex_array(0, 0, 0);
722         gaw_normal_array(0, 0);
723         gaw_texcoord_array(0, 0, 0);
724         gaw_color_array(0, 0, 0);
725 }
726
727 void gaw_free_compiled(int id)
728 {
729         int idx = id - 1;
730
731         darr_free(st.comp[idx].varr);
732         darr_free(st.comp[idx].narr);
733         darr_free(st.comp[idx].uvarr);
734         darr_free(st.comp[idx].carr);
735         memset(st.comp + idx, 0, sizeof *st.comp);
736 }
737
738 void gaw_mtl_diffuse(float r, float g, float b, float a)
739 {
740         st.mtl.kd[0] = r;
741         st.mtl.kd[1] = g;
742         st.mtl.kd[2] = b;
743         st.mtl.kd[3] = a;
744 }
745
746 void gaw_mtl_specular(float r, float g, float b, float shin)
747 {
748         st.mtl.ks[0] = r;
749         st.mtl.ks[1] = g;
750         st.mtl.ks[2] = b;
751         st.mtl.shin = shin;
752 }
753
754 void gaw_mtl_emission(float r, float g, float b)
755 {
756         st.mtl.ke[0] = r;
757         st.mtl.ke[1] = g;
758         st.mtl.ke[2] = b;
759 }
760
761 void gaw_texenv_sphmap(int enable)
762 {
763         if(enable) {
764                 st.opt |= 1 << GAW_SPHEREMAP;
765         } else {
766                 st.opt &= ~(1 << GAW_SPHEREMAP);
767         }
768 }
769
770 void gaw_set_tex1d(unsigned int texid)
771 {
772         if(texid > 0) {
773                 gaw_bind_tex1d(texid);
774                 gaw_enable(GAW_TEXTURE_1D);
775         } else {
776                 st.cur_tex = -1;
777                 gaw_disable(GAW_TEXTURE_1D);
778         }
779 }
780
781 void gaw_set_tex2d(unsigned int texid)
782 {
783         if(texid > 0) {
784                 gaw_bind_tex2d(texid);
785                 gaw_enable(GAW_TEXTURE_2D);
786         } else {
787                 st.cur_tex = -1;
788                 gaw_disable(GAW_TEXTURE_2D);
789         }
790 }
791
792 void gaw_ambient(float r, float g, float b)
793 {
794         st.ambient[0] = r;
795         st.ambient[1] = g;
796         st.ambient[2] = b;
797 }
798
799 void gaw_light_pos(int idx, float x, float y, float z)
800 {
801         int mvtop = st.mtop[GAW_MODELVIEW];
802
803         st.lt[idx].type = LT_POS;
804         st.lt[idx].x = x;
805         st.lt[idx].y = y;
806         st.lt[idx].z = z;
807
808         xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &st.lt[idx].x);
809 }
810
811 void gaw_light_dir(int idx, float x, float y, float z)
812 {
813         int mvtop = st.mtop[GAW_MODELVIEW];
814
815         st.lt[idx].type = LT_DIR;
816         st.lt[idx].x = x;
817         st.lt[idx].y = y;
818         st.lt[idx].z = z;
819
820         /* calc the normal matrix */
821         memcpy(st.norm_mat, st.mat[GAW_MODELVIEW][mvtop], 16 * sizeof(float));
822         st.norm_mat[12] = st.norm_mat[13] = st.norm_mat[14] = 0.0f;
823
824         xform4_vec3(st.norm_mat, &st.lt[idx].x);
825
826         NORMALIZE(&st.lt[idx].x);
827 }
828
829 void gaw_light_color(int idx, float r, float g, float b, float s)
830 {
831         st.lt[idx].r = r;
832         st.lt[idx].g = g;
833         st.lt[idx].b = b;
834 }
835
836 void gaw_lighting_fast(void)
837 {
838 }
839
840 void gaw_fog_color(float r, float g, float b)
841 {
842 }
843
844 void gaw_fog_linear(float z0, float z1)
845 {
846 }
847
848 void gaw_fog_fast(void)
849 {
850 }
851
852
853 void gaw_poly_wire(void)
854 {
855         st.polymode = POLYFILL_WIRE;
856 }
857
858 void gaw_poly_flat(void)
859 {
860         st.polymode = POLYFILL_FLAT;
861 }
862
863 void gaw_poly_gouraud(void)
864 {
865         st.polymode = POLYFILL_GOURAUD;
866 }
867
868
869 static __inline void xform4_vec3(const float *mat, float *vec)
870 {
871         float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12];
872         float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13];
873         float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
874         vec[3] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
875         vec[2] = z;
876         vec[1] = y;
877         vec[0] = x;
878 }
879
880 static __inline void xform3_vec3(const float *mat, float *vec)
881 {
882         float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2];
883         float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2];
884         vec[2] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2];
885         vec[1] = y;
886         vec[0] = x;
887 }
888
889 static void shade(struct vertex *v)
890 {
891         int i, r, g, b;
892         float color[3];
893
894         color[0] = st.ambient[0] * st.mtl.kd[0];
895         color[1] = st.ambient[1] * st.mtl.kd[1];
896         color[2] = st.ambient[2] * st.mtl.kd[2];
897
898         for(i=0; i<MAX_LIGHTS; i++) {
899                 float ldir[3];
900                 float ndotl;
901
902                 if(!(st.opt & (GAW_LIGHT0 << i))) {
903                         continue;
904                 }
905
906                 ldir[0] = st.lt[i].x;
907                 ldir[1] = st.lt[i].y;
908                 ldir[2] = st.lt[i].z;
909
910                 if(st.lt[i].type != LT_DIR) {
911                         ldir[0] -= v->x;
912                         ldir[1] -= v->y;
913                         ldir[2] -= v->z;
914                         NORMALIZE(ldir);
915                 }
916
917                 if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
918                         ndotl = 0.0f;
919                 }
920
921                 color[0] += st.mtl.kd[0] * st.lt[i].r * ndotl;
922                 color[1] += st.mtl.kd[1] * st.lt[i].g * ndotl;
923                 color[2] += st.mtl.kd[2] * st.lt[i].b * ndotl;
924
925                 /*
926                 if(st.opt & (1 << GAW_SPECULAR)) {
927                         float ndoth;
928                         ldir[2] += 1.0f;
929                         NORMALIZE(ldir);
930                         if((ndoth = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
931                                 ndoth = 0.0f;
932                         }
933                         ndoth = pow(ndoth, st.mtl.shin);
934
935                         color[0] += st.mtl.ks[0] * st.lt[i].r * ndoth;
936                         color[1] += st.mtl.ks[1] * st.lt[i].g * ndoth;
937                         color[2] += st.mtl.ks[2] * st.lt[i].b * ndoth;
938                 }
939                 */
940         }
941
942         r = cround64(color[0] * 255.0);
943         g = cround64(color[1] * 255.0);
944         b = cround64(color[2] * 255.0);
945
946         v->r = r > 255 ? 255 : r;
947         v->g = g > 255 ? 255 : g;
948         v->b = b > 255 ? 255 : b;
949 }