split the polyfiller to a preprocessor-based template file, included
[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         g3d_polygon_mode(G3D_GOURAUD);
81 }
82
83 static void update(void)
84 {
85         static int prev_mx, prev_my;
86         static unsigned int prev_bmask;
87
88         if(mouse_bmask) {
89                 if((mouse_bmask ^ prev_bmask) == 0) {
90                         int dx = mouse_x - prev_mx;
91                         int dy = mouse_y - prev_my;
92
93                         if(dx || dy) {
94                                 theta += dx * 2.0;
95                                 phi += dy * 2.0;
96
97                                 if(phi < -90) phi = -90;
98                                 if(phi > 90) phi = 90;
99                         }
100                 }
101         }
102         prev_mx = mouse_x;
103         prev_my = mouse_y;
104         prev_bmask = mouse_bmask;
105 }
106
107
108 static void draw(void)
109 {
110         update();
111
112         memset(fb_pixels, 0, fb_width * fb_height * 2);
113
114         g3d_matrix_mode(G3D_MODELVIEW);
115         g3d_load_identity();
116         g3d_translate(0, 0, -3);
117         g3d_rotate(phi, 1, 0, 0);
118         g3d_rotate(theta, 0, 1, 0);
119
120         g3d_light_pos(0, -10, 10, 20);
121
122         zsort(&torus);
123
124         g3d_mtl_diffuse(0.3, 0.6, 1.0);
125         draw_mesh(&torus);
126
127         /*draw_mesh(&cube);*/
128         swap_buffers(fb_pixels);
129 }
130
131 static void draw_debug(void)
132 {
133         update();
134
135         memset(lowres_pixels, 0, lowres_width * lowres_height * 2);
136
137         g3d_matrix_mode(G3D_MODELVIEW);
138         g3d_load_identity();
139         g3d_translate(0, 0, -3);
140         g3d_rotate(phi, 1, 0, 0);
141         g3d_rotate(theta, 0, 1, 0);
142
143         g3d_framebuffer(lowres_width, lowres_height, lowres_pixels);
144         /*zsort(&torus);*/
145         draw_mesh(&cube);
146
147         draw_lowres_raster();
148
149
150         g3d_framebuffer(fb_width, fb_height, fb_pixels);
151
152         g3d_polygon_mode(G3D_WIRE);
153         draw_mesh(&cube);
154         g3d_polygon_mode(G3D_FLAT);
155
156         swap_buffers(fb_pixels);
157 }
158
159 static void draw_mesh(struct mesh *mesh)
160 {
161         if(mesh->iarr) {
162                 g3d_draw_indexed(mesh->prim, mesh->varr, mesh->vcount, mesh->iarr, mesh->icount);
163         } else {
164                 g3d_draw(mesh->prim, mesh->varr, mesh->vcount);
165         }
166 }
167
168 #define NORMAL(vp, x, y, z) do { vp->nx = x; vp->ny = y; vp->nz = z; } while(0)
169 #define COLOR(vp, cr, cg, cb) do { vp->r = cr; vp->g = cg; vp->b = cb; } while(0)
170 #define TEXCOORD(vp, tu, tv) do { vp->u = tu; vp->v = tv; } while(0)
171 #define VERTEX(vp, vx, vy, vz) \
172         do { \
173                 vp->x = vx; vp->y = vy; vp->z = vz; vp->w = 1.0f; \
174                 ++vp; \
175         } while(0)
176
177 static int gen_cube(struct mesh *mesh, float sz)
178 {
179         struct g3d_vertex *vptr;
180         float hsz = sz / 2.0;
181
182         mesh->prim = G3D_QUADS;
183         mesh->iarr = 0;
184         mesh->icount = 0;
185
186         mesh->vcount = 24;
187         if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
188                 return -1;
189         }
190         vptr = mesh->varr;
191
192         /* -Z */
193         NORMAL(vptr, 0, 0, -1);
194         COLOR(vptr, 255, 0, 255);
195         VERTEX(vptr, hsz, -hsz, -hsz);
196         VERTEX(vptr, -hsz, -hsz, -hsz);
197         VERTEX(vptr, -hsz, hsz, -hsz);
198         VERTEX(vptr, hsz, hsz, -hsz);
199         /* -Y */
200         NORMAL(vptr, 0, -1, 0);
201         COLOR(vptr, 0, 255, 255);
202         VERTEX(vptr, -hsz, -hsz, -hsz);
203         VERTEX(vptr, hsz, -hsz, -hsz);
204         VERTEX(vptr, hsz, -hsz, hsz);
205         VERTEX(vptr, -hsz, -hsz, hsz);
206         /* -X */
207         NORMAL(vptr, -1, 0, 0);
208         COLOR(vptr, 255, 255, 0);
209         VERTEX(vptr, -hsz, -hsz, -hsz);
210         VERTEX(vptr, -hsz, -hsz, hsz);
211         VERTEX(vptr, -hsz, hsz, hsz);
212         VERTEX(vptr, -hsz, hsz, -hsz);
213         /* +X */
214         NORMAL(vptr, 1, 0, 0);
215         COLOR(vptr, 255, 0, 0);
216         VERTEX(vptr, hsz, -hsz, hsz);
217         VERTEX(vptr, hsz, -hsz, -hsz);
218         VERTEX(vptr, hsz, hsz, -hsz);
219         VERTEX(vptr, hsz, hsz, hsz);
220         /* +Y */
221         NORMAL(vptr, 0, 1, 0);
222         COLOR(vptr, 0, 255, 0);
223         VERTEX(vptr, -hsz, hsz, hsz);
224         VERTEX(vptr, hsz, hsz, hsz);
225         VERTEX(vptr, hsz, hsz, -hsz);
226         VERTEX(vptr, -hsz, hsz, -hsz);
227         /* +Z */
228         NORMAL(vptr, 0, 0, 1);
229         COLOR(vptr, 0, 0, 255);
230         VERTEX(vptr, -hsz, -hsz, hsz);
231         VERTEX(vptr, hsz, -hsz, hsz);
232         VERTEX(vptr, hsz, hsz, hsz);
233         VERTEX(vptr, -hsz, hsz, hsz);
234
235         return 0;
236 }
237
238 static void torusvec(float *res, float theta, float phi, float mr, float rr)
239 {
240         float rx, ry, rz;
241         theta = -theta;
242
243         rx = -cos(phi) * rr + mr;
244         ry = sin(phi) * rr;
245         rz = 0.0f;
246
247         res[0] = rx * sin(theta) + rz * cos(theta);
248         res[1] = ry;
249         res[2] = -rx * cos(theta) + rz * sin(theta);
250 }
251
252 static int gen_torus(struct mesh *mesh, float rad, float ringrad, int usub, int vsub)
253 {
254         int i, j;
255         int nfaces, uverts, vverts;
256         struct g3d_vertex *vptr;
257         int16_t *iptr;
258
259         mesh->prim = G3D_QUADS;
260
261         if(usub < 4) usub = 4;
262         if(vsub < 2) vsub = 2;
263
264         uverts = usub + 1;
265         vverts = vsub + 1;
266
267         mesh->vcount = uverts * vverts;
268         nfaces = usub * vsub;
269         mesh->icount = nfaces * 4;
270
271         if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
272                 return -1;
273         }
274         if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
275                 return -1;
276         }
277         vptr = mesh->varr;
278         iptr = mesh->iarr;
279
280         for(i=0; i<uverts; i++) {
281                 float u = (float)i / (float)(uverts - 1);
282                 float theta = u * 2.0 * M_PI;
283                 float rcent[3];
284
285                 torusvec(rcent, theta, 0, rad, 0);
286
287                 for(j=0; j<vverts; j++) {
288                         float v = (float)j / (float)(vverts - 1);
289                         float phi = v * 2.0 * M_PI;
290                         int chess = (i & 1) == (j & 1);
291
292                         torusvec(&vptr->x, theta, phi, rad, ringrad);
293
294                         vptr->nx = (vptr->x - rcent[0]) / ringrad;
295                         vptr->ny = (vptr->y - rcent[1]) / ringrad;
296                         vptr->nz = (vptr->z - rcent[2]) / ringrad;
297                         vptr->u = u;
298                         vptr->v = v;
299                         vptr->r = chess ? 255 : 64;
300                         vptr->g = 128;
301                         vptr->b = chess ? 64 : 255;
302                         ++vptr;
303
304                         if(i < usub && j < vsub) {
305                                 int idx = i * vverts + j;
306                                 *iptr++ = idx;
307                                 *iptr++ = idx + 1;
308                                 *iptr++ = idx + vverts + 1;
309                                 *iptr++ = idx + vverts;
310                         }
311                 }
312         }
313         return 0;
314 }
315
316
317 static struct {
318         struct g3d_vertex *varr;
319         const float *xform;
320 } zsort_cls;
321
322 static int zsort_cmp(const void *aptr, const void *bptr)
323 {
324         const int16_t *a = (const int16_t*)aptr;
325         const int16_t *b = (const int16_t*)bptr;
326
327         const float *m = zsort_cls.xform;
328
329         const struct g3d_vertex *va = zsort_cls.varr + a[0];
330         const struct g3d_vertex *vb = zsort_cls.varr + b[0];
331
332         float za = m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
333         float zb = m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
334
335         va = zsort_cls.varr + a[2];
336         vb = zsort_cls.varr + b[2];
337
338         za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
339         zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
340
341         return za - zb;
342 }
343
344 static void zsort(struct mesh *m)
345 {
346         int nfaces = m->icount / m->prim;
347
348         zsort_cls.varr = m->varr;
349         zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
350
351         qsort(m->iarr, nfaces, m->prim * sizeof *m->iarr, zsort_cmp);
352 }
353
354 static void draw_huge_pixel(uint16_t *dest, int dest_width, uint16_t color)
355 {
356         int i, j;
357         uint16_t grid_color = PACK_RGB16(127, 127, 127);
358
359         for(i=0; i<LOWRES_SCALE; i++) {
360                 for(j=0; j<LOWRES_SCALE; j++) {
361                         dest[j] = i == 0 || j == 0 ? grid_color : color;
362                 }
363                 dest += dest_width;
364         }
365 }
366
367 static void draw_lowres_raster(void)
368 {
369         int i, j;
370         uint16_t *sptr = lowres_pixels;
371         uint16_t *dptr = fb_pixels;
372
373         for(i=0; i<lowres_height; i++) {
374                 for(j=0; j<lowres_width; j++) {
375                         draw_huge_pixel(dptr, fb_width, *sptr++);
376                         dptr += LOWRES_SCALE;
377                 }
378                 dptr += fb_width * LOWRES_SCALE - fb_width;
379         }
380 }