mesh, obj loading, sorting, shitty normals...
[dos_low3d] / src / main.c
1 #include "config.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <conio.h>
7 #include <dos.h>
8 #include "video.h"
9 #include "3dgfx.h"
10 #include "mesh.h"
11 #include "vmath.h"
12 #include "util.h"
13
14 void update(void);
15 void handle_key(int key);
16 void interrupt timer_intr();
17 int parse_args(int argc, char **argv);
18 void dump_vmem(void);
19
20 static int opt_vsync = 1;
21 static int quit;
22 static unsigned long nframes;
23
24 volatile unsigned long nticks;
25 static void interrupt (*prev_timer_intr)();
26
27 static const char *mesh_fname;
28 static struct mesh mesh;
29
30 #define VERT(x, y, z) { x << 16, y << 16, z << 16, 0x10000 }
31 static struct g3d_vertex cube_varr[] = {
32         VERT(-1, -1, 1), VERT(1, -1, 1), VERT(1, -1, -1), VERT(-1, -1, -1),
33         VERT(-1, 1, 1), VERT(1, 1, 1), VERT(1, 1, -1), VERT(-1, 1, -1)
34 };
35 static struct meshface cube_faces[] = {
36         {4, {0, 1, 5, 4}},
37         {4, {1, 2, 6, 5}},
38         {4, {2, 3, 7, 6}},
39         {4, {3, 0, 4, 7}},
40         {4, {4, 5, 6, 7}},
41         {4, {3, 2, 1, 0}}
42 };
43
44 int main(int argc, char **argv)
45 {
46         int i;
47         int32_t proj[16];
48         unsigned long rate, total_ticks, sec;
49
50         if(parse_args(argc, argv) == -1) {
51                 return 1;
52         }
53
54         if(mesh_fname) {
55                 if(load_mesh(&mesh, mesh_fname) == -1) {
56                         return 1;
57                 }
58                 flip_mesh_winding(&mesh);
59         } else {
60                 mesh.varr = cube_varr;
61                 mesh.nverts = sizeof cube_varr / sizeof *cube_varr;
62                 mesh.faces = cube_faces;
63                 mesh.nfaces = sizeof cube_faces / sizeof *cube_faces;
64         }
65         for(i=0; i<mesh.nfaces; i++) {
66                 mesh.faces[i].color = (i & 7) + 9;
67         }
68
69         init_video();
70
71         for(i=0; i<256; i++) {
72                 int r = XCOS(i << 1) >> 5;
73                 int b = (255 - r) >> 1;
74                 vid_setpalent(i, r, 8, b);
75         }
76         vid_setpalent(0, 0, 0, 0);
77
78         g3d_init();
79         g3d_framebuffer(320, 200, 0);
80
81         mat_perspective(proj, 50, (4 << 16) / 3, 0x8000, 0x100000);
82         g3d_projection(proj);
83
84         prev_timer_intr = _dos_getvect(0x1c);
85         _dos_setvect(0x1c, timer_intr);
86
87         for(;;) {
88                 while(kbhit()) {
89                         int c = getch();
90                         handle_key(c);
91                         if(quit) goto end;
92                 }
93
94                 update();
95                 nframes++;
96         }
97
98 end:
99         _disable();
100         total_ticks = nticks;
101         _dos_setvect(0x1c, prev_timer_intr);
102         _enable();
103
104         close_video();
105
106         /* 1.193182MHz / 65536 = 18.20651245117 ticks/sec */
107         rate = nframes * 1820 / nticks;
108         sec = nticks * 100 / 182;
109         printf("%lu frames in %lu.%lu sec - %lu.%lu fps\n", nframes,
110                         sec / 10, sec % 10, rate / 100, rate % 100);
111
112         return 0;
113 }
114
115 void update(void)
116 {
117         int i;
118         int32_t xform[16];
119
120         mat_trans(xform, 0, 0, -0x70000);
121         mat_mul_rotx(xform, nframes);
122         mat_mul_roty(xform, nframes);
123         g3d_modelview(xform);
124
125         g3d_fbpixels = vid_backbuf;
126         if(opt_vsync) {
127                 vid_wait_vblank();
128         }
129
130 #ifdef USE_DIRTY_CLEAR
131         g3d_clear_dirty();
132 #else
133         vid_clearfb();
134 #endif
135
136         sort_mesh(&mesh, xform);
137         draw_mesh_zorder(&mesh);
138
139         vid_pgflip();
140 }
141
142 void handle_key(int key)
143 {
144         switch(key) {
145         case 27:
146                 quit = 1;
147                 break;
148
149         case ' ':
150                 dump_vmem();
151                 break;
152         }
153 }
154
155 void interrupt timer_intr()
156 {
157         nticks++;
158         _chain_intr(prev_timer_intr);
159 }
160
161 static const char *helpfmt = "Usage: %s [options] [mesh file]\n"
162         "Options:\n"
163         "  -vsync: enable vsync (default)\n"
164         "  -novsync: disable vsync\n"
165         "  -help,-h: print usage and exit\n";
166
167 int parse_args(int argc, char **argv)
168 {
169         int i;
170
171         for(i=1; i<argc; i++) {
172                 if(argv[i][0] == '-') {
173                         if(strcmp(argv[i], "-vsync") == 0) {
174                                 opt_vsync = 1;
175                         } else if(strcmp(argv[i], "-novsync") == 0) {
176                                 opt_vsync = 0;
177                         } else if(strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "-h") == 0) {
178                                 printf(helpfmt, argv[0]);
179                                 exit(0);
180                         } else {
181                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
182                                 return -1;
183                         }
184                 } else {
185                         if(mesh_fname) {
186                                 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
187                                 return -1;
188                         }
189                         mesh_fname = argv[i];
190                 }
191         }
192
193         return 0;
194 }
195
196 #define GC_ADDR 0x3ce
197 #define GC_DATA 0x3cf
198 #define RDSEL   4
199
200 void dump_vmem(void)
201 {
202         unsigned char *img, *src, *dest;
203         unsigned char cmap[256][3];
204         int i, j;
205         FILE *fp;
206
207         /* grab colormap */
208         outp(0x3c7, 0);
209         for(i=0; i<256; i++) {
210                 cmap[i][0] = inp(0x3c9) << 2;
211                 cmap[i][1] = inp(0x3c9) << 2;
212                 cmap[i][2] = inp(0x3c9) << 2;
213         }
214
215         /* allocate image */
216         if(!(img = malloc(320 * 400 * 3))) {
217                 return;
218         }
219         if(!(fp = fopen("vmem.ppm", "wb"))) {
220                 free(img);
221                 return;
222         }
223
224         src = (unsigned char*)0xa0000;
225         for(i=0; i<4; i++) {
226                 outp(0x3ce, 4); /* graphics controller: read map select register */
227                 outp(0x3cf, i);
228                 dest = img + i * 3;
229                 for(j=0; j<16000; j++) {
230                         int idx = src[j];
231                         dest[0] = cmap[idx][0];
232                         dest[1] = cmap[idx][1];
233                         dest[2] = cmap[idx][2];
234                         dest += 12;
235                 }
236         }
237
238         src = (unsigned char*)0xa4000;
239         for(i=0; i<4; i++) {
240                 outp(0x3ce, 4); /* graphics controller: read map select register */
241                 outp(0x3cf, i);
242                 dest = img + i * 3;
243                 for(j=0; j<16000; j++) {
244                         int idx = src[j];
245                         dest[0] = cmap[idx][0];
246                         dest[1] = cmap[idx][1];
247                         dest[2] = cmap[idx][2];
248                         dest += 12;
249                 }
250         }
251
252         fprintf(fp, "P6\n%d %d\n255\n", 320, 400);
253         fwrite(img, 1, 320 * 400 * 3, fp);
254         fclose(fp);
255         free(img);
256 }