added lighting
[dosdemo] / src / polytest.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include "screen.h"
6 #include "demo.h"
7 #include "3dgfx.h"
8 #include "gfxutil.h"
9
10 struct mesh {
11         int prim;
12         struct g3d_vertex *varr;
13         int16_t *iarr;
14         int vcount, icount;
15 };
16
17 static int init(void);
18 static void destroy(void);
19 static void start(long trans_time);
20 static void draw(void);
21 static void draw_mesh(struct mesh *mesh);
22 static int gen_cube(struct mesh *mesh, float sz);
23 static int gen_torus(struct mesh *mesh, float rad, float ringrad, int usub, int vsub);
24 static void zsort(struct mesh *m);
25 static void draw_lowres_raster(void);
26
27 static struct screen scr = {
28         "polytest",
29         init,
30         destroy,
31         start, 0,
32         draw
33 };
34
35 static float theta, phi = 25;
36 static struct mesh cube, torus;
37
38 #define LOWRES_SCALE    10
39 static uint16_t *lowres_pixels;
40 static int lowres_width, lowres_height;
41
42 struct screen *polytest_screen(void)
43 {
44         return &scr;
45 }
46
47 static int init(void)
48 {
49         gen_cube(&cube, 1.0);
50         gen_torus(&torus, 1.0, 0.25, 24, 12);
51
52 #ifdef DEBUG_POLYFILL
53         lowres_width = fb_width / LOWRES_SCALE;
54         lowres_height = fb_height / LOWRES_SCALE;
55         lowres_pixels = malloc(lowres_width * lowres_height * 2);
56         scr.draw = draw_debug;
57 #endif
58
59         return 0;
60 }
61
62 static void destroy(void)
63 {
64         free(lowres_pixels);
65         free(cube.varr);
66         free(torus.varr);
67         free(torus.iarr);
68 }
69
70 static void start(long trans_time)
71 {
72         g3d_matrix_mode(G3D_PROJECTION);
73         g3d_load_identity();
74         g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
75
76         g3d_enable(G3D_CULL_FACE);
77         g3d_enable(G3D_LIGHTING);
78         g3d_enable(G3D_LIGHT0);
79 }
80
81 static void update(void)
82 {
83         static int prev_mx, prev_my;
84         static unsigned int prev_bmask;
85
86         if(mouse_bmask) {
87                 if((mouse_bmask ^ prev_bmask) == 0) {
88                         int dx = mouse_x - prev_mx;
89                         int dy = mouse_y - prev_my;
90
91                         if(dx || dy) {
92                                 theta += dx * 2.0;
93                                 phi += dy * 2.0;
94
95                                 if(phi < -90) phi = -90;
96                                 if(phi > 90) phi = 90;
97                         }
98                 }
99         }
100         prev_mx = mouse_x;
101         prev_my = mouse_y;
102         prev_bmask = mouse_bmask;
103 }
104
105
106 static void draw(void)
107 {
108         update();
109
110         memset(fb_pixels, 0, fb_width * fb_height * 2);
111
112         g3d_matrix_mode(G3D_MODELVIEW);
113         g3d_load_identity();
114         g3d_translate(0, 0, -3);
115         g3d_rotate(phi, 1, 0, 0);
116         g3d_rotate(theta, 0, 1, 0);
117
118         g3d_light_pos(0, -10, 10, 20);
119
120         zsort(&torus);
121
122         g3d_mtl_diffuse(0.3, 0.6, 1.0);
123         draw_mesh(&torus);
124
125         /*draw_mesh(&cube);*/
126         swap_buffers(fb_pixels);
127 }
128
129 static void draw_debug(void)
130 {
131         update();
132
133         memset(lowres_pixels, 0, lowres_width * lowres_height * 2);
134
135         g3d_matrix_mode(G3D_MODELVIEW);
136         g3d_load_identity();
137         g3d_translate(0, 0, -3);
138         g3d_rotate(phi, 1, 0, 0);
139         g3d_rotate(theta, 0, 1, 0);
140
141         g3d_framebuffer(lowres_width, lowres_height, lowres_pixels);
142         /*zsort(&torus);*/
143         draw_mesh(&cube);
144
145         draw_lowres_raster();
146
147
148         g3d_framebuffer(fb_width, fb_height, fb_pixels);
149
150         g3d_polygon_mode(G3D_WIRE);
151         draw_mesh(&cube);
152         g3d_polygon_mode(G3D_FLAT);
153
154         swap_buffers(fb_pixels);
155 }
156
157 static void draw_mesh(struct mesh *mesh)
158 {
159         if(mesh->iarr) {
160                 g3d_draw_indexed(mesh->prim, mesh->varr, mesh->vcount, mesh->iarr, mesh->icount);
161         } else {
162                 g3d_draw(mesh->prim, mesh->varr, mesh->vcount);
163         }
164 }
165
166 #define NORMAL(vp, x, y, z) do { vp->nx = x; vp->ny = y; vp->nz = z; } while(0)
167 #define COLOR(vp, cr, cg, cb) do { vp->r = cr; vp->g = cg; vp->b = cb; } while(0)
168 #define TEXCOORD(vp, tu, tv) do { vp->u = tu; vp->v = tv; } while(0)
169 #define VERTEX(vp, vx, vy, vz) \
170         do { \
171                 vp->x = vx; vp->y = vy; vp->z = vz; vp->w = 1.0f; \
172                 ++vp; \
173         } while(0)
174
175 static int gen_cube(struct mesh *mesh, float sz)
176 {
177         struct g3d_vertex *vptr;
178         float hsz = sz / 2.0;
179
180         mesh->prim = G3D_QUADS;
181         mesh->iarr = 0;
182         mesh->icount = 0;
183
184         mesh->vcount = 24;
185         if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
186                 return -1;
187         }
188         vptr = mesh->varr;
189
190         /* -Z */
191         NORMAL(vptr, 0, 0, -1);
192         COLOR(vptr, 255, 0, 255);
193         VERTEX(vptr, hsz, -hsz, -hsz);
194         VERTEX(vptr, -hsz, -hsz, -hsz);
195         VERTEX(vptr, -hsz, hsz, -hsz);
196         VERTEX(vptr, hsz, hsz, -hsz);
197         /* -Y */
198         NORMAL(vptr, 0, -1, 0);
199         COLOR(vptr, 0, 255, 255);
200         VERTEX(vptr, -hsz, -hsz, -hsz);
201         VERTEX(vptr, hsz, -hsz, -hsz);
202         VERTEX(vptr, hsz, -hsz, hsz);
203         VERTEX(vptr, -hsz, -hsz, hsz);
204         /* -X */
205         NORMAL(vptr, -1, 0, 0);
206         COLOR(vptr, 255, 255, 0);
207         VERTEX(vptr, -hsz, -hsz, -hsz);
208         VERTEX(vptr, -hsz, -hsz, hsz);
209         VERTEX(vptr, -hsz, hsz, hsz);
210         VERTEX(vptr, -hsz, hsz, -hsz);
211         /* +X */
212         NORMAL(vptr, 1, 0, 0);
213         COLOR(vptr, 255, 0, 0);
214         VERTEX(vptr, hsz, -hsz, hsz);
215         VERTEX(vptr, hsz, -hsz, -hsz);
216         VERTEX(vptr, hsz, hsz, -hsz);
217         VERTEX(vptr, hsz, hsz, hsz);
218         /* +Y */
219         NORMAL(vptr, 0, 1, 0);
220         COLOR(vptr, 0, 255, 0);
221         VERTEX(vptr, -hsz, hsz, hsz);
222         VERTEX(vptr, hsz, hsz, hsz);
223         VERTEX(vptr, hsz, hsz, -hsz);
224         VERTEX(vptr, -hsz, hsz, -hsz);
225         /* +Z */
226         NORMAL(vptr, 0, 0, 1);
227         COLOR(vptr, 0, 0, 255);
228         VERTEX(vptr, -hsz, -hsz, hsz);
229         VERTEX(vptr, hsz, -hsz, hsz);
230         VERTEX(vptr, hsz, hsz, hsz);
231         VERTEX(vptr, -hsz, hsz, hsz);
232
233         return 0;
234 }
235
236 static void torusvec(float *res, float theta, float phi, float mr, float rr)
237 {
238         float rx, ry, rz;
239         theta = -theta;
240
241         rx = -cos(phi) * rr + mr;
242         ry = sin(phi) * rr;
243         rz = 0.0f;
244
245         res[0] = rx * sin(theta) + rz * cos(theta);
246         res[1] = ry;
247         res[2] = -rx * cos(theta) + rz * sin(theta);
248 }
249
250 static int gen_torus(struct mesh *mesh, float rad, float ringrad, int usub, int vsub)
251 {
252         int i, j;
253         int nfaces, uverts, vverts;
254         struct g3d_vertex *vptr;
255         int16_t *iptr;
256
257         mesh->prim = G3D_QUADS;
258
259         if(usub < 4) usub = 4;
260         if(vsub < 2) vsub = 2;
261
262         uverts = usub + 1;
263         vverts = vsub + 1;
264
265         mesh->vcount = uverts * vverts;
266         nfaces = usub * vsub;
267         mesh->icount = nfaces * 4;
268
269         if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
270                 return -1;
271         }
272         if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
273                 return -1;
274         }
275         vptr = mesh->varr;
276         iptr = mesh->iarr;
277
278         for(i=0; i<uverts; i++) {
279                 float u = (float)i / (float)(uverts - 1);
280                 float theta = u * 2.0 * M_PI;
281                 float rcent[3];
282
283                 torusvec(rcent, theta, 0, rad, 0);
284
285                 for(j=0; j<vverts; j++) {
286                         float v = (float)j / (float)(vverts - 1);
287                         float phi = v * 2.0 * M_PI;
288                         int chess = (i & 1) == (j & 1);
289
290                         torusvec(&vptr->x, theta, phi, rad, ringrad);
291
292                         vptr->nx = (vptr->x - rcent[0]) / ringrad;
293                         vptr->ny = (vptr->y - rcent[1]) / ringrad;
294                         vptr->nz = (vptr->z - rcent[2]) / ringrad;
295                         vptr->u = u;
296                         vptr->v = v;
297                         vptr->r = chess ? 255 : 64;
298                         vptr->g = 128;
299                         vptr->b = chess ? 64 : 255;
300                         ++vptr;
301
302                         if(i < usub && j < vsub) {
303                                 int idx = i * vverts + j;
304                                 *iptr++ = idx;
305                                 *iptr++ = idx + 1;
306                                 *iptr++ = idx + vverts + 1;
307                                 *iptr++ = idx + vverts;
308                         }
309                 }
310         }
311         return 0;
312 }
313
314
315 static struct {
316         struct g3d_vertex *varr;
317         const float *xform;
318 } zsort_cls;
319
320 static int zsort_cmp(const void *aptr, const void *bptr)
321 {
322         const int16_t *a = (const int16_t*)aptr;
323         const int16_t *b = (const int16_t*)bptr;
324
325         const float *m = zsort_cls.xform;
326
327         const struct g3d_vertex *va = zsort_cls.varr + a[0];
328         const struct g3d_vertex *vb = zsort_cls.varr + b[0];
329
330         float za = m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
331         float zb = m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
332
333         va = zsort_cls.varr + a[2];
334         vb = zsort_cls.varr + b[2];
335
336         za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
337         zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
338
339         return za - zb;
340 }
341
342 static void zsort(struct mesh *m)
343 {
344         int nfaces = m->icount / m->prim;
345
346         zsort_cls.varr = m->varr;
347         zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
348
349         qsort(m->iarr, nfaces, m->prim * sizeof *m->iarr, zsort_cmp);
350 }
351
352 static void draw_huge_pixel(uint16_t *dest, int dest_width, uint16_t color)
353 {
354         int i, j;
355         uint16_t grid_color = PACK_RGB16(127, 127, 127);
356
357         for(i=0; i<LOWRES_SCALE; i++) {
358                 for(j=0; j<LOWRES_SCALE; j++) {
359                         dest[j] = i == 0 || j == 0 ? grid_color : color;
360                 }
361                 dest += dest_width;
362         }
363 }
364
365 static void draw_lowres_raster(void)
366 {
367         int i, j;
368         uint16_t *sptr = lowres_pixels;
369         uint16_t *dptr = fb_pixels;
370
371         for(i=0; i<lowres_height; i++) {
372                 for(j=0; j<lowres_width; j++) {
373                         draw_huge_pixel(dptr, fb_width, *sptr++);
374                         dptr += LOWRES_SCALE;
375                 }
376                 dptr += fb_width * LOWRES_SCALE - fb_width;
377         }
378 }