5e556217d93e4438abf0ae37693acd1b6f20e801
[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 #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                         float oow = 1.0f / v[i].w;
536                         v[i].x *= oow;
537                         v[i].y *= oow;
538                         if(st.opt & (1 << GAW_DEPTH_TEST)) {
539                                 v[i].z *= oow;
540                         }
541                 }
542
543                 gaw_swtnl_drawprim(prim, v, vnum);
544         }
545 }
546
547 void gaw_begin(int prim)
548 {
549         st.imm_prim = prim;
550         st.imm_pcount = prim_vcount[st.imm_prim];
551         st.imm_numv = 0;
552 }
553
554 void gaw_end(void)
555 {
556         imm_flush();
557 }
558
559 static void imm_flush(void)
560 {
561         int numv = st.imm_numv;
562         st.imm_numv = 0;
563
564         gaw_vertex_array(3, sizeof(struct vertex), &st.imm_vbuf->x);
565         gaw_normal_array(sizeof(struct vertex), &st.imm_vbuf->nx);
566         gaw_texcoord_array(2, sizeof(struct vertex), &st.imm_vbuf->u);
567         gaw_color_array(4, 0, st.imm_cbuf);
568
569         gaw_draw_indexed(st.imm_prim, 0, numv);
570
571         gaw_vertex_array(0, 0, 0);
572         gaw_normal_array(0, 0);
573         gaw_texcoord_array(0, 0, 0);
574         gaw_color_array(0, 0, 0);
575 }
576
577 void gaw_color3f(float r, float g, float b)
578 {
579         gaw_color4f(r, g, b, 1.0f);
580 }
581
582 void gaw_color4f(float r, float g, float b, float a)
583 {
584         st.imm_curcol[0] = r;
585         st.imm_curcol[1] = g;
586         st.imm_curcol[2] = b;
587         st.imm_curcol[3] = a;
588 }
589
590 void gaw_color3ub(int r, int g, int b)
591 {
592         st.imm_curcol[0] = r / 255.0f;
593         st.imm_curcol[1] = g / 255.0f;
594         st.imm_curcol[2] = b / 255.0f;
595         st.imm_curcol[3] = 1.0f;
596 }
597
598 void gaw_normal(float x, float y, float z)
599 {
600         st.imm_curv.nx = x;
601         st.imm_curv.ny = y;
602         st.imm_curv.nz = z;
603 }
604
605 void gaw_texcoord1f(float u)
606 {
607         st.imm_curv.u = u;
608         st.imm_curv.v = 0.0f;
609 }
610
611 void gaw_texcoord2f(float u, float v)
612 {
613         st.imm_curv.u = u;
614         st.imm_curv.v = v;
615 }
616
617 void gaw_vertex2f(float x, float y)
618 {
619         gaw_vertex4f(x, y, 0, 1);
620 }
621
622 void gaw_vertex3f(float x, float y, float z)
623 {
624         gaw_vertex4f(x, y, z, 1);
625 }
626
627 void gaw_vertex4f(float x, float y, float z, float w)
628 {
629         float *cptr = st.imm_cbuf + st.imm_numv * 4;
630         struct vertex *vptr = st.imm_vbuf + st.imm_numv++;
631         *vptr = st.imm_curv;
632         vptr->x = x;
633         vptr->y = y;
634         vptr->z = z;
635         vptr->w = w;
636
637         cptr[0] = st.imm_curcol[0];
638         cptr[1] = st.imm_curcol[1];
639         cptr[2] = st.imm_curcol[2];
640         cptr[3] = st.imm_curcol[3];
641
642         if(!--st.imm_pcount) {
643                 if(st.imm_numv >= IMM_VBUF_SIZE - prim_vcount[st.imm_prim]) {
644                         imm_flush();
645                 }
646                 st.imm_pcount = prim_vcount[st.imm_prim];
647         }
648 }
649
650 void gaw_rect(float x1, float y1, float x2, float y2)
651 {
652         gaw_begin(GAW_QUADS);
653         gaw_vertex2f(x1, y1);
654         gaw_vertex2f(x2, y1);
655         gaw_vertex2f(x2, y2);
656         gaw_vertex2f(x1, y2);
657         gaw_end();
658 }
659
660
661 void gaw_pointsize(float sz)
662 {
663         /* TODO */
664 }
665
666 void gaw_linewidth(float w)
667 {
668         /* TODO */
669 }
670
671 int gaw_compile_begin(void)
672 {
673         int i;
674
675         st.cur_comp = -1;
676         for(i=0; i<MAX_COMPILED; i++) {
677                 if(st.comp[i].varr == 0) {
678                         st.cur_comp = i;
679                         break;
680                 }
681         }
682         if(st.cur_comp < 0) {
683                 return 0;
684         }
685
686         st.comp[i].prim = -1;
687         st.comp[i].varr = darr_alloc(0, sizeof(float));
688         st.comp[i].narr = darr_alloc(0, sizeof(float));
689         st.comp[i].uvarr = darr_alloc(0, sizeof(float));
690         st.comp[i].carr = darr_alloc(0, sizeof(float));
691
692         return st.cur_comp + 1;
693 }
694
695 void gaw_compile_end(void)
696 {
697         st.cur_comp = -1;
698 }
699
700 void gaw_draw_compiled(int id)
701 {
702         int idx = id - 1;
703
704         if(!st.comp[idx].varr || st.comp[idx].prim == -1) {
705                 return;
706         }
707
708         gaw_vertex_array(3, 0, st.comp[idx].varr);
709         gaw_normal_array(0, st.comp[idx].narr);
710         gaw_texcoord_array(2, 0, st.comp[idx].uvarr);
711         gaw_color_array(4, 0, st.comp[idx].carr);
712
713         gaw_draw(st.comp[idx].prim, darr_size(st.comp[idx].varr) / 3);
714
715         gaw_vertex_array(0, 0, 0);
716         gaw_normal_array(0, 0);
717         gaw_texcoord_array(0, 0, 0);
718         gaw_color_array(0, 0, 0);
719 }
720
721 void gaw_free_compiled(int id)
722 {
723         int idx = id - 1;
724
725         darr_free(st.comp[idx].varr);
726         darr_free(st.comp[idx].narr);
727         darr_free(st.comp[idx].uvarr);
728         darr_free(st.comp[idx].carr);
729         memset(st.comp + idx, 0, sizeof *st.comp);
730 }
731
732 void gaw_mtl_diffuse(float r, float g, float b, float a)
733 {
734         st.mtl.kd[0] = r;
735         st.mtl.kd[1] = g;
736         st.mtl.kd[2] = b;
737         st.mtl.kd[3] = a;
738 }
739
740 void gaw_mtl_specular(float r, float g, float b, float shin)
741 {
742         st.mtl.ks[0] = r;
743         st.mtl.ks[1] = g;
744         st.mtl.ks[2] = b;
745         st.mtl.shin = shin;
746 }
747
748 void gaw_mtl_emission(float r, float g, float b)
749 {
750         st.mtl.ke[0] = r;
751         st.mtl.ke[1] = g;
752         st.mtl.ke[2] = b;
753 }
754
755 void gaw_texenv_sphmap(int enable)
756 {
757         if(enable) {
758                 st.opt |= 1 << GAW_SPHEREMAP;
759         } else {
760                 st.opt &= ~(1 << GAW_SPHEREMAP);
761         }
762 }
763
764 void gaw_set_tex1d(unsigned int texid)
765 {
766         if(texid > 0) {
767                 gaw_bind_tex1d(texid);
768                 gaw_enable(GAW_TEXTURE_1D);
769         } else {
770                 st.cur_tex = -1;
771                 gaw_disable(GAW_TEXTURE_1D);
772         }
773 }
774
775 void gaw_set_tex2d(unsigned int texid)
776 {
777         if(texid > 0) {
778                 gaw_bind_tex2d(texid);
779                 gaw_enable(GAW_TEXTURE_2D);
780         } else {
781                 st.cur_tex = -1;
782                 gaw_disable(GAW_TEXTURE_2D);
783         }
784 }
785
786 void gaw_ambient(float r, float g, float b)
787 {
788         st.ambient[0] = r;
789         st.ambient[1] = g;
790         st.ambient[2] = b;
791 }
792
793 void gaw_light_pos(int idx, float x, float y, float z)
794 {
795         int mvtop = st.mtop[GAW_MODELVIEW];
796
797         st.lt[idx].type = LT_POS;
798         st.lt[idx].x = x;
799         st.lt[idx].y = y;
800         st.lt[idx].z = z;
801
802         xform4_vec3(st.mat[GAW_MODELVIEW][mvtop], &st.lt[idx].x);
803 }
804
805 void gaw_light_dir(int idx, float x, float y, float z)
806 {
807         int mvtop = st.mtop[GAW_MODELVIEW];
808
809         st.lt[idx].type = LT_DIR;
810         st.lt[idx].x = x;
811         st.lt[idx].y = y;
812         st.lt[idx].z = z;
813
814         /* calc the normal matrix */
815         memcpy(st.norm_mat, st.mat[GAW_MODELVIEW][mvtop], 16 * sizeof(float));
816         st.norm_mat[12] = st.norm_mat[13] = st.norm_mat[14] = 0.0f;
817
818         xform4_vec3(st.norm_mat, &st.lt[idx].x);
819
820         NORMALIZE(&st.lt[idx].x);
821 }
822
823 void gaw_light_color(int idx, float r, float g, float b, float s)
824 {
825         st.lt[idx].r = r;
826         st.lt[idx].g = g;
827         st.lt[idx].b = b;
828 }
829
830 void gaw_lighting_fast(void)
831 {
832 }
833
834 void gaw_fog_color(float r, float g, float b)
835 {
836 }
837
838 void gaw_fog_linear(float z0, float z1)
839 {
840 }
841
842 void gaw_fog_fast(void)
843 {
844 }
845
846
847 void gaw_poly_wire(void)
848 {
849         st.polymode = POLYFILL_WIRE;
850 }
851
852 void gaw_poly_flat(void)
853 {
854         st.polymode = POLYFILL_FLAT;
855 }
856
857 void gaw_poly_gouraud(void)
858 {
859         st.polymode = POLYFILL_GOURAUD;
860 }
861
862
863 static __inline void xform4_vec3(const float *mat, float *vec)
864 {
865         float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12];
866         float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13];
867         float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
868         vec[3] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
869         vec[2] = z;
870         vec[1] = y;
871         vec[0] = x;
872 }
873
874 static __inline void xform3_vec3(const float *mat, float *vec)
875 {
876         float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2];
877         float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2];
878         vec[2] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2];
879         vec[1] = y;
880         vec[0] = x;
881 }
882
883 static void shade(struct vertex *v)
884 {
885         int i, r, g, b;
886         float color[3];
887
888         color[0] = st.ambient[0] * st.mtl.kd[0];
889         color[1] = st.ambient[1] * st.mtl.kd[1];
890         color[2] = st.ambient[2] * st.mtl.kd[2];
891
892         for(i=0; i<MAX_LIGHTS; i++) {
893                 float ldir[3];
894                 float ndotl;
895
896                 if(!(st.opt & (GAW_LIGHT0 << i))) {
897                         continue;
898                 }
899
900                 ldir[0] = st.lt[i].x;
901                 ldir[1] = st.lt[i].y;
902                 ldir[2] = st.lt[i].z;
903
904                 if(st.lt[i].type != LT_DIR) {
905                         ldir[0] -= v->x;
906                         ldir[1] -= v->y;
907                         ldir[2] -= v->z;
908                         NORMALIZE(ldir);
909                 }
910
911                 if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
912                         ndotl = 0.0f;
913                 }
914
915                 color[0] += st.mtl.kd[0] * st.lt[i].r * ndotl;
916                 color[1] += st.mtl.kd[1] * st.lt[i].g * ndotl;
917                 color[2] += st.mtl.kd[2] * st.lt[i].b * ndotl;
918
919                 /*
920                 if(st.opt & (1 << GAW_SPECULAR)) {
921                         float ndoth;
922                         ldir[2] += 1.0f;
923                         NORMALIZE(ldir);
924                         if((ndoth = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
925                                 ndoth = 0.0f;
926                         }
927                         ndoth = pow(ndoth, st.mtl.shin);
928
929                         color[0] += st.mtl.ks[0] * st.lt[i].r * ndoth;
930                         color[1] += st.mtl.ks[1] * st.lt[i].g * ndoth;
931                         color[2] += st.mtl.ks[2] * st.lt[i].b * ndoth;
932                 }
933                 */
934         }
935
936         r = cround64(color[0] * 255.0);
937         g = cround64(color[1] * 255.0);
938         b = cround64(color[2] * 255.0);
939
940         v->r = r > 255 ? 255 : r;
941         v->g = g > 255 ? 255 : g;
942         v->b = b > 255 ? 255 : b;
943 }