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