dos3d

view src/test.c @ 0:f04884489bad

dos3d initial import
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 21 Nov 2011 06:14:01 +0200
parents
children 0b7f840afe4a
line source
1 /*
2 256-color 3D graphics hack for real-mode DOS.
3 Copyright (C) 2011 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <signal.h>
22 #include <conio.h>
23 #include "vga.h"
24 #include "mingl.h"
25 #include "timer.h"
26 #include "mouse.h"
28 #define ROFFS 64
29 #define GOFFS 128
30 #define BOFFS 192
32 static int init(void);
33 static void shutdown(void);
34 static void redraw(void);
35 static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx);
36 static int keyb(char key);
37 static void mouse_button(int bn, int x, int y);
38 static void mouse_motion(int x, int y);
39 static void sighandler(int s);
40 static int parse_args(int argc, char **argv);
41 static void print_perf(void);
43 static unsigned char *fbuf;
45 static int use_vsync = 1;
46 static int under_windows = 0;
47 static unsigned long num_frm;
49 enum { CUBE, SPHERE, TORUS, NUM_PRIMS };
50 static int prim = SPHERE;
51 static int auto_rotate = 1;
52 static float cam_theta, cam_phi;
54 static int mx, my;
56 int main(int argc, char **argv)
57 {
58 int mbn, prev_mx = -1, prev_my = -1, prev_mbn = 0;
60 if(parse_args(argc, argv) == -1) {
61 return 1;
62 }
64 if(init() == -1) {
65 return 1;
66 }
68 reset_timer();
70 for(;;) {
71 if(kbhit()) {
72 if(keyb(getch()) == 0) {
73 break;
74 }
75 }
77 mbn = read_mouse(&mx, &my);
78 if(mbn != prev_mbn) {
79 mouse_button(mbn, mx, my);
80 prev_mbn = mbn;
81 }
82 if(mx != prev_mx || my != prev_my) {
83 if(mbn) {
84 mouse_motion(mx, my);
85 }
86 prev_mx = mx;
87 prev_my = my;
88 }
90 redraw();
91 }
93 shutdown();
94 print_perf();
95 return 0;
96 }
98 static int init(void)
99 {
100 int i;
102 init_timer(under_windows ? 0 : 100);
104 set_video_mode(0x13);
106 signal(SIGINT, sighandler);
107 signal(SIGSEGV, sighandler);
108 signal(SIGFPE, sighandler);
109 signal(SIGILL, sighandler);
110 signal(SIGABRT, sighandler);
112 for(i=0; i<64; i++) {
113 int x = i << 2;
114 set_palette(i, x, x, x);
115 set_palette(i + ROFFS, x, 0, 0);
116 set_palette(i + GOFFS, 0, x, 0);
117 set_palette(i + BOFFS, 0, 0, x);
118 }
120 if(mgl_init(320, 200) == -1) {
121 fprintf(stderr, "mgl init failed\n");
122 return -1;
123 }
124 fbuf = mgl_framebuffer();
126 mgl_enable(MGL_CULL_FACE);
127 mgl_enable(MGL_SMOOTH);
128 mgl_color_range(63); /* gradient range */
130 mgl_enable(MGL_LIGHTING);
131 mgl_light_intensity(0, 1.0);
132 mgl_light_direction(0, -0.5, 0.5, 1);
134 mgl_matrix_mode(MGL_PROJECTION);
135 mgl_load_identity();
136 mgl_perspective(45.0, 320.0 / 200.0, 0.5, 100.0);
138 return 0;
139 }
141 static void shutdown(void)
142 {
143 mgl_free();
144 set_video_mode(3);
145 }
147 static void redraw(void)
148 {
149 float angle = get_msec() / 10.0;
150 mgl_clear(0);
152 mgl_matrix_mode(MGL_MODELVIEW);
153 mgl_load_identity();
154 if(auto_rotate) {
155 mgl_rotate(angle, 0, 0, 1);
156 mgl_rotate(angle * 0.5, 1, 0, 0);
157 } else {
158 mgl_rotate(cam_theta, 0, 1, 0);
159 mgl_rotate(cam_phi, 1, 0, 0);
160 }
161 mgl_translate(0, 0, -4);
163 switch(prim) {
164 case TORUS:
165 mgl_index(GOFFS);
166 mgl_torus(1.0, 0.25, 16, 8);
167 break;
168 case SPHERE:
169 mgl_index(BOFFS);
170 mgl_sphere(1.0, 16, 8);
171 break;
172 case CUBE:
173 mgl_index(ROFFS);
174 mgl_cube(1.0);
175 }
177 /*mgl_begin(MGL_QUADS);
178 mgl_index(ROFFS);
179 mgl_color1f(1.0);
180 mgl_vertex2f(-1, -1);
181 mgl_vertex2f(1, -1);
182 mgl_color1f(0.1);
183 mgl_vertex2f(1, 1);
184 mgl_vertex2f(-1, 1);
185 mgl_end();*/
187 if(!auto_rotate) {
188 draw_cursor(fbuf, 320, 200, mx, my, 63);
189 }
191 copy_frame(fbuf);
192 if(use_vsync) {
193 wait_vsync();
194 }
195 num_frm++;
196 }
198 static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx)
199 {
200 static char img[] =
201 "oo........"
202 "oxo......."
203 "oxxo......"
204 "oxxxo....."
205 "oxxxxo...."
206 "oxxxxxo..."
207 "oxxxxxxo.."
208 "oxxxxxxxo."
209 "oxxxxxxxxo"
210 "oxxxxxoooo"
211 "oxxoxxo..."
212 "oxo.oxxo.."
213 "oo..oxxo.."
214 ".....oxxo."
215 ".....oxxo."
216 "......oo..";
217 int i, j, w = 10, h = 16;
219 if(mx < 0 || my < 0) {
220 return;
221 }
222 if(mx + w >= xsz) {
223 w = xsz - mx;
224 }
225 if(my + h >= ysz) {
226 h = ysz - my;
227 }
229 fb += my * xsz + mx;
230 for(i=0; i<h; i++) {
231 for(j=0; j<w; j++) {
232 char c = img[(i << 3) + (i << 1) + j];
233 if(c != '.') {
234 fb[j] = c == 'x' ? 0 : cidx;
235 }
236 }
237 fb += xsz;
238 }
239 }
241 static int keyb(char key)
242 {
243 switch(key) {
244 case 'q':
245 case 27:
246 return 0;
248 case ' ':
249 auto_rotate = !auto_rotate;
250 break;
252 case 'p':
253 prim = (prim + 1) % NUM_PRIMS;
254 break;
256 default:
257 break;
258 }
259 return 1;
260 }
262 static int bnstate;
263 static int prev_x, prev_y;
265 static void mouse_button(int bn, int x, int y)
266 {
267 bnstate = bn;
268 prev_x = x;
269 prev_y = y;
270 }
272 static void mouse_motion(int x, int y)
273 {
274 int dx, dy;
276 dx = x - prev_x;
277 dy = y - prev_y;
278 prev_x = x;
279 prev_y = y;
281 if(bnstate) {
282 cam_theta += dx;
283 cam_phi += dy;
285 if(cam_phi > 90) cam_phi = 90;
286 if(cam_phi < -90) cam_phi = -90;
287 }
288 }
290 static void sighandler(int s)
291 {
292 set_video_mode(3);
294 switch(s) {
295 case SIGABRT:
296 fprintf(stderr, "abort\n");
297 break;
299 case SIGILL:
300 fprintf(stderr, "illegal operation\n");
301 break;
303 case SIGSEGV:
304 fprintf(stderr, "segmentation fault\n");
305 break;
307 case SIGINT:
308 fprintf(stderr, "interrupted\n");
309 break;
311 case SIGFPE:
312 fprintf(stderr, "floating point exception\n");
313 break;
315 default:
316 fprintf(stderr, "unexpected signal\n");
317 }
319 exit(1);
320 }
322 static int parse_args(int argc, char **argv)
323 {
324 int i;
326 for(i=1; i<argc; i++) {
327 if(argv[i][0] == '-') {
328 if(argv[i][2] != 0) {
329 goto invalid;
330 }
331 switch(argv[i][1]) {
332 case 'a':
333 auto_rotate = !auto_rotate;
334 break;
336 case 'v':
337 use_vsync = !use_vsync;
338 break;
340 case 'p':
341 if(strcmp(argv[++i], "cube") == 0) {
342 prim = CUBE;
343 } else if(strcmp(argv[i], "sphere") == 0) {
344 prim = SPHERE;
345 } else if(strcmp(argv[i], "torus") == 0) {
346 prim = TORUS;
347 } else {
348 goto invalid;
349 }
350 break;
352 case 'w':
353 under_windows = 1;
354 break;
356 case 'h':
357 printf("Usage %s [options]\n", argv[0]);
358 printf("options:\n");
359 printf(" -p select one of (cube|sphere|torus)\n");
360 printf(" -v use vsync\n");
361 printf(" -w run under windows\n");
362 printf(" -h print usage information and exit\n");
363 exit(0);
365 default:
366 goto invalid;
367 }
368 } else {
369 goto invalid;
370 }
371 }
373 return 0;
375 invalid:
376 fprintf(stderr, "invalid argument: %s\n", argv[i]);
377 return -1;
378 }
381 static void print_perf(void)
382 {
383 unsigned long msec, avg_frame_time;
384 float sec, fps;
386 msec = get_msec();
387 if(!num_frm || msec < 1000) {
388 printf("leaving so soon? (%lu ms)\n", msec);
389 return;
390 }
392 sec = msec / 1000.0f;
393 fps = (float)num_frm / sec;
394 avg_frame_time = msec / num_frm;
396 printf("%lu frames in %.2f seconds\n", num_frm, sec);
397 printf(" avg. frame time: %lu ms\n", avg_frame_time);
398 printf(" avg. framerate: %.2f fps\n", fps);
399 }