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