dos3d

view src/test.c @ 12:c29a6e024950

merged
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 28 Nov 2011 05:03:22 +0200
parents bce78aaafc68
children 7b574ba5758e
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);
117 have_mouse();
120 if(mgl_init(320, 200) == -1) {
121 fprintf(stderr, "mgl init failed\n");
122 return -1;
123 }
124 fbuf = mgl_framebuffer();
127 if(!texfile) {
128 palm_add_color(255, 255, 255);
129 palm_add_color(255, 0, 0);
130 palm_add_color(0, 255, 0);
131 palm_add_color(0, 0, 255);
132 palm_build();
134 white_base = palm_color_base(255, 255, 255);
135 red_base = palm_color_base(255, 0, 0);
136 green_base = palm_color_base(0, 255, 0);
137 blue_base = palm_color_base(0, 0, 255);
139 tex = tex_gen_checker(64, 64, 3, 3, red_base, blue_base);
140 } else {
141 if(!(tex = load_texture(texfile))) {
142 return -1;
143 }
145 palm_build();
146 get_texture_pixels(tex);
148 mgl_enable(MGL_TEXTURE_2D);
149 }
151 grad_range = palm_color_range();
153 pal = palm_palette();
154 for(i=0; i<palm_palette_size(); i++) {
155 set_palette(i, pal[i].r, pal[i].g, pal[i].b);
156 }
158 mgl_enable(MGL_CULL_FACE);
159 mgl_enable(MGL_DEPTH_TEST);
160 mgl_enable(MGL_SMOOTH);
161 mgl_color_range(grad_range - 1); /* gradient range */
163 mgl_enable(MGL_LIGHTING);
164 mgl_light_intensity(0, 1.0);
165 mgl_light_direction(0, -0.5, 0.5, 1);
167 mgl_matrix_mode(MGL_PROJECTION);
168 mgl_load_identity();
169 mgl_perspective(45.0, 320.0 / 200.0, 0.5, 100.0);
171 mgl_teximage(tex->width, tex->height, tex->pixels);
173 return 0;
174 }
176 static void shutdown(void)
177 {
178 mgl_free();
179 set_video_mode(3);
180 }
182 static void redraw(void)
183 {
184 float angle = get_msec() / 10.0;
185 mgl_clear(0);
186 mgl_clear_depth();
188 mgl_matrix_mode(MGL_MODELVIEW);
189 mgl_load_identity();
190 if(auto_rotate) {
191 mgl_rotate(angle, 0, 0, 1);
192 mgl_rotate(angle * 0.5, 1, 0, 0);
193 } else {
194 mgl_rotate(cam_theta, 0, 1, 0);
195 mgl_rotate(cam_phi, 1, 0, 0);
196 }
197 mgl_translate(0, 0, -cam_zoom);
199 switch(prim) {
200 case TORUS:
201 mgl_index(green_base);
202 mgl_torus(1.0, 0.25, 16, 8);
203 break;
204 case SPHERE:
205 mgl_index(blue_base);
206 mgl_sphere(1.0, 16, 8);
207 break;
208 case CUBE:
209 mgl_index(red_base);
210 mgl_cube(1.0);
211 }
213 if(!auto_rotate) {
214 draw_cursor(fbuf, 320, 200, mx, my, white_base + grad_range - 1);
215 }
217 copy_frame(fbuf);
218 if(use_vsync) {
219 wait_vsync();
220 }
221 num_frm++;
222 }
224 static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx)
225 {
226 static char img[] =
227 "oo........"
228 "oxo......."
229 "oxxo......"
230 "oxxxo....."
231 "oxxxxo...."
232 "oxxxxxo..."
233 "oxxxxxxo.."
234 "oxxxxxxxo."
235 "oxxxxxxxxo"
236 "oxxxxxoooo"
237 "oxxoxxo..."
238 "oxo.oxxo.."
239 "oo..oxxo.."
240 ".....oxxo."
241 ".....oxxo."
242 "......oo..";
243 int i, j, w = 10, h = 16;
245 if(mx < 0 || my < 0) {
246 return;
247 }
248 if(mx + w >= xsz) {
249 w = xsz - mx;
250 }
251 if(my + h >= ysz) {
252 h = ysz - my;
253 }
255 fb += my * xsz + mx;
256 for(i=0; i<h; i++) {
257 for(j=0; j<w; j++) {
258 char c = img[(i << 3) + (i << 1) + j];
259 if(c != '.') {
260 fb[j] = c == 'x' ? 0 : cidx;
261 }
262 }
263 fb += xsz;
264 }
265 }
267 static int keyb(char key)
268 {
269 switch(key) {
270 case 'q':
271 case 27:
272 return 0;
274 case 's':
275 if(mgl_isenabled(MGL_SMOOTH)) {
276 mgl_disable(MGL_SMOOTH);
277 } else {
278 mgl_enable(MGL_SMOOTH);
279 }
280 break;
282 case 't':
283 if(mgl_isenabled(MGL_TEXTURE_2D)) {
284 mgl_disable(MGL_TEXTURE_2D);
285 } else {
286 mgl_enable(MGL_TEXTURE_2D);
287 }
288 break;
290 case ' ':
291 auto_rotate = !auto_rotate;
292 break;
294 case 'p':
295 prim = (prim + 1) % NUM_PRIMS;
296 break;
298 default:
299 break;
300 }
301 return 1;
302 }
304 static int bnstate;
305 static int prev_x, prev_y;
307 static void mouse_button(int bn, int x, int y)
308 {
309 bnstate = bn;
310 prev_x = x;
311 prev_y = y;
312 }
314 static void mouse_motion(int x, int y)
315 {
316 int dx, dy;
318 dx = x - prev_x;
319 dy = y - prev_y;
320 prev_x = x;
321 prev_y = y;
323 if(bnstate & MOUSE_LEFT) {
324 cam_theta += dx;
325 cam_phi += dy;
327 if(cam_phi > 90) cam_phi = 90;
328 if(cam_phi < -90) cam_phi = -90;
329 }
330 if(bnstate & MOUSE_RIGHT) {
331 cam_zoom += dy * 0.1;
332 if(cam_zoom < 0.0) {
333 cam_zoom = 0.0;
334 }
335 }
336 }
338 static void sighandler(int s)
339 {
340 set_video_mode(3);
342 switch(s) {
343 case SIGABRT:
344 fprintf(stderr, "abort\n");
345 break;
347 case SIGILL:
348 fprintf(stderr, "illegal operation\n");
349 break;
351 case SIGSEGV:
352 fprintf(stderr, "segmentation fault\n");
353 break;
355 case SIGINT:
356 fprintf(stderr, "interrupted\n");
357 break;
359 case SIGFPE:
360 fprintf(stderr, "floating point exception\n");
361 break;
363 default:
364 fprintf(stderr, "unexpected signal\n");
365 }
367 exit(1);
368 }
370 static int parse_args(int argc, char **argv)
371 {
372 int i;
374 for(i=1; i<argc; i++) {
375 if(argv[i][0] == '-') {
376 if(argv[i][2] != 0) {
377 goto invalid;
378 }
379 switch(argv[i][1]) {
380 case 'a':
381 auto_rotate = !auto_rotate;
382 break;
384 case 't':
385 texfile = argv[++i];
386 break;
388 case 'v':
389 use_vsync = !use_vsync;
390 break;
392 case 'p':
393 if(strcmp(argv[++i], "cube") == 0) {
394 prim = CUBE;
395 } else if(strcmp(argv[i], "sphere") == 0) {
396 prim = SPHERE;
397 } else if(strcmp(argv[i], "torus") == 0) {
398 prim = TORUS;
399 } else {
400 goto invalid;
401 }
402 break;
404 case 'w':
405 under_windows = 1;
406 break;
408 case 'h':
409 printf("Usage %s [options]\n", argv[0]);
410 printf("options:\n");
411 printf(" -p select one of (cube|sphere|torus)\n");
412 printf(" -v use vsync\n");
413 printf(" -w run under windows\n");
414 printf(" -h print usage information and exit\n");
415 exit(0);
417 default:
418 goto invalid;
419 }
420 } else {
421 goto invalid;
422 }
423 }
425 return 0;
427 invalid:
428 fprintf(stderr, "invalid argument: %s\n", argv[i]);
429 return -1;
430 }
433 static void print_perf(void)
434 {
435 unsigned long msec, avg_frame_time;
436 float sec, fps;
438 msec = get_msec();
439 if(!num_frm || msec < 1000) {
440 printf("leaving so soon? (%lu ms)\n", msec);
441 return;
442 }
444 sec = msec / 1000.0f;
445 fps = (float)num_frm / sec;
446 avg_frame_time = msec / num_frm;
448 printf("%lu frames in %.2f seconds\n", num_frm, sec);
449 printf(" avg. frame time: %lu ms\n", avg_frame_time);
450 printf(" avg. framerate: %.2f fps\n", fps);
451 }