picking and brute force ray intersections
[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_get_viewport(int *vp)
104 {
105         memcpy(vp, st.vport, sizeof st.vport);
106 }
107
108 void gaw_matrix_mode(int mode)
109 {
110         st.mmode = mode;
111 }
112
113 void gaw_load_identity(void)
114 {
115         int top = st.mtop[st.mmode];
116         memcpy(st.mat[st.mmode][top], idmat, 16 * sizeof(float));
117 }
118
119 void gaw_load_matrix(const float *m)
120 {
121         int top = st.mtop[st.mmode];
122         memcpy(st.mat[st.mmode][top], m, 16 * sizeof(float));
123 }
124
125 #define M(i,j)  (((i) << 2) + (j))
126 void gaw_mult_matrix(const float *m2)
127 {
128         int i, j, top = st.mtop[st.mmode];
129         float m1[16];
130         float *dest = st.mat[st.mmode][top];
131
132         memcpy(m1, dest, sizeof m1);
133
134         for(i=0; i<4; i++) {
135                 for(j=0; j<4; j++) {
136                         *dest++ = m1[M(0,j)] * m2[M(i,0)] +
137                                 m1[M(1,j)] * m2[M(i,1)] +
138                                 m1[M(2,j)] * m2[M(i,2)] +
139                                 m1[M(3,j)] * m2[M(i,3)];
140                 }
141         }
142 }
143
144 void gaw_push_matrix(void)
145 {
146         int top = st.mtop[st.mmode];
147         if(top >= STACK_SIZE) {
148                 fprintf(stderr, "push_matrix overflow\n");
149                 return;
150         }
151         memcpy(st.mat[st.mmode][top + 1], st.mat[st.mmode][top], 16 * sizeof(float));
152         st.mtop[st.mmode] = top + 1;
153 }
154
155 void gaw_pop_matrix(void)
156 {
157         if(st.mtop[st.mmode] <= 0) {
158                 fprintf(stderr, "pop_matrix underflow\n");
159                 return;
160         }
161         --st.mtop[st.mmode];
162 }
163
164 void gaw_get_modelview(float *m)
165 {
166         int top = st.mtop[GAW_MODELVIEW];
167         memcpy(m, st.mat[GAW_MODELVIEW][top], 16 * sizeof(float));
168 }
169
170 void gaw_get_projection(float *m)
171 {
172         int top = st.mtop[GAW_PROJECTION];
173         memcpy(m, st.mat[GAW_PROJECTION][top], 16 * sizeof(float));
174 }
175
176 void gaw_translate(float x, float y, float z)
177 {
178         static float m[16];
179         m[0] = m[5] = m[10] = m[15] = 1.0f;
180         m[12] = x;
181         m[13] = y;
182         m[14] = z;
183         gaw_mult_matrix(m);
184 }
185
186 void gaw_rotate(float deg, float x, float y, float z)
187 {
188         static float m[16];
189
190         float angle = M_PI * deg / 180.0f;
191         float sina = sin(angle);
192         float cosa = cos(angle);
193         float one_minus_cosa = 1.0f - cosa;
194         float nxsq = x * x;
195         float nysq = y * y;
196         float nzsq = z * z;
197
198         m[0] = nxsq + (1.0f - nxsq) * cosa;
199         m[4] = x * y * one_minus_cosa - z * sina;
200         m[8] = x * z * one_minus_cosa + y * sina;
201         m[1] = x * y * one_minus_cosa + z * sina;
202         m[5] = nysq + (1.0 - nysq) * cosa;
203         m[9] = y * z * one_minus_cosa - x * sina;
204         m[2] = x * z * one_minus_cosa - y * sina;
205         m[6] = y * z * one_minus_cosa + x * sina;
206         m[10] = nzsq + (1.0 - nzsq) * cosa;
207         m[15] = 1.0f;
208
209         gaw_mult_matrix(m);
210 }
211
212 void gaw_scale(float sx, float sy, float sz)
213 {
214         static float m[16];
215         m[0] = sx;
216         m[5] = sy;
217         m[10] = sz;
218         m[15] = 1.0f;
219         gaw_mult_matrix(m);
220 }
221
222 void gaw_ortho(float l, float r, float b, float t, float n, float f)
223 {
224         static float m[16];
225
226         float dx = r - l;
227         float dy = t - b;
228         float dz = f - n;
229
230         m[0] = 2.0 / dx;
231         m[5] = 2.0 / dy;
232         m[10] = -2.0 / dz;
233         m[12] = -(r + l) / dx;
234         m[13] = -(t + b) / dy;
235         m[14] = -(f + n) / dz;
236         m[15] = 1.0f;
237
238         gaw_mult_matrix(m);
239 }
240
241 void gaw_frustum(float left, float right, float bottom, float top, float zn, float zf)
242 {
243         static float m[16];
244
245         float dx = right - left;
246         float dy = top - bottom;
247         float dz = zf - zn;
248
249         float a = (right + left) / dx;
250         float b = (top + bottom) / dy;
251         float c = -(zf + zn) / dz;
252         float d = -2.0 * zf * zn / dz;
253
254         m[0] = 2.0 * zn / dx;
255         m[5] = 2.0 * zn / dy;
256         m[8] = a;
257         m[9] = b;
258         m[10] = c;
259         m[11] = -1.0f;
260         m[14] = d;
261
262         gaw_mult_matrix(m);
263 }
264
265 void gaw_perspective(float vfov_deg, float aspect, float znear, float zfar)
266 {
267         static float m[16];
268
269         float vfov = M_PI * vfov_deg / 180.0f;
270         float s = 1.0f / tan(vfov * 0.5f);
271         float range = znear - zfar;
272
273         m[0] = s / aspect;
274         m[5] = s;
275         m[10] = (znear + zfar) / range;
276         m[11] = -1.0f;
277         m[14] = 2.0f * znear * zfar / range;
278
279         gaw_mult_matrix(m);
280 }
281
282 void gaw_save(void)
283 {
284         if(st.savopt_top >= STACK_SIZE) {
285                 return;
286         }
287         st.savopt[st.savopt_top++] = st.opt;
288 }
289
290 void gaw_restore(void)
291 {
292         if(st.savopt_top <= 0) {
293                 return;
294         }
295         st.opt = st.savopt[--st.savopt_top];
296 }
297
298 void gaw_swtnl_enable(int what)
299 {
300         st.opt |= 1 << what;
301 }
302
303 void gaw_swtnl_disable(int what)
304 {
305         st.opt &= ~(1 << what);
306 }
307
308 void gaw_depth_func(int func)
309 {
310         /* TODO */
311 }
312
313 void gaw_blend_func(int src, int dest)
314 {
315         st.bsrc = src;
316         st.bdst = dest;
317 }
318
319 void gaw_alpha_func(int func, float ref)
320 {
321         /* TODO */
322 }
323
324 void gaw_zoffset(float offs)
325 {
326         st.zoffs = offs * 0.1;
327 }
328
329 #define CLAMP(x, a, b)          ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
330
331 void gaw_clear_color(float r, float g, float b, float a)
332 {
333         int ir = (int)(r * 255.0f);
334         int ig = (int)(g * 255.0f);
335         int ib = (int)(b * 255.0f);
336
337         ir = CLAMP(ir, 0, 255);
338         ig = CLAMP(ig, 0, 255);
339         ib = CLAMP(ib, 0, 255);
340
341         st.clear_color = PACK_RGB(ir, ig, ib);
342 }
343
344 void gaw_clear_depth(float z)
345 {
346         int iz = (int)(z * (float)0xffffff);
347         st.clear_depth = CLAMP(iz, 0, 0xffffff);
348 }
349
350 void gaw_swtnl_color_mask(int rmask, int gmask, int bmask, int amask)
351 {
352         /* TODO */
353 }
354
355 void gaw_swtnl_depth_mask(int mask)
356 {
357         /* TODO */
358 }
359
360 void gaw_vertex_array(int nelem, int stride, const void *ptr)
361 {
362         if(stride <= 0) {
363                 stride = nelem * sizeof(float);
364         }
365         st.vertex_nelem = nelem;
366         st.vertex_stride = stride;
367         st.vertex_ptr = ptr;
368 }
369
370 void gaw_normal_array(int stride, const void *ptr)
371 {
372         if(stride <= 0) {
373                 stride = 3 * sizeof(float);
374         }
375         st.normal_stride = stride;
376         st.normal_ptr = ptr;
377 }
378
379 void gaw_texcoord_array(int nelem, int stride, const void *ptr)
380 {
381         if(stride <= 0) {
382                 stride = nelem * sizeof(float);
383         }
384         st.texcoord_nelem = nelem;
385         st.texcoord_stride = stride;
386         st.texcoord_ptr = ptr;
387 }
388
389 void gaw_color_array(int nelem, int stride, const void *ptr)
390 {
391         if(stride <= 0) {
392                 stride = nelem * sizeof(float);
393         }
394         st.color_nelem = nelem;
395         st.color_stride = stride;
396         st.color_ptr = ptr;
397 }
398
399 void gaw_draw(int prim, int nverts)
400 {
401         gaw_draw_indexed(prim, 0, nverts);
402 }
403
404
405 #define NEED_NORMALS \
406         (st.opt & ((1 << GAW_LIGHTING) | (1 << GAW_SPHEREMAP)))
407
408 static int prim_vcount[] = {1, 2, 3, 4, 0};
409
410 void gaw_draw_indexed(int prim, const unsigned int *idxarr, int nidx)
411 {
412         int i, j, vidx, vnum, nfaces;
413         struct vertex v[16];
414         int mvtop = st.mtop[GAW_MODELVIEW];
415         int ptop = st.mtop[GAW_PROJECTION];
416         struct vertex *tmpv;
417         const float *vptr;
418
419         if(prim == GAW_QUAD_STRIP) return;      /* TODO */
420
421         if(st.cur_comp >= 0) {
422                 st.comp[st.cur_comp].prim = prim;
423         }
424
425         tmpv = alloca(prim * 6 * sizeof *tmpv);
426
427         /* calc the normal matrix */
428         if(NEED_NORMALS) {
429                 memcpy(st.norm_mat, st.mat[GAW_MODELVIEW][mvtop], 16 * sizeof(float));
430                 st.norm_mat[12] = st.norm_mat[13] = st.norm_mat[14] = 0.0f;
431         }
432
433         vidx = 0;
434         nfaces = nidx / prim_vcount[prim];
435
436         for(j=0; j<nfaces; j++) {
437                 vnum = prim_vcount[prim];       /* reset vnum for each iteration */
438
439                 for(i=0; i<vnum; i++) {
440                         if(idxarr) {
441                                 vidx = *idxarr++;
442                         }
443                         vptr = (const float*)((char*)st.vertex_ptr + vidx * st.vertex_stride);
444                         v[i].x = vptr[0];
445                         v[i].y = vptr[1];
446                         v[i].z = st.vertex_nelem > 2 ? vptr[2] : 0.0f;
447                         v[i].w = st.vertex_nelem > 3 ? vptr[3] : 1.0f;
448
449                         if(st.normal_ptr) {
450                                 vptr = (const float*)((char*)st.normal_ptr + vidx * st.normal_stride);
451                         } else {
452                                 vptr = &st.imm_curv.nx;
453                         }
454                         v[i].nx = vptr[0];
455                         v[i].ny = vptr[1];
456                         v[i].nz = vptr[2];
457
458                         if(st.texcoord_ptr) {
459                                 vptr = (const float*)((char*)st.texcoord_ptr + vidx * st.texcoord_stride);
460                         } else {
461                                 vptr = &st.imm_curv.u;
462                         }
463                         v[i].u = vptr[0];
464                         v[i].v = vptr[1];
465
466                         if(st.color_ptr) {
467                                 vptr = (const float*)((char*)st.color_ptr + vidx * st.color_stride);
468                         } else {
469                                 vptr = st.imm_curcol;
470                         }
471                         v[i].r = (int)(vptr[0] * 255.0f);
472                         v[i].g = (int)(vptr[1] * 255.0f);
473                         v[i].b = (int)(vptr[2] * 255.0f);
474                         v[i].a = st.color_nelem > 3 ? (int)(vptr[3] * 255.0f) : 255;
475
476                         vidx++;
477
478                         if(st.cur_comp >= 0) {
479                                 /* currently compiling geometry */
480                                 struct comp_geom *cg = st.comp + st.cur_comp;
481                                 float col[4];
482
483                                 col[0] = v[i].r / 255.0f;
484                                 col[1] = v[i].g / 255.0f;
485                                 col[2] = v[i].b / 255.0f;
486                                 col[3] = v[i].a / 255.0f;
487
488                                 darr_push(cg->varr, &v[i].x);
489                                 darr_push(cg->varr, &v[i].y);
490                                 darr_push(cg->varr, &v[i].z);
491                                 darr_push(cg->narr, &v[i].nx);
492                                 darr_push(cg->narr, &v[i].ny);
493                                 darr_push(cg->narr, &v[i].nz);
494                                 darr_push(cg->uvarr, &v[i].u);
495                                 darr_push(cg->uvarr, &v[i].v);
496                                 darr_push(cg->carr, col);
497                                 darr_push(cg->carr, col + 1);
498                                 darr_push(cg->carr, col + 2);
499                                 darr_push(cg->carr, col + 3);
500                                 continue;       /* don't transform, just skip to the next vertex */
501                         }
502
503                         xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &v[i].x);
504
505                         if(NEED_NORMALS) {
506                                 xform3_vec3(st.norm_mat, &v[i].nx);
507                                 if(st.opt & (1 << GAW_LIGHTING)) {
508                                         shade(v + i);
509                                 }
510                                 if(st.opt & (1 << GAW_SPHEREMAP)) {
511                                         v[i].u = v[i].nx * 0.5 + 0.5;
512                                         v[i].v = 0.5 - v[i].ny * 0.5;
513                                 }
514                         }
515                         {
516                                 float *mat = st.mat[GAW_TEXTURE][st.mtop[GAW_TEXTURE]];
517                                 float x = mat[0] * v[i].u + mat[4] * v[i].v + mat[12];
518                                 float y = mat[1] * v[i].u + mat[5] * v[i].v + mat[13];
519                                 float w = mat[3] * v[i].u + mat[7] * v[i].v + mat[15];
520                                 v[i].u = x / w;
521                                 v[i].v = y / w;
522                         }
523                         xform4_vec3(st.mat[GAW_PROJECTION][ptop], &v[i].x);
524                 }
525
526                 if(st.cur_comp >= 0) {
527                         /* compiling geometry, don't draw, skip to the next primitive */
528                         continue;
529                 }
530
531                 /* clipping */
532                 for(i=0; i<6; i++) {
533                         memcpy(tmpv, v, vnum * sizeof *v);
534
535                         if(clip_frustum(v, &vnum, tmpv, vnum, i) < 0) {
536                                 /* polygon completely outside of view volume. discard */
537                                 vnum = 0;
538                                 break;
539                         }
540                 }
541
542                 if(!vnum) continue;
543
544                 for(i=0; i<vnum; i++) {
545                         float oow = 1.0f / v[i].w;
546                         v[i].x *= oow;
547                         v[i].y *= oow;
548                         if(st.opt & (1 << GAW_POLYGON_OFFSET)) {
549                                 v[i].z += st.zoffs;
550                         }
551                         if(st.opt & (1 << GAW_DEPTH_TEST)) {
552                                 v[i].z *= oow;
553                         }
554                 }
555
556                 gaw_swtnl_drawprim(prim, v, vnum);
557         }
558 }
559
560 void gaw_begin(int prim)
561 {
562         st.imm_prim = prim;
563         st.imm_pcount = prim_vcount[st.imm_prim];
564         st.imm_numv = 0;
565 }
566
567 void gaw_end(void)
568 {
569         imm_flush();
570 }
571
572 static void imm_flush(void)
573 {
574         int numv = st.imm_numv;
575         st.imm_numv = 0;
576
577         gaw_vertex_array(3, sizeof(struct vertex), &st.imm_vbuf->x);
578         gaw_normal_array(sizeof(struct vertex), &st.imm_vbuf->nx);
579         gaw_texcoord_array(2, sizeof(struct vertex), &st.imm_vbuf->u);
580         gaw_color_array(4, 0, st.imm_cbuf);
581
582         gaw_draw_indexed(st.imm_prim, 0, numv);
583
584         gaw_vertex_array(0, 0, 0);
585         gaw_normal_array(0, 0);
586         gaw_texcoord_array(0, 0, 0);
587         gaw_color_array(0, 0, 0);
588 }
589
590 void gaw_color3f(float r, float g, float b)
591 {
592         gaw_color4f(r, g, b, 1.0f);
593 }
594
595 void gaw_color4f(float r, float g, float b, float a)
596 {
597         st.imm_curcol[0] = r;
598         st.imm_curcol[1] = g;
599         st.imm_curcol[2] = b;
600         st.imm_curcol[3] = a;
601 }
602
603 void gaw_color3ub(int r, int g, int b)
604 {
605         st.imm_curcol[0] = r / 255.0f;
606         st.imm_curcol[1] = g / 255.0f;
607         st.imm_curcol[2] = b / 255.0f;
608         st.imm_curcol[3] = 1.0f;
609 }
610
611 void gaw_normal(float x, float y, float z)
612 {
613         st.imm_curv.nx = x;
614         st.imm_curv.ny = y;
615         st.imm_curv.nz = z;
616 }
617
618 void gaw_texcoord1f(float u)
619 {
620         st.imm_curv.u = u;
621         st.imm_curv.v = 0.0f;
622 }
623
624 void gaw_texcoord2f(float u, float v)
625 {
626         st.imm_curv.u = u;
627         st.imm_curv.v = v;
628 }
629
630 void gaw_vertex2f(float x, float y)
631 {
632         gaw_vertex4f(x, y, 0, 1);
633 }
634
635 void gaw_vertex3f(float x, float y, float z)
636 {
637         gaw_vertex4f(x, y, z, 1);
638 }
639
640 void gaw_vertex4f(float x, float y, float z, float w)
641 {
642         float *cptr = st.imm_cbuf + st.imm_numv * 4;
643         struct vertex *vptr = st.imm_vbuf + st.imm_numv++;
644         *vptr = st.imm_curv;
645         vptr->x = x;
646         vptr->y = y;
647         vptr->z = z;
648         vptr->w = w;
649
650         cptr[0] = st.imm_curcol[0];
651         cptr[1] = st.imm_curcol[1];
652         cptr[2] = st.imm_curcol[2];
653         cptr[3] = st.imm_curcol[3];
654
655         if(!--st.imm_pcount) {
656                 if(st.imm_numv >= IMM_VBUF_SIZE - prim_vcount[st.imm_prim]) {
657                         imm_flush();
658                 }
659                 st.imm_pcount = prim_vcount[st.imm_prim];
660         }
661 }
662
663 void gaw_rect(float x1, float y1, float x2, float y2)
664 {
665         gaw_begin(GAW_QUADS);
666         gaw_vertex2f(x1, y1);
667         gaw_vertex2f(x2, y1);
668         gaw_vertex2f(x2, y2);
669         gaw_vertex2f(x1, y2);
670         gaw_end();
671 }
672
673
674 void gaw_pointsize(float sz)
675 {
676         /* TODO */
677 }
678
679 void gaw_linewidth(float w)
680 {
681         /* TODO */
682 }
683
684 int gaw_compile_begin(void)
685 {
686         int i;
687
688         st.cur_comp = -1;
689         for(i=0; i<MAX_COMPILED; i++) {
690                 if(st.comp[i].varr == 0) {
691                         st.cur_comp = i;
692                         break;
693                 }
694         }
695         if(st.cur_comp < 0) {
696                 return 0;
697         }
698
699         st.comp[i].prim = -1;
700         st.comp[i].varr = darr_alloc(0, sizeof(float));
701         st.comp[i].narr = darr_alloc(0, sizeof(float));
702         st.comp[i].uvarr = darr_alloc(0, sizeof(float));
703         st.comp[i].carr = darr_alloc(0, sizeof(float));
704
705         return st.cur_comp + 1;
706 }
707
708 void gaw_compile_end(void)
709 {
710         st.cur_comp = -1;
711 }
712
713 void gaw_draw_compiled(int id)
714 {
715         int idx = id - 1;
716
717         if(!st.comp[idx].varr || st.comp[idx].prim == -1) {
718                 return;
719         }
720
721         gaw_vertex_array(3, 0, st.comp[idx].varr);
722         gaw_normal_array(0, st.comp[idx].narr);
723         gaw_texcoord_array(2, 0, st.comp[idx].uvarr);
724         gaw_color_array(4, 0, st.comp[idx].carr);
725
726         gaw_draw(st.comp[idx].prim, darr_size(st.comp[idx].varr) / 3);
727
728         gaw_vertex_array(0, 0, 0);
729         gaw_normal_array(0, 0);
730         gaw_texcoord_array(0, 0, 0);
731         gaw_color_array(0, 0, 0);
732 }
733
734 void gaw_free_compiled(int id)
735 {
736         int idx = id - 1;
737
738         darr_free(st.comp[idx].varr);
739         darr_free(st.comp[idx].narr);
740         darr_free(st.comp[idx].uvarr);
741         darr_free(st.comp[idx].carr);
742         memset(st.comp + idx, 0, sizeof *st.comp);
743 }
744
745 void gaw_mtl_diffuse(float r, float g, float b, float a)
746 {
747         st.mtl.kd[0] = r;
748         st.mtl.kd[1] = g;
749         st.mtl.kd[2] = b;
750         st.mtl.kd[3] = a;
751 }
752
753 void gaw_mtl_specular(float r, float g, float b, float shin)
754 {
755         st.mtl.ks[0] = r;
756         st.mtl.ks[1] = g;
757         st.mtl.ks[2] = b;
758         st.mtl.shin = shin;
759 }
760
761 void gaw_mtl_emission(float r, float g, float b)
762 {
763         st.mtl.ke[0] = r;
764         st.mtl.ke[1] = g;
765         st.mtl.ke[2] = b;
766 }
767
768 void gaw_texenv_sphmap(int enable)
769 {
770         if(enable) {
771                 st.opt |= 1 << GAW_SPHEREMAP;
772         } else {
773                 st.opt &= ~(1 << GAW_SPHEREMAP);
774         }
775 }
776
777 void gaw_set_tex1d(unsigned int texid)
778 {
779         if(texid > 0) {
780                 gaw_bind_tex1d(texid);
781                 gaw_enable(GAW_TEXTURE_1D);
782         } else {
783                 st.cur_tex = -1;
784                 gaw_disable(GAW_TEXTURE_1D);
785         }
786 }
787
788 void gaw_set_tex2d(unsigned int texid)
789 {
790         if(texid > 0) {
791                 gaw_bind_tex2d(texid);
792                 gaw_enable(GAW_TEXTURE_2D);
793         } else {
794                 st.cur_tex = -1;
795                 gaw_disable(GAW_TEXTURE_2D);
796         }
797 }
798
799 void gaw_ambient(float r, float g, float b)
800 {
801         st.ambient[0] = r;
802         st.ambient[1] = g;
803         st.ambient[2] = b;
804 }
805
806 void gaw_light_pos(int idx, float x, float y, float z)
807 {
808         int mvtop = st.mtop[GAW_MODELVIEW];
809
810         st.lt[idx].type = LT_POS;
811         st.lt[idx].x = x;
812         st.lt[idx].y = y;
813         st.lt[idx].z = z;
814
815         xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &st.lt[idx].x);
816 }
817
818 void gaw_light_dir(int idx, float x, float y, float z)
819 {
820         int mvtop = st.mtop[GAW_MODELVIEW];
821
822         st.lt[idx].type = LT_DIR;
823         st.lt[idx].x = x;
824         st.lt[idx].y = y;
825         st.lt[idx].z = z;
826
827         /* calc the normal matrix */
828         memcpy(st.norm_mat, st.mat[GAW_MODELVIEW][mvtop], 16 * sizeof(float));
829         st.norm_mat[12] = st.norm_mat[13] = st.norm_mat[14] = 0.0f;
830
831         xform4_vec3(st.norm_mat, &st.lt[idx].x);
832
833         NORMALIZE(&st.lt[idx].x);
834 }
835
836 void gaw_light_color(int idx, float r, float g, float b, float s)
837 {
838         st.lt[idx].r = r;
839         st.lt[idx].g = g;
840         st.lt[idx].b = b;
841 }
842
843 void gaw_lighting_fast(void)
844 {
845 }
846
847 void gaw_fog_color(float r, float g, float b)
848 {
849 }
850
851 void gaw_fog_linear(float z0, float z1)
852 {
853 }
854
855 void gaw_fog_fast(void)
856 {
857 }
858
859
860 void gaw_poly_wire(void)
861 {
862         st.polymode = POLYFILL_WIRE;
863 }
864
865 void gaw_poly_flat(void)
866 {
867         st.polymode = POLYFILL_FLAT;
868 }
869
870 void gaw_poly_gouraud(void)
871 {
872         st.polymode = POLYFILL_GOURAUD;
873 }
874
875
876 static __inline void xform4_vec3(const float *mat, float *vec)
877 {
878         float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12];
879         float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13];
880         float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
881         vec[3] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
882         vec[2] = z;
883         vec[1] = y;
884         vec[0] = x;
885 }
886
887 static __inline void xform3_vec3(const float *mat, float *vec)
888 {
889         float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2];
890         float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2];
891         vec[2] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2];
892         vec[1] = y;
893         vec[0] = x;
894 }
895
896 static void shade(struct vertex *v)
897 {
898         int i, r, g, b;
899         float color[3];
900
901         color[0] = st.ambient[0] * st.mtl.kd[0];
902         color[1] = st.ambient[1] * st.mtl.kd[1];
903         color[2] = st.ambient[2] * st.mtl.kd[2];
904
905         for(i=0; i<MAX_LIGHTS; i++) {
906                 float ldir[3];
907                 float ndotl;
908
909                 if(!(st.opt & (GAW_LIGHT0 << i))) {
910                         continue;
911                 }
912
913                 ldir[0] = st.lt[i].x;
914                 ldir[1] = st.lt[i].y;
915                 ldir[2] = st.lt[i].z;
916
917                 if(st.lt[i].type != LT_DIR) {
918                         ldir[0] -= v->x;
919                         ldir[1] -= v->y;
920                         ldir[2] -= v->z;
921                         NORMALIZE(ldir);
922                 }
923
924                 if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
925                         ndotl = 0.0f;
926                 }
927
928                 color[0] += st.mtl.kd[0] * st.lt[i].r * ndotl;
929                 color[1] += st.mtl.kd[1] * st.lt[i].g * ndotl;
930                 color[2] += st.mtl.kd[2] * st.lt[i].b * ndotl;
931
932                 /*
933                 if(st.opt & (1 << GAW_SPECULAR)) {
934                         float ndoth;
935                         ldir[2] += 1.0f;
936                         NORMALIZE(ldir);
937                         if((ndoth = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
938                                 ndoth = 0.0f;
939                         }
940                         ndoth = pow(ndoth, st.mtl.shin);
941
942                         color[0] += st.mtl.ks[0] * st.lt[i].r * ndoth;
943                         color[1] += st.mtl.ks[1] * st.lt[i].g * ndoth;
944                         color[2] += st.mtl.ks[2] * st.lt[i].b * ndoth;
945                 }
946                 */
947         }
948
949         r = cround64(color[0] * 255.0);
950         g = cround64(color[1] * 255.0);
951         b = cround64(color[2] * 255.0);
952
953         v->r = r > 255 ? 255 : r;
954         v->g = g > 255 ? 255 : g;
955         v->b = b > 255 ? 255 : b;
956 }