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