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