# HG changeset patch # User John Tsiombikas # Date 1379805690 -10800 # Node ID 5ff8ce78059ad989c3a6233fe7219586810bce99 # Parent ad6b185723cd03962911d2b437d194c5b926502c first pass at converting the rasterizer to fixed point diff -r ad6b185723cd -r 5ff8ce78059a Makefile --- a/Makefile Sat Sep 21 20:18:28 2013 +0300 +++ b/Makefile Sun Sep 22 02:21:30 2013 +0300 @@ -1,14 +1,15 @@ obj = src/test.o \ src/mingl.o src/mglrast.o src/mglgen.o \ src/texture.o src/palman.o \ - src/scene.o src/cvec.o \ + src/scene.o src/cvec.o src/fixed_point.o \ dosemu/dosemu.o dep = $(obj:.o=.d) -bin = test +bin = deepstone CC = gcc CFLAGS = -pedantic -Wall -g `pkg-config --cflags sdl` -Isrc -Idosemu -LDFLAGS = `pkg-config --libs sdl` +#-DRAST_FLOAT -DDBG_USE_FLOAT +LDFLAGS = `pkg-config --libs sdl` -lm $(bin): $(obj) $(CC) -o $@ $(obj) $(LDFLAGS) diff -r ad6b185723cd -r 5ff8ce78059a dosemu/dosemu.c --- a/dosemu/dosemu.c Sat Sep 21 20:18:28 2013 +0300 +++ b/dosemu/dosemu.c Sun Sep 22 02:21:30 2013 +0300 @@ -38,6 +38,7 @@ fprintf(stderr, "failed to set video mode\n"); abort(); } + SDL_WM_SetCaption("Deepstone", 0); SDL_ShowCursor(0); SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); break; diff -r ad6b185723cd -r 5ff8ce78059a src/fixed_point.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fixed_point.c Sun Sep 22 02:21:30 2013 +0300 @@ -0,0 +1,52 @@ +#include +#include "fixed_point.h" + +const fixed fixed_zero = 0; +const fixed fixed_one = fixedi(1); +const fixed fixed_half = fixedf(0.5); +const fixed fixed_tenth = fixedf(0.1); +const fixed fixed_255 = fixedi(255); + +#ifndef DBG_USE_FLOAT + +#define PI 3.1415927 +#define TWO_PI 6.2831853 + +#define LUT_SIZE 256 + +static fixed sin_lut[LUT_SIZE], cos_lut[LUT_SIZE]; +static int initialized; + +static void precalc_lut(void) +{ + int i; + + for(i=0; i= 0 ? sin_lut[a] : -sin_lut[-a]; +} + +fixed fixed_cos(fixed angle) { + int a; + + if(!initialized) precalc_lut(); + a = FIXED_INT_PART(fixed_div(angle, fix_two_pi) * 255) % 256; + return a >= 0 ? cos_lut[a] : cos_lut[-a]; +} + +#endif diff -r ad6b185723cd -r 5ff8ce78059a src/fixed_point.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fixed_point.h Sun Sep 22 02:21:30 2013 +0300 @@ -0,0 +1,106 @@ +#ifndef FIXED_POINT_H_ +#define FIXED_POINT_H_ + +#include "inttypes.h" + +#ifdef DBG_USE_FLOAT +typedef float fixed; +#else +typedef int32_t fixed; +#endif + +/* valid choices for DECIMAL_BITS + * 8: for fixed point 24:8 + * 16: for fixed point 16:16 + */ +#define DECIMAL_BITS 16 + +#if DECIMAL_BITS == 8 +#define FIXED_SHIFT 8 +#define FLT_SCALE 256.0f +#define FRAC_MASK 0xff +#else /* DECIMAL_BITS == 16 */ +#define FIXED_SHIFT 16 +#define FLT_SCALE 65536.0f +#define FRAC_MASK 0xffff +#endif /* DECIMAL_BITS */ + +/*extern const fixed fixed_zero; +extern const fixed fixed_one; +extern const fixed fixed_half; +extern const fixed fixed_tenth; +extern const fixed fixed_255;*/ + +#ifdef DBG_USE_FLOAT +/* ------- debug mode, use floating point -------- */ +#define FIXED_INT_PART(n) ((int)(n)) +#define FIXED_FRAC_PART(n) ((n) > 0.0f ? (FIXED_INT_PART(n) - (n)) : (FIXED_INT_PART(n) + (n))) +#define FIXED_ROUND(n) FIXED_INT_PART((n) >= 0.0 ? (n) + 0.5f : (n) - 0.5f) + +#define FIXED_TO_FLOAT(n) (n) +#define FLOAT_TO_FIXED(n) (n) +#define INT_TO_FIXED(n) ((float)(n)) + +#define FIXED_EPSILON (1e-6) + +#else /* ---- really fixed point ---- */ + +#define FIXED_INT_PART(n) ((n) >> FIXED_SHIFT) +#define FIXED_FRAC_PART(n) ((n) & FRAC_MASK) +#define FIXED_ROUND(n) FIXED_INT_PART((n) >= 0 ? (n) + fixedf(0.5) : (n) - fixedf(0.5)) +/*#define FIXED_ROUND(n) FIXED_INT_PART(n)*/ + +#define FIXED_TO_FLOAT(n) (float)((n) / FLT_SCALE) +#define FLOAT_TO_FIXED(n) (fixed)((n) * FLT_SCALE) +#define INT_TO_FIXED(n) (fixed)((n) << FIXED_SHIFT) + +#define FIXED_EPSILON (1) + +#endif + + +#define fixed_int(n) FIXED_INT_PART(n) +#define fixed_frac(n) FIXED_FRAC_PART(n) +#define fixed_float(n) FIXED_TO_FLOAT(n) +#define fixed_round(n) FIXED_ROUND(n) + +#define fixedf(n) FLOAT_TO_FIXED(n) +#define fixedi(n) INT_TO_FIXED(n) + +#define fixed_add(n1, n2) ((n1) + (n2)) +#define fixed_sub(n1, n2) ((n1) - (n2)) + + + +#ifdef DBG_USE_FLOAT + +#define fixed_mul(n1, n2) ((n1) * (n2)) +#define fixed_div(n1, n2) ((n1) / (n2)) + +#define fixed_sin(x) (fixed)sin(x) +#define fixed_cos(x) (fixed)cos(x) + +#else + +#if DECIMAL_BITS == 8 +#define fixed_mul(n1, n2) (fixed)((n1) * (n2) >> FIXED_SHIFT) +#define fixed_div(n1, n2) (((n1) << FIXED_SHIFT) / (n2)) +#else +#define fixed_div(n1, n2) (((int64_t)(n1) << FIXED_SHIFT) / (int64_t)(n2)) +#define fixed_mul(n1, n2) (((n1) >> 8) * ((n2) >> 8)) +#endif /* DECIMAL_BITS */ + +#ifdef __cplusplus +extern "C" { +#endif + +fixed fixed_sin(fixed angle); +fixed fixed_cos(fixed angle); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif /* FIXED_POINT_H_ */ diff -r ad6b185723cd -r 5ff8ce78059a src/mglimpl.h --- a/src/mglimpl.h Sat Sep 21 20:18:28 2013 +0300 +++ b/src/mglimpl.h Sun Sep 22 02:21:30 2013 +0300 @@ -26,6 +26,14 @@ int cidx; }; +struct fixed_vertex { + vec4x_t pos; + vec4x_t norm; + vec2x_t tc; + fixed energy; + int cidx; +}; + struct texture { int width, height; int xshift, yshift; @@ -57,6 +65,25 @@ }; +#define vertex_to_fixedvertex(v, vx) \ + do { \ + vec4_to_fixed4((v).pos, (vx).pos); \ + vec3_to_fixed3((v).norm, (vx).norm); \ + vec2_to_fixed2((v).tc, (vx).tc); \ + (vx).energy = fixedf((v).energy); \ + (vx).cidx = (v).cidx; \ + } while(0) + +#define fixedvertex_to_vertex(vx, v) \ + do { \ + fixed4_to_vec4((vx).pos, (v).pos); \ + fixed3_to_vec3((vx).norm, (v).norm); \ + fixed2_to_vec2((vx).tc, (v).tc); \ + (v).energy = fixed_float((vx).energy); \ + (v).cidx = (vx).cidx; \ + } while(0) + + int mgl_rast_init(struct state *state, struct framebuffer *fbuf); void mgl_rast_cleanup(void); void mgl_rast_prepare(void); diff -r ad6b185723cd -r 5ff8ce78059a src/mglrast.c --- a/src/mglrast.c Sat Sep 21 20:18:28 2013 +0300 +++ b/src/mglrast.c Sun Sep 22 02:21:30 2013 +0300 @@ -1,20 +1,3 @@ -/* -256-color 3D graphics hack for real-mode DOS. -Copyright (C) 2011 John Tsiombikas - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ #include #include #include @@ -24,7 +7,13 @@ #include "mglimpl.h" -static struct vertex *vleft, *vright; +#ifdef RAST_FLOAT +typedef struct vertex VERTEX; +#else +typedef struct fixed_vertex VERTEX; +#endif + +static VERTEX *vleft, *vright; static struct framebuffer *fb; static struct state *st; @@ -102,9 +91,10 @@ #undef SCAN_LINE -static void (*scan_edge)(struct vertex*, struct vertex*); +static void (*scan_edge)(VERTEX*, VERTEX*); static void (*scan_line)(int, unsigned char*); + int mgl_rast_init(struct state *state, struct framebuffer *fbuf) { fb = fbuf; @@ -132,7 +122,7 @@ void mgl_rast_prepare(void) { - static void (*sedge[])(struct vertex*, struct vertex*) = { + static void (*sedge[])(VERTEX*, VERTEX*) = { /* tez */ scan_edge_flat, /* 000 */ scan_edge_z, /* 001 */ @@ -190,6 +180,7 @@ void mgl_draw_poly(struct vertex *v, int numv) { +#ifdef RAST_FLOAT int ybeg, yend, i; unsigned char *sline; @@ -215,4 +206,37 @@ scan_line(i, sline); sline += fb->width; } +#else + int ybeg, yend, i; + unsigned char *sline; + + ybeg = fb->height; + yend = 0; + + for(i=0; i yend) yend = y; + if(y < ybeg) ybeg = y; + } + + if(ybeg < 0) ybeg = 0; + if(yend >= fb->height) yend = fb->height - 1; + + sline = fb->pixels + ybeg * fb->width; + for(i=ybeg; iwidth; + } +#endif } diff -r ad6b185723cd -r 5ff8ce78059a src/scantmpl.h --- a/src/scantmpl.h Sat Sep 21 20:18:28 2013 +0300 +++ b/src/scantmpl.h Sun Sep 22 02:21:30 2013 +0300 @@ -1,61 +1,44 @@ -/* -256-color 3D graphics hack for real-mode DOS. -Copyright (C) 2011 John Tsiombikas - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -static void SCAN_EDGE(struct vertex *v0, struct vertex *v1) +static void SCAN_EDGE(VERTEX *v0, VERTEX *v1) { int i, start, end; - float dx, dy, dfdx; + fixed dx, dy, dfdx; #ifdef INTERP_DEPTH - float z, dz, dfdz; + fixed z, dz, dfdz; #endif #ifdef INTERP_ENERGY - float e, de, dfde; + fixed e, de, dfde; #endif #ifdef INTERP_TEX - float u, v, du, dv, dfdu, dfdv; + fixed u, v, du, dv, dfdu, dfdv; #endif - float x; - struct vertex *edge; + fixed x; + VERTEX *edge; dy = v1->pos.y - v0->pos.y; - if(dy < 1e-6 && dy > -1e-6) { + if(dy < FIXED_EPSILON && dy > -FIXED_EPSILON) { return; } dx = v1->pos.x - v0->pos.x; - dfdx = dx / dy; + dfdx = fixed_div(dx, dy); #ifdef INTERP_DEPTH dz = v1->pos.z - v0->pos.z; - dfdz = dz / dy; + dfdz = fixed_div(dz, dy); #endif #ifdef INTERP_ENERGY de = v1->energy - v0->energy; - dfde = de / dy; + dfde = fixed_div(de, dy); #endif #ifdef INTERP_TEX du = v1->tc.x - v0->tc.x; dv = v1->tc.y - v0->tc.y; - dfdu = du / dy; - dfdv = dv / dy; + dfdu = fixed_div(du, dy); + dfdv = fixed_div(dv, dy); #endif - if(dy < 0.0) { - struct vertex *tmp = v0; + if(dy < 0) { + VERTEX *tmp = v0; v0 = v1; v1 = tmp; edge = (st->ord == MGL_CCW) ? vright : vleft; @@ -63,8 +46,8 @@ edge = (st->ord == MGL_CCW) ? vleft : vright; } - start = (int)ROUND(v0->pos.y); - end = (int)ROUND(v1->pos.y); + start = (int)fixed_round(v0->pos.y); + end = (int)fixed_round(v1->pos.y); if(start >= 0) { @@ -80,18 +63,18 @@ v = v0->tc.y; #endif } else { - float lines = -v0->pos.y; + fixed lines = -v0->pos.y; - x = v0->pos.x + dfdx * lines; + x = v0->pos.x + fixed_mul(dfdx, lines); #ifdef INTERP_DEPTH - z = v0->pos.z + dfdz * lines; + z = v0->pos.z + fixed_mul(dfdz, lines); #endif #ifdef INTERP_ENERGY - e = v0->energy + dfde * lines; + e = v0->energy + fixed_mul(dfde, lines); #endif #ifdef INTERP_TEX - u = v0->tc.x + dfdu * lines; - v = v0->tc.y + dfdv * lines; + u = v0->tc.x + fixed_mul(dfdu, lines); + v = v0->tc.y + fixed_mul(dfdv, lines); #endif start = 0; } @@ -132,22 +115,22 @@ int x0, x1, len, tmp, cidx; #if defined(INTERP_DEPTH) || defined(INTERP_ENERGY) || defined(INTERP_TEX) int i; - float x, dx; + fixed x, dx; #endif #ifdef INTERP_DEPTH - float z, dz, dfdz; + fixed z, dz, dfdz; #endif #ifdef INTERP_ENERGY - float e, de, dfde; + fixed e, de, dfde; #endif #ifdef INTERP_TEX unsigned int tx, ty; - float u, v, du, dv, dfdu, dfdv; + fixed u, v, du, dv, dfdu, dfdv; #endif - struct vertex *left, *right; + VERTEX *left, *right; - x0 = (int)ROUND(vleft[y].pos.x); - x1 = (int)ROUND(vright[y].pos.x); + x0 = (int)fixed_round(vleft[y].pos.x); + x1 = (int)fixed_round(vright[y].pos.x); if(x1 < x0) { if(st->flags & MGL_CULL_FACE) { @@ -174,13 +157,13 @@ len = x1 - x0; assert(len >= 0); /* no interpolation at all, just memset the whole scanline */ - memset(sline + x0, cidx + left[y].energy * st->col_range, len); + memset(sline + x0, cidx + fixed_int(fixed_mul(left[y].energy, fixedi(st->col_range))), len); #else /* otherwise do a loop and interpolate whatever needs interpolating */ x = left[y].pos.x; dx = right[y].pos.x - x; - if(dx < 0.5 && dx > -0.5) { + if(dx < fixedf(0.5) && dx > -fixedf(0.5)) { return; } @@ -188,41 +171,41 @@ #ifdef INTERP_DEPTH z = left[y].pos.z; dz = right[y].pos.z - z; - dfdz = dz / dx; + dfdz = fixed_div(dz, dx); #endif #ifdef INTERP_ENERGY e = left[y].energy; de = right[y].energy - e; - dfde = de / dx; + dfde = fixed_div(de, dx); #endif #ifdef INTERP_TEX u = left[y].tc.x; v = left[y].tc.y; du = right[y].tc.x - u; dv = right[y].tc.y - v; - dfdu = du / dx; - dfdv = dv / dx; + dfdu = fixed_div(du, dx); + dfdv = fixed_div(dv, dx); #endif } else { - float dist = -left[y].pos.x; + fixed dist = -left[y].pos.x; #ifdef INTERP_DEPTH dz = right[y].pos.z - left[y].pos.z; - dfdz = dz / dx; - z = left[y].pos.z + dfdz * dist; + dfdz = fixed_div(dz, dx); + z = left[y].pos.z + fixed_mul(dfdz, dist); #endif #ifdef INTERP_ENERGY de = right[y].energy - left[y].energy; - dfde = de / dx; - e = left[y].energy + dfde * dist; + dfde = fixed_div(de, dx); + e = left[y].energy + fixed_mul(dfde, dist); #endif #ifdef INTERP_TEX du = right[y].tc.x - left[y].tc.x; dv = right[y].tc.y - left[y].tc.y; - dfdu = du / dx; - dfdv = dv / dx; - u = left[y].tc.x + dfdu * dist; - v = left[y].tc.y + dfdv * dist; + dfdu = fixed_div(du, dx); + dfdv = fixed_div(dv, dx); + u = left[y].tc.x + fixed_mul(dfdu, dist); + v = left[y].tc.y + fixed_mul(dfdv, dist); #endif x0 = 0; } @@ -234,10 +217,14 @@ #ifdef INTERP_DEPTH long pix = (sline + x0 + i) - fb->pixels; +#ifdef RAST_FLOAT unsigned short zval = (unsigned short)(z * USHRT_MAX); +#else + unsigned short zval = (unsigned short)((z >> 1) & 0xffff); +#endif unsigned short *zptr = fb->zbuf[ZTILE(pix)] + ZTILE_OFFS(pix); - if(z < 0.0 || z >= 1.0 || zval > *zptr) { + if(z < 0 || z >= fixedi(1) || zval > *zptr) { # ifdef INTERP_TEX u += dfdu; v += dfdv; @@ -253,18 +240,18 @@ z += dfdz; #endif #ifdef INTERP_TEX - tx = (unsigned int)(u * st->tex.width) & st->tex.xmask; - ty = (unsigned int)(v * st->tex.height) & st->tex.ymask; + tx = (unsigned int)fixed_int(fixed_mul(u, fixedi(st->tex.width))) & st->tex.xmask; + ty = (unsigned int)fixed_int(fixed_mul(v, fixedi(st->tex.height))) & st->tex.ymask; c = st->tex.pixels[(ty << st->tex.xshift) + tx]; u += dfdu; v += dfdv; #endif #ifdef INTERP_ENERGY - c += e * st->col_range; + c += fixed_int(fixed_mul(e, fixedi(st->col_range))); e += dfde; #else - c += left[y].energy * st->col_range; + c += fixed_int(fixed_mul(left[y].energy, fixedi(st->col_range))); #endif sline[x0 + i] = c; } diff -r ad6b185723cd -r 5ff8ce78059a src/test.c --- a/src/test.c Sat Sep 21 20:18:28 2013 +0300 +++ b/src/test.c Sun Sep 22 02:21:30 2013 +0300 @@ -270,6 +270,14 @@ } break; + case 'z': + if(mgl_isenabled(MGL_DEPTH_TEST)) { + mgl_disable(MGL_DEPTH_TEST); + } else { + mgl_enable(MGL_DEPTH_TEST); + } + break; + case ' ': auto_rotate = !auto_rotate; break; diff -r ad6b185723cd -r 5ff8ce78059a src/vmath.h --- a/src/vmath.h Sat Sep 21 20:18:28 2013 +0300 +++ b/src/vmath.h Sun Sep 22 02:21:30 2013 +0300 @@ -2,6 +2,7 @@ #define VMATH_H_ #include +#include "fixed_point.h" #ifndef M_PI #define M_PI 3.1415926536 @@ -19,5 +20,61 @@ float x, y; } vec2_t; +typedef struct { + fixed x, y, z, w; +} vec4x_t; + +typedef struct { + fixed x, y, z; +} vec3x_t; + +typedef struct { + fixed x, y; +} vec2x_t; + + +#define vec2_to_fixed2(v, f) \ + do { \ + f.x = fixedf(v.x); \ + f.y = fixedf(v.y); \ + } while(0) + +#define vec3_to_fixed3(v, f) \ + do { \ + f.x = fixedf(v.x); \ + f.y = fixedf(v.y); \ + f.z = fixedf(v.z); \ + } while(0) + +#define vec4_to_fixed4(v, f) \ + do { \ + f.x = fixedf(v.x); \ + f.y = fixedf(v.y); \ + f.z = fixedf(v.z); \ + f.w = fixedf(v.w); \ + } while(0) + + +#define fixed2_to_vec2(f, v) \ + do { \ + v.x = fixed_float(f.x); \ + v.y = fixed_float(f.y); \ + } while(0) + +#define fixed3_to_vec3(f, v) \ + do { \ + v.x = fixed_float(f.x); \ + v.y = fixed_float(f.y); \ + v.z = fixed_float(f.z); \ + } while(0) + +#define fixed4_to_vec4(f, v) \ + do { \ + v.x = fixed_float(f.x); \ + v.y = fixed_float(f.y); \ + v.z = fixed_float(f.z); \ + v.w = fixed_float(f.w); \ + } while(0) + #endif /* VMATH_H_ */