dos3d

diff 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 diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/test.c	Mon Nov 21 06:14:01 2011 +0200
     1.3 @@ -0,0 +1,399 @@
     1.4 +/*
     1.5 +256-color 3D graphics hack for real-mode DOS.
     1.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
     1.7 +
     1.8 +This program is free software: you can redistribute it and/or modify
     1.9 +it under the terms of the GNU General Public License as published by
    1.10 +the Free Software Foundation, either version 3 of the License, or
    1.11 +(at your option) any later version.
    1.12 +
    1.13 +This program is distributed in the hope that it will be useful,
    1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.16 +GNU General Public License for more details.
    1.17 +
    1.18 +You should have received a copy of the GNU General Public License
    1.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
    1.20 +*/
    1.21 +#include <stdio.h>
    1.22 +#include <stdlib.h>
    1.23 +#include <string.h>
    1.24 +#include <signal.h>
    1.25 +#include <conio.h>
    1.26 +#include "vga.h"
    1.27 +#include "mingl.h"
    1.28 +#include "timer.h"
    1.29 +#include "mouse.h"
    1.30 +
    1.31 +#define ROFFS	64
    1.32 +#define GOFFS	128
    1.33 +#define BOFFS	192
    1.34 +
    1.35 +static int init(void);
    1.36 +static void shutdown(void);
    1.37 +static void redraw(void);
    1.38 +static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx);
    1.39 +static int keyb(char key);
    1.40 +static void mouse_button(int bn, int x, int y);
    1.41 +static void mouse_motion(int x, int y);
    1.42 +static void sighandler(int s);
    1.43 +static int parse_args(int argc, char **argv);
    1.44 +static void print_perf(void);
    1.45 +
    1.46 +static unsigned char *fbuf;
    1.47 +
    1.48 +static int use_vsync = 1;
    1.49 +static int under_windows = 0;
    1.50 +static unsigned long num_frm;
    1.51 +
    1.52 +enum { CUBE, SPHERE, TORUS, NUM_PRIMS };
    1.53 +static int prim = SPHERE;
    1.54 +static int auto_rotate = 1;
    1.55 +static float cam_theta, cam_phi;
    1.56 +
    1.57 +static int mx, my;
    1.58 +
    1.59 +int main(int argc, char **argv)
    1.60 +{
    1.61 +	int mbn, prev_mx = -1, prev_my = -1, prev_mbn = 0;
    1.62 +
    1.63 +	if(parse_args(argc, argv) == -1) {
    1.64 +		return 1;
    1.65 +	}
    1.66 +
    1.67 +	if(init() == -1) {
    1.68 +		return 1;
    1.69 +	}
    1.70 +
    1.71 +	reset_timer();
    1.72 +
    1.73 +	for(;;) {
    1.74 +        if(kbhit()) {
    1.75 +			if(keyb(getch()) == 0) {
    1.76 +				break;
    1.77 +            }
    1.78 +        }
    1.79 +
    1.80 +		mbn = read_mouse(&mx, &my);
    1.81 +		if(mbn != prev_mbn) {
    1.82 +			mouse_button(mbn, mx, my);
    1.83 +			prev_mbn = mbn;
    1.84 +		}
    1.85 +		if(mx != prev_mx || my != prev_my) {
    1.86 +			if(mbn) {
    1.87 +				mouse_motion(mx, my);
    1.88 +			}
    1.89 +			prev_mx = mx;
    1.90 +			prev_my = my;
    1.91 +		}
    1.92 +
    1.93 +		redraw();
    1.94 +	}
    1.95 +
    1.96 +	shutdown();
    1.97 +	print_perf();
    1.98 +	return 0;
    1.99 +}
   1.100 +
   1.101 +static int init(void)
   1.102 +{
   1.103 +	int i;
   1.104 +
   1.105 +	init_timer(under_windows ? 0 : 100);
   1.106 +
   1.107 +	set_video_mode(0x13);
   1.108 +
   1.109 +	signal(SIGINT, sighandler);
   1.110 +	signal(SIGSEGV, sighandler);
   1.111 +	signal(SIGFPE, sighandler);
   1.112 +	signal(SIGILL, sighandler);
   1.113 +	signal(SIGABRT, sighandler);
   1.114 +
   1.115 +	for(i=0; i<64; i++) {
   1.116 +		int x = i << 2;
   1.117 +		set_palette(i, x, x, x);
   1.118 +		set_palette(i + ROFFS, x, 0, 0);
   1.119 +		set_palette(i + GOFFS, 0, x, 0);
   1.120 +		set_palette(i + BOFFS, 0, 0, x);
   1.121 +	}
   1.122 +
   1.123 +	if(mgl_init(320, 200) == -1) {
   1.124 +		fprintf(stderr, "mgl init failed\n");
   1.125 +		return -1;
   1.126 +	}
   1.127 +	fbuf = mgl_framebuffer();
   1.128 +
   1.129 +	mgl_enable(MGL_CULL_FACE);
   1.130 +	mgl_enable(MGL_SMOOTH);
   1.131 +	mgl_color_range(63);	/* gradient range */
   1.132 +
   1.133 +	mgl_enable(MGL_LIGHTING);
   1.134 +	mgl_light_intensity(0, 1.0);
   1.135 +	mgl_light_direction(0, -0.5, 0.5, 1);
   1.136 +
   1.137 +	mgl_matrix_mode(MGL_PROJECTION);
   1.138 +	mgl_load_identity();
   1.139 +	mgl_perspective(45.0, 320.0 / 200.0, 0.5, 100.0);
   1.140 +
   1.141 +    return 0;
   1.142 +}
   1.143 +
   1.144 +static void shutdown(void)
   1.145 +{
   1.146 +	mgl_free();
   1.147 +    set_video_mode(3);
   1.148 +}
   1.149 +
   1.150 +static void redraw(void)
   1.151 +{
   1.152 +	float angle = get_msec() / 10.0;
   1.153 +	mgl_clear(0);
   1.154 +
   1.155 +	mgl_matrix_mode(MGL_MODELVIEW);
   1.156 +	mgl_load_identity();
   1.157 +	if(auto_rotate) {
   1.158 +		mgl_rotate(angle, 0, 0, 1);
   1.159 +		mgl_rotate(angle * 0.5, 1, 0, 0);
   1.160 +	} else {
   1.161 +		mgl_rotate(cam_theta, 0, 1, 0);
   1.162 +		mgl_rotate(cam_phi, 1, 0, 0);
   1.163 +	}
   1.164 +	mgl_translate(0, 0, -4);
   1.165 +
   1.166 +	switch(prim) {
   1.167 +	case TORUS:
   1.168 +		mgl_index(GOFFS);
   1.169 +		mgl_torus(1.0, 0.25, 16, 8);
   1.170 +		break;
   1.171 +	case SPHERE:
   1.172 +		mgl_index(BOFFS);
   1.173 +		mgl_sphere(1.0, 16, 8);
   1.174 +		break;
   1.175 +	case CUBE:
   1.176 +		mgl_index(ROFFS);
   1.177 +		mgl_cube(1.0);
   1.178 +	}
   1.179 +
   1.180 +	/*mgl_begin(MGL_QUADS);
   1.181 +	mgl_index(ROFFS);
   1.182 +	mgl_color1f(1.0);
   1.183 +	mgl_vertex2f(-1, -1);
   1.184 +	mgl_vertex2f(1, -1);
   1.185 +	mgl_color1f(0.1);
   1.186 +	mgl_vertex2f(1, 1);
   1.187 +	mgl_vertex2f(-1, 1);
   1.188 +	mgl_end();*/
   1.189 +
   1.190 +	if(!auto_rotate) {
   1.191 +		draw_cursor(fbuf, 320, 200, mx, my, 63);
   1.192 +	}
   1.193 +
   1.194 +    copy_frame(fbuf);
   1.195 +	if(use_vsync) {
   1.196 +		wait_vsync();
   1.197 +	}
   1.198 +	num_frm++;
   1.199 +}
   1.200 +
   1.201 +static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx)
   1.202 +{
   1.203 +	static char img[] =
   1.204 +		"oo........"
   1.205 +		"oxo......."
   1.206 +		"oxxo......"
   1.207 +		"oxxxo....."
   1.208 +		"oxxxxo...."
   1.209 +		"oxxxxxo..."
   1.210 +		"oxxxxxxo.."
   1.211 +		"oxxxxxxxo."
   1.212 +		"oxxxxxxxxo"
   1.213 +		"oxxxxxoooo"
   1.214 +		"oxxoxxo..."
   1.215 +		"oxo.oxxo.."
   1.216 +		"oo..oxxo.."
   1.217 +		".....oxxo."
   1.218 +		".....oxxo."
   1.219 +		"......oo..";
   1.220 +	int i, j, w = 10, h = 16;
   1.221 +
   1.222 +	if(mx < 0 || my < 0) {
   1.223 +		return;
   1.224 +	}
   1.225 +	if(mx + w >= xsz) {
   1.226 +		w = xsz - mx;
   1.227 +	}
   1.228 +	if(my + h >= ysz) {
   1.229 +		h = ysz - my;
   1.230 +	}
   1.231 +
   1.232 +	fb += my * xsz + mx;
   1.233 +	for(i=0; i<h; i++) {
   1.234 +		for(j=0; j<w; j++) {
   1.235 +			char c = img[(i << 3) + (i << 1) + j];
   1.236 +			if(c != '.') {
   1.237 +				fb[j] = c == 'x' ? 0 : cidx;
   1.238 +			}
   1.239 +		}
   1.240 +		fb += xsz;
   1.241 +	}
   1.242 +}
   1.243 +
   1.244 +static int keyb(char key)
   1.245 +{
   1.246 +	switch(key) {
   1.247 +	case 'q':
   1.248 +	case 27:
   1.249 +		return 0;
   1.250 +
   1.251 +	case ' ':
   1.252 +		auto_rotate = !auto_rotate;
   1.253 +		break;
   1.254 +
   1.255 +	case 'p':
   1.256 +		prim = (prim + 1) % NUM_PRIMS;
   1.257 +		break;
   1.258 +
   1.259 +	default:
   1.260 +		break;
   1.261 +	}
   1.262 +	return 1;
   1.263 +}
   1.264 +
   1.265 +static int bnstate;
   1.266 +static int prev_x, prev_y;
   1.267 +
   1.268 +static void mouse_button(int bn, int x, int y)
   1.269 +{
   1.270 +	bnstate = bn;
   1.271 +	prev_x = x;
   1.272 +	prev_y = y;
   1.273 +}
   1.274 +
   1.275 +static void mouse_motion(int x, int y)
   1.276 +{
   1.277 +	int dx, dy;
   1.278 +
   1.279 +	dx = x - prev_x;
   1.280 +	dy = y - prev_y;
   1.281 +	prev_x = x;
   1.282 +	prev_y = y;
   1.283 +
   1.284 +	if(bnstate) {
   1.285 +		cam_theta += dx;
   1.286 +		cam_phi += dy;
   1.287 +
   1.288 +		if(cam_phi > 90) cam_phi = 90;
   1.289 +		if(cam_phi < -90) cam_phi = -90;
   1.290 +	}
   1.291 +}
   1.292 +
   1.293 +static void sighandler(int s)
   1.294 +{
   1.295 +	set_video_mode(3);
   1.296 +
   1.297 +	switch(s) {
   1.298 +	case SIGABRT:
   1.299 +		fprintf(stderr, "abort\n");
   1.300 +		break;
   1.301 +
   1.302 +	case SIGILL:
   1.303 +		fprintf(stderr, "illegal operation\n");
   1.304 +		break;
   1.305 +
   1.306 +	case SIGSEGV:
   1.307 +		fprintf(stderr, "segmentation fault\n");
   1.308 +		break;
   1.309 +
   1.310 +	case SIGINT:
   1.311 +		fprintf(stderr, "interrupted\n");
   1.312 +		break;
   1.313 +
   1.314 +	case SIGFPE:
   1.315 +		fprintf(stderr, "floating point exception\n");
   1.316 +		break;
   1.317 +
   1.318 +	default:
   1.319 +		fprintf(stderr, "unexpected signal\n");
   1.320 +	}
   1.321 +
   1.322 +	exit(1);
   1.323 +}
   1.324 +
   1.325 +static int parse_args(int argc, char **argv)
   1.326 +{
   1.327 +	int i;
   1.328 +
   1.329 +	for(i=1; i<argc; i++) {
   1.330 +		if(argv[i][0] == '-') {
   1.331 +			if(argv[i][2] != 0) {
   1.332 +				goto invalid;
   1.333 +			}
   1.334 +			switch(argv[i][1]) {
   1.335 +			case 'a':
   1.336 +				auto_rotate = !auto_rotate;
   1.337 +				break;
   1.338 +
   1.339 +			case 'v':
   1.340 +				use_vsync = !use_vsync;
   1.341 +				break;
   1.342 +
   1.343 +			case 'p':
   1.344 +				if(strcmp(argv[++i], "cube") == 0) {
   1.345 +					prim = CUBE;
   1.346 +				} else if(strcmp(argv[i], "sphere") == 0) {
   1.347 +					prim = SPHERE;
   1.348 +				} else if(strcmp(argv[i], "torus") == 0) {
   1.349 +					prim = TORUS;
   1.350 +				} else {
   1.351 +					goto invalid;
   1.352 +				}
   1.353 +				break;
   1.354 +
   1.355 +			case 'w':
   1.356 +				under_windows = 1;
   1.357 +				break;
   1.358 +
   1.359 +			case 'h':
   1.360 +				printf("Usage %s [options]\n", argv[0]);
   1.361 +				printf("options:\n");
   1.362 +				printf(" -p  select one of (cube|sphere|torus)\n");
   1.363 +				printf(" -v  use vsync\n");
   1.364 +				printf(" -w  run under windows\n");
   1.365 +				printf(" -h  print usage information and exit\n");
   1.366 +				exit(0);
   1.367 +
   1.368 +			default:
   1.369 +				goto invalid;
   1.370 +			}
   1.371 +		} else {
   1.372 +			goto invalid;
   1.373 +		}
   1.374 +	}
   1.375 +
   1.376 +	return 0;
   1.377 +
   1.378 +invalid:
   1.379 +	fprintf(stderr, "invalid argument: %s\n", argv[i]);
   1.380 +	return -1;
   1.381 +}
   1.382 +
   1.383 +
   1.384 +static void print_perf(void)
   1.385 +{
   1.386 +	unsigned long msec, avg_frame_time;
   1.387 +	float sec, fps;
   1.388 +
   1.389 +	msec = get_msec();
   1.390 +	if(!num_frm || msec < 1000) {
   1.391 +		printf("leaving so soon? (%lu ms)\n", msec);
   1.392 +		return;
   1.393 +	}
   1.394 +
   1.395 +	sec = msec / 1000.0f;
   1.396 +	fps = (float)num_frm / sec;
   1.397 +	avg_frame_time = msec / num_frm;
   1.398 +
   1.399 +	printf("%lu frames in %.2f seconds\n", num_frm, sec);
   1.400 +	printf("  avg. frame time: %lu ms\n", avg_frame_time);
   1.401 +	printf("  avg. framerate: %.2f fps\n", fps);
   1.402 +}