dos3d

view src/test.c @ 9:bce78aaafc68

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 26 Nov 2011 03:59:48 +0200
parents c3e0bccd673e
children 059bb38506b3
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"
27 #include "palman.h"
28 #include "texture.h"
30 static int init(void);
31 static void shutdown(void);
32 static void redraw(void);
33 static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx);
34 static int keyb(char key);
35 static void mouse_button(int bn, int x, int y);
36 static void mouse_motion(int x, int y);
37 static void sighandler(int s);
38 static int parse_args(int argc, char **argv);
39 static void print_perf(void);
41 static unsigned char *fbuf;
43 static struct texture *tex;
44 static char *texfile;
46 static int white_base, red_base, green_base, blue_base;
47 static int grad_range;
49 static int use_vsync = 1;
50 static int under_windows = 0;
51 static unsigned long num_frm;
53 enum { CUBE, SPHERE, TORUS, NUM_PRIMS };
54 static int prim = SPHERE;
55 static int auto_rotate = 1;
56 static float cam_theta, cam_phi, cam_zoom = 4.0;
58 static int mx, my;
60 int main(int argc, char **argv)
61 {
62 int mbn, prev_mx = -1, prev_my = -1, prev_mbn = 0;
64 if(parse_args(argc, argv) == -1) {
65 return 1;
66 }
68 if(init() == -1) {
69 return 1;
70 }
72 reset_timer();
74 for(;;) {
75 if(kbhit()) {
76 if(keyb(getch()) == 0) {
77 break;
78 }
79 }
81 mbn = read_mouse(&mx, &my);
82 if(mbn != prev_mbn) {
83 mouse_button(mbn, mx, my);
84 prev_mbn = mbn;
85 }
86 if(mx != prev_mx || my != prev_my) {
87 if(mbn) {
88 mouse_motion(mx, my);
89 }
90 prev_mx = mx;
91 prev_my = my;
92 }
94 redraw();
95 }
97 shutdown();
98 print_perf();
99 return 0;
100 }
102 static int init(void)
103 {
104 int i;
105 struct palm_color *pal;
107 init_timer(under_windows ? 0 : 100);
109 set_video_mode(0x13);
111 signal(SIGINT, sighandler);
112 signal(SIGSEGV, sighandler);
113 signal(SIGFPE, sighandler);
114 signal(SIGILL, sighandler);
115 signal(SIGABRT, sighandler);
118 if(mgl_init(320, 200) == -1) {
119 fprintf(stderr, "mgl init failed\n");
120 return -1;
121 }
122 fbuf = mgl_framebuffer();
125 if(!texfile) {
126 palm_add_color(255, 255, 255);
127 palm_add_color(255, 0, 0);
128 palm_add_color(0, 255, 0);
129 palm_add_color(0, 0, 255);
130 palm_build();
132 white_base = palm_color_base(255, 255, 255);
133 red_base = palm_color_base(255, 0, 0);
134 green_base = palm_color_base(0, 255, 0);
135 blue_base = palm_color_base(0, 0, 255);
137 tex = tex_gen_checker(64, 64, 3, 3, red_base, blue_base);
138 } else {
139 if(!(tex = load_texture(texfile))) {
140 return -1;
141 }
143 palm_build();
144 get_texture_pixels(tex);
146 mgl_enable(MGL_TEXTURE_2D);
147 }
149 grad_range = palm_color_range();
151 pal = palm_palette();
152 for(i=0; i<palm_palette_size(); i++) {
153 set_palette(i, pal[i].r, pal[i].g, pal[i].b);
154 }
156 mgl_enable(MGL_CULL_FACE);
157 mgl_enable(MGL_DEPTH_TEST);
158 mgl_enable(MGL_SMOOTH);
159 mgl_color_range(grad_range - 1); /* gradient range */
161 mgl_enable(MGL_LIGHTING);
162 mgl_light_intensity(0, 1.0);
163 mgl_light_direction(0, -0.5, 0.5, 1);
165 mgl_matrix_mode(MGL_PROJECTION);
166 mgl_load_identity();
167 mgl_perspective(45.0, 320.0 / 200.0, 0.5, 100.0);
169 mgl_teximage(tex->width, tex->height, tex->pixels);
171 return 0;
172 }
174 static void shutdown(void)
175 {
176 mgl_free();
177 set_video_mode(3);
178 }
180 static void redraw(void)
181 {
182 float angle = get_msec() / 10.0;
183 mgl_clear(0);
184 mgl_clear_depth();
186 mgl_matrix_mode(MGL_MODELVIEW);
187 mgl_load_identity();
188 if(auto_rotate) {
189 mgl_rotate(angle, 0, 0, 1);
190 mgl_rotate(angle * 0.5, 1, 0, 0);
191 } else {
192 mgl_rotate(cam_theta, 0, 1, 0);
193 mgl_rotate(cam_phi, 1, 0, 0);
194 }
195 mgl_translate(0, 0, -cam_zoom);
197 switch(prim) {
198 case TORUS:
199 mgl_index(green_base);
200 mgl_torus(1.0, 0.25, 16, 8);
201 break;
202 case SPHERE:
203 mgl_index(blue_base);
204 mgl_sphere(1.0, 16, 8);
205 break;
206 case CUBE:
207 mgl_index(red_base);
208 mgl_cube(1.0);
209 }
211 if(!auto_rotate) {
212 draw_cursor(fbuf, 320, 200, mx, my, white_base + grad_range - 1);
213 }
215 copy_frame(fbuf);
216 if(use_vsync) {
217 wait_vsync();
218 }
219 num_frm++;
220 }
222 static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx)
223 {
224 static char img[] =
225 "oo........"
226 "oxo......."
227 "oxxo......"
228 "oxxxo....."
229 "oxxxxo...."
230 "oxxxxxo..."
231 "oxxxxxxo.."
232 "oxxxxxxxo."
233 "oxxxxxxxxo"
234 "oxxxxxoooo"
235 "oxxoxxo..."
236 "oxo.oxxo.."
237 "oo..oxxo.."
238 ".....oxxo."
239 ".....oxxo."
240 "......oo..";
241 int i, j, w = 10, h = 16;
243 if(mx < 0 || my < 0) {
244 return;
245 }
246 if(mx + w >= xsz) {
247 w = xsz - mx;
248 }
249 if(my + h >= ysz) {
250 h = ysz - my;
251 }
253 fb += my * xsz + mx;
254 for(i=0; i<h; i++) {
255 for(j=0; j<w; j++) {
256 char c = img[(i << 3) + (i << 1) + j];
257 if(c != '.') {
258 fb[j] = c == 'x' ? 0 : cidx;
259 }
260 }
261 fb += xsz;
262 }
263 }
265 static int keyb(char key)
266 {
267 switch(key) {
268 case 'q':
269 case 27:
270 return 0;
272 case 's':
273 if(mgl_isenabled(MGL_SMOOTH)) {
274 mgl_disable(MGL_SMOOTH);
275 } else {
276 mgl_enable(MGL_SMOOTH);
277 }
278 break;
280 case 't':
281 if(mgl_isenabled(MGL_TEXTURE_2D)) {
282 mgl_disable(MGL_TEXTURE_2D);
283 } else {
284 mgl_enable(MGL_TEXTURE_2D);
285 }
286 break;
288 case ' ':
289 auto_rotate = !auto_rotate;
290 break;
292 case 'p':
293 prim = (prim + 1) % NUM_PRIMS;
294 break;
296 default:
297 break;
298 }
299 return 1;
300 }
302 static int bnstate;
303 static int prev_x, prev_y;
305 static void mouse_button(int bn, int x, int y)
306 {
307 bnstate = bn;
308 prev_x = x;
309 prev_y = y;
310 }
312 static void mouse_motion(int x, int y)
313 {
314 int dx, dy;
316 dx = x - prev_x;
317 dy = y - prev_y;
318 prev_x = x;
319 prev_y = y;
321 if(bnstate & MOUSE_LEFT) {
322 cam_theta += dx;
323 cam_phi += dy;
325 if(cam_phi > 90) cam_phi = 90;
326 if(cam_phi < -90) cam_phi = -90;
327 }
328 if(bnstate & MOUSE_RIGHT) {
329 cam_zoom += dy * 0.1;
330 if(cam_zoom < 0.0) {
331 cam_zoom = 0.0;
332 }
333 }
334 }
336 static void sighandler(int s)
337 {
338 set_video_mode(3);
340 switch(s) {
341 case SIGABRT:
342 fprintf(stderr, "abort\n");
343 break;
345 case SIGILL:
346 fprintf(stderr, "illegal operation\n");
347 break;
349 case SIGSEGV:
350 fprintf(stderr, "segmentation fault\n");
351 break;
353 case SIGINT:
354 fprintf(stderr, "interrupted\n");
355 break;
357 case SIGFPE:
358 fprintf(stderr, "floating point exception\n");
359 break;
361 default:
362 fprintf(stderr, "unexpected signal\n");
363 }
365 exit(1);
366 }
368 static int parse_args(int argc, char **argv)
369 {
370 int i;
372 for(i=1; i<argc; i++) {
373 if(argv[i][0] == '-') {
374 if(argv[i][2] != 0) {
375 goto invalid;
376 }
377 switch(argv[i][1]) {
378 case 'a':
379 auto_rotate = !auto_rotate;
380 break;
382 case 't':
383 texfile = argv[++i];
384 break;
386 case 'v':
387 use_vsync = !use_vsync;
388 break;
390 case 'p':
391 if(strcmp(argv[++i], "cube") == 0) {
392 prim = CUBE;
393 } else if(strcmp(argv[i], "sphere") == 0) {
394 prim = SPHERE;
395 } else if(strcmp(argv[i], "torus") == 0) {
396 prim = TORUS;
397 } else {
398 goto invalid;
399 }
400 break;
402 case 'w':
403 under_windows = 1;
404 break;
406 case 'h':
407 printf("Usage %s [options]\n", argv[0]);
408 printf("options:\n");
409 printf(" -p select one of (cube|sphere|torus)\n");
410 printf(" -v use vsync\n");
411 printf(" -w run under windows\n");
412 printf(" -h print usage information and exit\n");
413 exit(0);
415 default:
416 goto invalid;
417 }
418 } else {
419 goto invalid;
420 }
421 }
423 return 0;
425 invalid:
426 fprintf(stderr, "invalid argument: %s\n", argv[i]);
427 return -1;
428 }
431 static void print_perf(void)
432 {
433 unsigned long msec, avg_frame_time;
434 float sec, fps;
436 msec = get_msec();
437 if(!num_frm || msec < 1000) {
438 printf("leaving so soon? (%lu ms)\n", msec);
439 return;
440 }
442 sec = msec / 1000.0f;
443 fps = (float)num_frm / sec;
444 avg_frame_time = msec / num_frm;
446 printf("%lu frames in %.2f seconds\n", num_frm, sec);
447 printf(" avg. frame time: %lu ms\n", avg_frame_time);
448 printf(" avg. framerate: %.2f fps\n", fps);
449 }