dos3d

view src/test.c @ 4:c3e0bccd673e

added texture mapping
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 21 Nov 2011 11:51:23 +0200
parents 0e781cc43178
children bce78aaafc68
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;
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_SMOOTH);
158 mgl_color_range(grad_range - 1); /* gradient range */
160 mgl_enable(MGL_LIGHTING);
161 mgl_light_intensity(0, 1.0);
162 mgl_light_direction(0, -0.5, 0.5, 1);
164 mgl_matrix_mode(MGL_PROJECTION);
165 mgl_load_identity();
166 mgl_perspective(45.0, 320.0 / 200.0, 0.5, 100.0);
168 mgl_teximage(tex->width, tex->height, tex->pixels);
170 return 0;
171 }
173 static void shutdown(void)
174 {
175 mgl_free();
176 set_video_mode(3);
177 }
179 static void redraw(void)
180 {
181 float angle = get_msec() / 10.0;
182 mgl_clear(0);
184 mgl_matrix_mode(MGL_MODELVIEW);
185 mgl_load_identity();
186 if(auto_rotate) {
187 mgl_rotate(angle, 0, 0, 1);
188 mgl_rotate(angle * 0.5, 1, 0, 0);
189 } else {
190 mgl_rotate(cam_theta, 0, 1, 0);
191 mgl_rotate(cam_phi, 1, 0, 0);
192 }
193 mgl_translate(0, 0, -4);
195 switch(prim) {
196 case TORUS:
197 mgl_index(green_base);
198 mgl_torus(1.0, 0.25, 16, 8);
199 break;
200 case SPHERE:
201 mgl_index(blue_base);
202 mgl_sphere(1.0, 16, 8);
203 break;
204 case CUBE:
205 mgl_index(red_base);
206 mgl_cube(1.0);
207 }
209 if(!auto_rotate) {
210 draw_cursor(fbuf, 320, 200, mx, my, white_base + grad_range - 1);
211 }
213 copy_frame(fbuf);
214 if(use_vsync) {
215 wait_vsync();
216 }
217 num_frm++;
218 }
220 static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx)
221 {
222 static char img[] =
223 "oo........"
224 "oxo......."
225 "oxxo......"
226 "oxxxo....."
227 "oxxxxo...."
228 "oxxxxxo..."
229 "oxxxxxxo.."
230 "oxxxxxxxo."
231 "oxxxxxxxxo"
232 "oxxxxxoooo"
233 "oxxoxxo..."
234 "oxo.oxxo.."
235 "oo..oxxo.."
236 ".....oxxo."
237 ".....oxxo."
238 "......oo..";
239 int i, j, w = 10, h = 16;
241 if(mx < 0 || my < 0) {
242 return;
243 }
244 if(mx + w >= xsz) {
245 w = xsz - mx;
246 }
247 if(my + h >= ysz) {
248 h = ysz - my;
249 }
251 fb += my * xsz + mx;
252 for(i=0; i<h; i++) {
253 for(j=0; j<w; j++) {
254 char c = img[(i << 3) + (i << 1) + j];
255 if(c != '.') {
256 fb[j] = c == 'x' ? 0 : cidx;
257 }
258 }
259 fb += xsz;
260 }
261 }
263 static int keyb(char key)
264 {
265 switch(key) {
266 case 'q':
267 case 27:
268 return 0;
270 case 's':
271 if(mgl_isenabled(MGL_SMOOTH)) {
272 mgl_disable(MGL_SMOOTH);
273 } else {
274 mgl_enable(MGL_SMOOTH);
275 }
276 break;
278 case 't':
279 if(mgl_isenabled(MGL_TEXTURE_2D)) {
280 mgl_disable(MGL_TEXTURE_2D);
281 } else {
282 mgl_enable(MGL_TEXTURE_2D);
283 }
284 break;
286 case ' ':
287 auto_rotate = !auto_rotate;
288 break;
290 case 'p':
291 prim = (prim + 1) % NUM_PRIMS;
292 break;
294 default:
295 break;
296 }
297 return 1;
298 }
300 static int bnstate;
301 static int prev_x, prev_y;
303 static void mouse_button(int bn, int x, int y)
304 {
305 bnstate = bn;
306 prev_x = x;
307 prev_y = y;
308 }
310 static void mouse_motion(int x, int y)
311 {
312 int dx, dy;
314 dx = x - prev_x;
315 dy = y - prev_y;
316 prev_x = x;
317 prev_y = y;
319 if(bnstate) {
320 cam_theta += dx;
321 cam_phi += dy;
323 if(cam_phi > 90) cam_phi = 90;
324 if(cam_phi < -90) cam_phi = -90;
325 }
326 }
328 static void sighandler(int s)
329 {
330 set_video_mode(3);
332 switch(s) {
333 case SIGABRT:
334 fprintf(stderr, "abort\n");
335 break;
337 case SIGILL:
338 fprintf(stderr, "illegal operation\n");
339 break;
341 case SIGSEGV:
342 fprintf(stderr, "segmentation fault\n");
343 break;
345 case SIGINT:
346 fprintf(stderr, "interrupted\n");
347 break;
349 case SIGFPE:
350 fprintf(stderr, "floating point exception\n");
351 break;
353 default:
354 fprintf(stderr, "unexpected signal\n");
355 }
357 exit(1);
358 }
360 static int parse_args(int argc, char **argv)
361 {
362 int i;
364 for(i=1; i<argc; i++) {
365 if(argv[i][0] == '-') {
366 if(argv[i][2] != 0) {
367 goto invalid;
368 }
369 switch(argv[i][1]) {
370 case 'a':
371 auto_rotate = !auto_rotate;
372 break;
374 case 't':
375 texfile = argv[++i];
376 break;
378 case 'v':
379 use_vsync = !use_vsync;
380 break;
382 case 'p':
383 if(strcmp(argv[++i], "cube") == 0) {
384 prim = CUBE;
385 } else if(strcmp(argv[i], "sphere") == 0) {
386 prim = SPHERE;
387 } else if(strcmp(argv[i], "torus") == 0) {
388 prim = TORUS;
389 } else {
390 goto invalid;
391 }
392 break;
394 case 'w':
395 under_windows = 1;
396 break;
398 case 'h':
399 printf("Usage %s [options]\n", argv[0]);
400 printf("options:\n");
401 printf(" -p select one of (cube|sphere|torus)\n");
402 printf(" -v use vsync\n");
403 printf(" -w run under windows\n");
404 printf(" -h print usage information and exit\n");
405 exit(0);
407 default:
408 goto invalid;
409 }
410 } else {
411 goto invalid;
412 }
413 }
415 return 0;
417 invalid:
418 fprintf(stderr, "invalid argument: %s\n", argv[i]);
419 return -1;
420 }
423 static void print_perf(void)
424 {
425 unsigned long msec, avg_frame_time;
426 float sec, fps;
428 msec = get_msec();
429 if(!num_frm || msec < 1000) {
430 printf("leaving so soon? (%lu ms)\n", msec);
431 return;
432 }
434 sec = msec / 1000.0f;
435 fps = (float)num_frm / sec;
436 avg_frame_time = msec / num_frm;
438 printf("%lu frames in %.2f seconds\n", num_frm, sec);
439 printf(" avg. frame time: %lu ms\n", avg_frame_time);
440 printf(" avg. framerate: %.2f fps\n", fps);
441 }