From 3616caf014bccbf8814a67cf87ac012a91e7e968 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sun, 2 Oct 2016 22:09:29 +0300 Subject: [PATCH 01/16] sucks, maybe I should try integer rasterization with error accumulation... --- src/polyfill.c | 121 +++++++++++++++++++++++++++++--------------------------- src/polytest.c | 2 +- 2 files changed, 64 insertions(+), 59 deletions(-) diff --git a/src/polyfill.c b/src/polyfill.c index 79d1d69..7bffaa3 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -1,5 +1,8 @@ #include #include +#include +#include +#include #include "polyfill.h" #include "gfxutil.h" #include "demo.h" @@ -48,82 +51,84 @@ void polyfill_wire(struct pvertex *verts, int nverts) } } +static void scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge); + #define NEXTIDX(x) (((x) - 1 + nverts) % nverts) #define PREVIDX(x) (((x) + 1) % nverts) -#define CALC_EDGE(which) \ - do { \ - which##_x = pv[which##_beg].x; \ - which##_dx = pv[which##_end].x - pv[which##_beg].x; \ - which##_slope = (which##_dx << 8) / which##_dy; \ - } while(0) - void polyfill_flat(struct pvertex *pv, int nverts) { - int i, sline, x, slen, top = 0; - int left_beg, left_end, right_beg, right_end; - int32_t left_dy, left_dx, right_dy, right_dx; - int32_t left_slope, right_slope; - int32_t left_x, right_x, y; - uint16_t color = ((pv->r << 8) & 0xf800) | ((pv->g << 3) & 0x7e0) | - ((pv->b >> 3) & 0x1f); - uint16_t *pixptr; - - /* find topmost */ + int i; + int32_t y; + int topidx = 0, botidx = 0, sline; + struct pvertex *left, *right; + /*uint16_t color = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b);*/ + for(i=1; i pv[botidx].y) botidx = i; } - left_beg = right_beg = top; - left_end = PREVIDX(left_beg); - right_end = NEXTIDX(right_beg); - if((left_dy = pv[left_end].y - pv[left_beg].y)) { - CALC_EDGE(left); + left = (struct pvertex*)alloca(pimg_fb.height * sizeof *left); + right = (struct pvertex*)alloca(pimg_fb.height * sizeof *right); + memset(left, 0, pimg_fb.height * sizeof *left); + memset(right, 0, pimg_fb.height * sizeof *right); + + for(i=0; i> 8) == (y1 >> 8)) { + if(y0 > y1) { + int idx = y0 >> 8; + left[idx].x = pv[i].x < pv[next].x ? pv[i].x : pv[next].x; + right[idx].x = pv[i].x < pv[next].x ? pv[next].x : pv[i].x; + } + } else { + scan_edge(pv + i, pv + next, y0 > y1 ? left : right); + } } - if((right_dy = pv[right_end].y - pv[right_beg].y)) { - CALC_EDGE(right); - } + y = pv[topidx].y; + while(y < pv[botidx].y) { + int32_t x; + uint16_t *pixptr; - y = pv[top].y; - sline = pv[top].y >> 8; + sline = y >> 8; + x = left[sline].x; - for(;;) { - if(y >= pv[left_end].y) { - while(y >= pv[left_end].y) { - left_beg = left_end; - if(left_beg == right_beg) return; - left_end = PREVIDX(left_end); - } + pixptr = pimg_fb.pixels + sline * pimg_fb.width + (x >> 8); - left_dy = pv[left_end].y - pv[left_beg].y; - CALC_EDGE(left); + while(x <= right[sline].x) { + *pixptr++ += 15; + x += 256; } + y += 256; + } +} - if(y >= pv[right_end].y) { - while(y >= pv[right_end].y) { - right_beg = right_end; - if(left_beg == right_beg) return; - right_end = NEXTIDX(right_end); - } - - right_dy = pv[right_end].y - pv[right_beg].y; - CALC_EDGE(right); - } +static void scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge) +{ + int32_t x, y, dx, dy, slope; + int idx; - x = left_x >> 8; - slen = (right_x >> 8) - (left_x >> 8); + if(v0->y > v1->y) { + struct pvertex *tmp = v0; + v0 = v1; + v1 = tmp; + } - pixptr = pimg_fb.pixels + sline * pimg_fb.width + x; - for(i=0; iy - v0->y; + dx = v1->x - v0->x; + slope = (dx << 8) / dy; + idx = v0->y >> 8; - ++sline; + x = v0->x; + y = v0->y; + while(y <= v1->y) { + edge[idx++].x = x; + x += slope; y += 256; - left_x += left_slope; - right_x += right_slope; } } diff --git a/src/polytest.c b/src/polytest.c index b9ad891..b81e9aa 100644 --- a/src/polytest.c +++ b/src/polytest.c @@ -35,7 +35,7 @@ static struct screen scr = { static float theta, phi = 25; static struct mesh cube, torus; -#define LOWRES_SCALE 16 +#define LOWRES_SCALE 10 static uint16_t *lowres_pixels; static int lowres_width, lowres_height; -- 1.7.10.4 From dce48eb322ddf2a3c3622fc132ece21ba7653da3 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 3 Oct 2016 06:41:01 +0300 Subject: [PATCH 02/16] much better, not perfect --- src/polyfill.c | 50 +++++++++++++++++++++++++++++--------------------- src/polytest.c | 25 ++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/polyfill.c b/src/polyfill.c index 7bffaa3..122b234 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -51,7 +51,7 @@ void polyfill_wire(struct pvertex *verts, int nverts) } } -static void scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge); +static uint32_t scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge); #define NEXTIDX(x) (((x) - 1 + nverts) % nverts) #define PREVIDX(x) (((x) + 1) % nverts) @@ -59,10 +59,9 @@ static void scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *ed void polyfill_flat(struct pvertex *pv, int nverts) { int i; - int32_t y; - int topidx = 0, botidx = 0, sline; + int topidx = 0, botidx = 0, sltop = pimg_fb.height, slbot = 0; struct pvertex *left, *right; - /*uint16_t color = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b);*/ + uint16_t color = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b); for(i=1; i y1 ? left : right); + struct pvertex *edge = y0 > y1 ? left : right; + uint32_t res = scan_edge(pv + i, pv + next, edge); + uint32_t tmp = (res >> 16) & 0xffff; + if(tmp > slbot) slbot = tmp; + if((tmp = res & 0xffff) < sltop) { + sltop = tmp; + } } } - y = pv[topidx].y; - while(y < pv[botidx].y) { + for(i=sltop; i<=slbot; i++) { int32_t x; uint16_t *pixptr; - sline = y >> 8; - x = left[sline].x; - - pixptr = pimg_fb.pixels + sline * pimg_fb.width + (x >> 8); + x = left[i].x; + pixptr = pimg_fb.pixels + i * pimg_fb.width + (x >> 8); - while(x <= right[sline].x) { + while(x <= right[i].x) { +#ifdef DEBUG_POLYFILL *pixptr++ += 15; +#else + *pixptr++ = color; +#endif x += 256; } - y += 256; } } -static void scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge) +static uint32_t scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge) { - int32_t x, y, dx, dy, slope; - int idx; + int i; + int32_t x, dx, dy, slope; + int32_t start_idx, end_idx; if(v0->y > v1->y) { struct pvertex *tmp = v0; @@ -122,13 +128,15 @@ static void scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *ed dy = v1->y - v0->y; dx = v1->x - v0->x; slope = (dx << 8) / dy; - idx = v0->y >> 8; + + start_idx = v0->y >> 8; + end_idx = v1->y >> 8; x = v0->x; - y = v0->y; - while(y <= v1->y) { - edge[idx++].x = x; + for(i=start_idx; i Date: Mon, 3 Oct 2016 07:41:39 +0300 Subject: [PATCH 03/16] added lighting --- src/3dgfx.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/3dgfx.h | 15 +++++++- src/polytest.c | 6 +++ 3 files changed, 134 insertions(+), 2 deletions(-) diff --git a/src/3dgfx.c b/src/3dgfx.c index 41b3959..30721c8 100644 --- a/src/3dgfx.c +++ b/src/3dgfx.c @@ -11,6 +11,18 @@ typedef float g3d_matrix[16]; #define MAX_VBUF_SIZE 256 +#define MAX_LIGHTS 4 + +struct light { + float x, y, z; + float r, g, b; +}; + +struct material { + float kd[3]; + float ks[3]; + float shin; +}; struct g3d_state { unsigned int opt; @@ -23,6 +35,10 @@ struct g3d_state { g3d_matrix norm_mat; + float ambient[3]; + struct light lt[MAX_LIGHTS]; + struct material mtl; + int width, height; void *pixels; }; @@ -53,6 +69,13 @@ int g3d_init(void) g3d_matrix_mode(i); g3d_load_identity(); } + + for(i=0; imat[which][top]; } +void g3d_light_pos(int idx, float x, float y, float z) +{ + int mvtop = st->mtop[G3D_MODELVIEW]; + + st->lt[idx].x = x; + st->lt[idx].y = y; + st->lt[idx].z = z; + + xform4_vec3(st->mat[G3D_MODELVIEW][mvtop], &st->lt[idx].x); +} + +void g3d_light_color(int idx, float r, float g, float b) +{ + st->lt[idx].r = r; + st->lt[idx].g = g; + st->lt[idx].b = b; +} + +void g3d_light_ambient(float r, float g, float b) +{ + st->ambient[0] = r; + st->ambient[1] = g; + st->ambient[2] = b; +} + +void g3d_mtl_diffuse(float r, float g, float b) +{ + st->mtl.kd[0] = r; + st->mtl.kd[1] = g; + st->mtl.kd[2] = b; +} + +void g3d_mtl_specular(float r, float g, float b) +{ + st->mtl.ks[0] = r; + st->mtl.ks[1] = g; + st->mtl.ks[2] = b; +} + +void g3d_mtl_shininess(float shin) +{ + st->mtl.shin = shin; +} + void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size) { g3d_draw_indexed(prim, varr, varr_size, 0, 0); @@ -374,7 +441,53 @@ static void xform3_vec3(const float *mat, float *vec) vec[2] = z; } +#define NORMALIZE(v) \ + do { \ + float len = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); \ + if(len != 0.0) { \ + float s = 1.0 / len; \ + v[0] *= s; \ + v[1] *= s; \ + v[2] *= s; \ + } \ + } while(0) + static void shade(struct g3d_vertex *v) { - v->r = v->g = v->b = 255; + int i, r, g, b; + float color[3]; + + color[0] = st->ambient[0] * st->mtl.kd[0]; + color[1] = st->ambient[1] * st->mtl.kd[1]; + color[2] = st->ambient[2] * st->mtl.kd[2]; + + for(i=0; iopt & (G3D_LIGHT0 << i))) { + continue; + } + + ldir[0] = st->lt[i].x - v->x; + ldir[1] = st->lt[i].y - v->y; + ldir[2] = st->lt[i].z - v->z; + NORMALIZE(ldir); + + if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) { + ndotl = 0.0f; + } + + color[0] += st->mtl.kd[0] * st->lt[i].r * ndotl; + color[1] += st->mtl.kd[1] * st->lt[i].g * ndotl; + color[2] += st->mtl.kd[2] * st->lt[i].b * ndotl; + } + + r = color[0] * 255.0; + g = color[1] * 255.0; + b = color[2] * 255.0; + + v->r = r > 255 ? 255 : r; + v->g = g > 255 ? 255 : g; + v->b = b > 255 ? 255 : b; } diff --git a/src/3dgfx.h b/src/3dgfx.h index 4a3cde5..ee9de63 100644 --- a/src/3dgfx.h +++ b/src/3dgfx.h @@ -22,7 +22,11 @@ enum { G3D_CULL_FACE = 1, G3D_DEPTH_TEST = 2, /* XXX not implemented */ G3D_LIGHTING = 4, - G3D_TEXTURE = 8, + G3D_LIGHT0 = 8, + G3D_LIGHT1 = 16, + G3D_LIGHT2 = 32, + G3D_LIGHT3 = 64, + G3D_TEXTURE = 128, G3D_ALL = 0x7fffffff }; @@ -74,6 +78,15 @@ void g3d_perspective(float vfov, float aspect, float znear, float zfar); const float *g3d_get_matrix(int which, float *m); +void g3d_light_pos(int idx, float x, float y, float z); +void g3d_light_color(int idx, float r, float g, float b); + +void g3d_light_ambient(float r, float g, float b); + +void g3d_mtl_diffuse(float r, float g, float b); +void g3d_mtl_specular(float r, float g, float b); +void g3d_mtl_shininess(float shin); + void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size); void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, const int16_t *iarr, int iarr_size); diff --git a/src/polytest.c b/src/polytest.c index 826b0b0..58fdb41 100644 --- a/src/polytest.c +++ b/src/polytest.c @@ -74,6 +74,8 @@ static void start(long trans_time) g3d_perspective(50.0, 1.3333333, 0.5, 100.0); g3d_enable(G3D_CULL_FACE); + g3d_enable(G3D_LIGHTING); + g3d_enable(G3D_LIGHT0); } static void update(void) @@ -113,7 +115,11 @@ static void draw(void) g3d_rotate(phi, 1, 0, 0); g3d_rotate(theta, 0, 1, 0); + g3d_light_pos(0, -10, 10, 20); + zsort(&torus); + + g3d_mtl_diffuse(0.3, 0.6, 1.0); draw_mesh(&torus); /*draw_mesh(&cube);*/ -- 1.7.10.4 From ee4a19d1405ea1ee7fbbeef1cdf71292d21f353a Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 3 Oct 2016 08:09:59 +0300 Subject: [PATCH 04/16] use the fast double->int conversion in 3dgfx.c --- src/3dgfx.c | 15 ++++++++------- src/util.h | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 src/util.h diff --git a/src/3dgfx.c b/src/3dgfx.c index 30721c8..d7e2e41 100644 --- a/src/3dgfx.c +++ b/src/3dgfx.c @@ -6,6 +6,7 @@ #include "3dgfx.h" #include "polyfill.h" #include "inttypes.h" +#include "util.h" #define STACK_SIZE 8 typedef float g3d_matrix[16]; @@ -388,11 +389,11 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->height; /* convert pos to 24.8 fixed point */ - pv[i].x = (int32_t)(v[i].x * 256.0f); - pv[i].y = (int32_t)(v[i].y * 256.0f); + pv[i].x = cround64(v[i].x * 256.0f); + pv[i].y = cround64(v[i].y * 256.0f); /* convert tex coords to 16.16 fixed point */ - pv[i].u = (int32_t)(v[i].u * 65536.0f); - pv[i].v = (int32_t)(v[i].v * 65536.0f); + pv[i].u = cround64(v[i].u * 65536.0f); + pv[i].v = cround64(v[i].v * 65536.0f); /* pass the color through as is */ pv[i].r = v[i].r; pv[i].g = v[i].g; @@ -483,9 +484,9 @@ static void shade(struct g3d_vertex *v) color[2] += st->mtl.kd[2] * st->lt[i].b * ndotl; } - r = color[0] * 255.0; - g = color[1] * 255.0; - b = color[2] * 255.0; + r = cround64(color[0] * 255.0); + g = cround64(color[1] * 255.0); + b = cround64(color[2] * 255.0); v->r = r > 255 ? 255 : r; v->g = g > 255 ? 255 : g; diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..eb3773d --- /dev/null +++ b/src/util.h @@ -0,0 +1,27 @@ +#ifndef UTIL_H_ +#define UTIL_H_ + +#include "inttypes.h" + +#ifdef __GNUC__ +#define INLINE __inline + +#elif defined(__WATCOMC__) +#define INLINE __inline + +#else +#define INLINE +#endif + +/* fast conversion of double -> 32bit int + * for details see: + * - http://chrishecker.com/images/f/fb/Gdmfp.pdf + * - http://stereopsis.com/FPU.html#convert + */ +static INLINE int32_t cround64(double val) +{ + val += 6755399441055744.0; + return *(int32_t*)&val; +} + +#endif /* UTIL_H_ */ -- 1.7.10.4 From 11d54c8e4c441a29031ae37a6cbf83de43b9271c Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 3 Oct 2016 08:23:00 +0300 Subject: [PATCH 05/16] forgot to conditionally include malloc.h for alloca on watcom and msvc --- src/polyfill.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/polyfill.c b/src/polyfill.c index 122b234..80bfee5 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -2,7 +2,11 @@ #include #include #include +#if defined(__WATCOMC__) || defined(_MSC_VER) +#include +#else #include +#endif #include "polyfill.h" #include "gfxutil.h" #include "demo.h" -- 1.7.10.4 From b2dd6c9916fc3ed24545eaae52e0138b558e6543 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 3 Oct 2016 09:40:03 +0300 Subject: [PATCH 06/16] added dependency tracking to the GNU makefile --- .gitignore | 1 + GNUmakefile | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index 4b4c87a..f957445 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.swp *.o +*.d *.obj *.OBJ *.exe diff --git a/GNUmakefile b/GNUmakefile index e81d771..5e3fdeb 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,5 +1,6 @@ src = $(wildcard src/*.c) $(wildcard src/sdl/*.c) obj = $(src:.c=.o) +dep = $(obj:.o=.d) bin = demo inc = -Isrc -Isrc/sdl -Ilibs/imago/src -Ilibs/mikmod/include @@ -10,6 +11,11 @@ LDFLAGS = -Llibs/imago -Llibs/mikmod -limago -lmikmod `sdl-config --libs` -lm $(bin): $(obj) imago mikmod $(CC) -o $@ $(obj) $(LDFLAGS) +-include $(dep) + +%.d: %.c + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ + .PHONY: imago imago: $(MAKE) -C libs/imago @@ -21,3 +27,7 @@ mikmod: .PHONY: clean clean: rm -f $(obj) $(bin) + +.PHONY: cleandep +cleandep: + rm -f $(dep) -- 1.7.10.4 From 6218ea71a2a175dca5bf88ca7922e97f42f85e69 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 3 Oct 2016 10:24:08 +0300 Subject: [PATCH 07/16] split the polyfiller to a preprocessor-based template file, included multiple times in polyfill.c to instanciate all the variants. currently fully implemented are: flat and gouraud. --- src/3dgfx.h | 3 +- src/polyfill.c | 121 +++++++++----------------------- src/polyfill.h | 5 +- src/polytest.c | 2 + src/polytmpl.h | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 252 insertions(+), 89 deletions(-) create mode 100644 src/polytmpl.h diff --git a/src/3dgfx.h b/src/3dgfx.h index ee9de63..ecc3f3c 100644 --- a/src/3dgfx.h +++ b/src/3dgfx.h @@ -37,7 +37,8 @@ enum { G3D_CCW, G3D_CW }; /* arg to g3d_polygon_mode */ enum { G3D_WIRE, - G3D_FLAT + G3D_FLAT, + G3D_GOURAUD, }; /* matrix stacks */ diff --git a/src/polyfill.c b/src/polyfill.c index 80bfee5..634d525 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -14,7 +14,9 @@ void (*fillfunc[])(struct pvertex*, int) = { polyfill_wire, polyfill_flat, - 0, 0, 0 + polyfill_gouraud, + polyfill_tex, + polyfill_tex_gouraud }; struct pimage pimg_fb, pimg_texture; @@ -55,92 +57,37 @@ void polyfill_wire(struct pvertex *verts, int nverts) } } -static uint32_t scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge); - #define NEXTIDX(x) (((x) - 1 + nverts) % nverts) #define PREVIDX(x) (((x) + 1) % nverts) -void polyfill_flat(struct pvertex *pv, int nverts) -{ - int i; - int topidx = 0, botidx = 0, sltop = pimg_fb.height, slbot = 0; - struct pvertex *left, *right; - uint16_t color = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b); - - for(i=1; i pv[botidx].y) botidx = i; - } - - left = (struct pvertex*)alloca(pimg_fb.height * sizeof *left); - right = (struct pvertex*)alloca(pimg_fb.height * sizeof *right); - memset(left, 0, pimg_fb.height * sizeof *left); - memset(right, 0, pimg_fb.height * sizeof *right); - - for(i=0; i> 8) == (y1 >> 8)) { - if(y0 > y1) { - int idx = y0 >> 8; - left[idx].x = pv[i].x < pv[next].x ? pv[i].x : pv[next].x; - right[idx].x = pv[i].x < pv[next].x ? pv[next].x : pv[i].x; - } - } else { - struct pvertex *edge = y0 > y1 ? left : right; - uint32_t res = scan_edge(pv + i, pv + next, edge); - uint32_t tmp = (res >> 16) & 0xffff; - if(tmp > slbot) slbot = tmp; - if((tmp = res & 0xffff) < sltop) { - sltop = tmp; - } - } - } - - for(i=sltop; i<=slbot; i++) { - int32_t x; - uint16_t *pixptr; - - x = left[i].x; - pixptr = pimg_fb.pixels + i * pimg_fb.width + (x >> 8); - - while(x <= right[i].x) { -#ifdef DEBUG_POLYFILL - *pixptr++ += 15; -#else - *pixptr++ = color; -#endif - x += 256; - } - } -} - -static uint32_t scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge) -{ - int i; - int32_t x, dx, dy, slope; - int32_t start_idx, end_idx; - - if(v0->y > v1->y) { - struct pvertex *tmp = v0; - v0 = v1; - v1 = tmp; - } - - dy = v1->y - v0->y; - dx = v1->x - v0->x; - slope = (dx << 8) / dy; - - start_idx = v0->y >> 8; - end_idx = v1->y >> 8; - - x = v0->x; - for(i=start_idx; iy > v1->y) { + struct pvertex *tmp = v0; + v0 = v1; + v1 = tmp; + } + + x = v0->x; + dy = v1->y - v0->y; + dx = v1->x - v0->x; + slope = (dx << 8) / dy; +#ifdef GOURAUD + r = (v0->r << 8); + g = (v0->g << 8); + b = (v0->b << 8); + dr = (v1->r << 8) - r; + dg = (v1->g << 8) - g; + db = (v1->b << 8) - b; + rslope = (dr << 8) / dy; + gslope = (dg << 8) / dy; + bslope = (db << 8) / dy; +#endif +#ifdef TEXMAP + u = v0->u; + v = v0->v; + du = v1->u - v0->u; + dv = v1->v - v0->v; + uslope = (du << 8) / dy; + vslope = (dv << 8) / dy; +#endif + + start_idx = v0->y >> 8; + end_idx = v1->y >> 8; + + for(i=start_idx; i pv[botidx].y) botidx = i; + } + + left = alloca(pimg_fb.height * sizeof *left); + right = alloca(pimg_fb.height * sizeof *right); + + for(i=0; i> 8) == (y1 >> 8)) { + if(y0 > y1) { + int idx = y0 >> 8; + left[idx].x = pv[i].x < pv[next].x ? pv[i].x : pv[next].x; + right[idx].x = pv[i].x < pv[next].x ? pv[next].x : pv[i].x; + } + } else { + struct pvertex *edge = y0 > y1 ? left : right; + uint32_t res = SCANEDGE(pv + i, pv + next, edge); + uint32_t tmp = (res >> 16) & 0xffff; + if(tmp > slbot) slbot = tmp; + if((tmp = res & 0xffff) < sltop) { + sltop = tmp; + } + } + } + + /* find the mid-point and calculate slopes for all attributes */ +#if 0 +#if defined(GOURAUD) || defined(TEXMAP) + mid = (sltop + slbot) >> 1; + dx = right[mid].x - left[mid].x; + if((tmp = right[sltop].x - left[sltop].x) > dx) { + dx = tmp; + mid = sltop; + } + if((tmp = right[slbot].x - left[slbot].x) > dx) { + dx = tmp; + mid = slbot; + } + if(!dx) { + dx = 256; /* 1 */ + } +#endif +#ifdef GOURAUD + dr = right[mid].r - left[mid].r; + dg = right[mid].g - left[mid].g; + db = right[mid].b - left[mid].b; + rslope = (dr << 8) / dx; + gslope = (dg << 8) / dx; + bslope = (db << 8) / dx; +#endif +#ifdef TEXMAP + du = right[mid].u - left[mid].u; + dv = right[mid].v - left[mid].v; + uslope = (du << 8) / dx; + vslope = (dv << 8) / dx; +#endif +#endif /* 0 */ + + for(i=sltop; i<=slbot; i++) { + uint16_t *pixptr; + int32_t x; + + x = left[i].x; + pixptr = pimg_fb.pixels + i * pimg_fb.width + (x >> 8); + +#if defined(GOURAUD) || defined(TEXMAP) + if(!(dx = right[i].x - left[i].x)) dx = 256; /* 1 */ +#endif +#ifdef GOURAUD + r = left[i].r; + g = left[i].g; + b = left[i].b; + dr = right[i].r - left[i].r; + dg = right[i].g - left[i].g; + db = right[i].b - left[i].b; + rslope = (dr << 8) / dx; + gslope = (dg << 8) / dx; + bslope = (db << 8) / dx; +#endif +#ifdef TEXMAP + u = left[i].u; + v = left[i].v; + du = right[i].u - left[i].u; + dv = right[i].v - left[i].v; + uslope = (du << 8) / dx; + vslope = (dv << 8) / dx; +#endif + + while(x <= right[i].x) { +#ifdef GOURAUD + /* drop the extra 8 bits when packing */ + int cr = r >> 8; + int cg = g >> 8; + int cb = b >> 8; + color = PACK_RGB16(cr, cg, cb); + r += rslope; + g += gslope; + b += bslope; +#endif +#ifdef TEXMAP + /* TODO */ + u += uslope; + v += vslope; +#endif + +#ifdef DEBUG_OVERDRAW + *pixptr++ += DEBUG_OVERDRAW; +#else + *pixptr++ = color; +#endif + x += 256; + } + } +} + -- 1.7.10.4 From f7789d3011a5ac2620a2f7732a389963f790fd85 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 3 Oct 2016 10:58:17 +0300 Subject: [PATCH 08/16] fixed build on macosx --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 5e3fdeb..348256c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -3,7 +3,7 @@ obj = $(src:.c=.o) dep = $(obj:.o=.d) bin = demo -inc = -Isrc -Isrc/sdl -Ilibs/imago/src -Ilibs/mikmod/include +inc = -I/usr/local/include -Isrc -Isrc/sdl -Ilibs/imago/src -Ilibs/mikmod/include CFLAGS = -pedantic -Wall -g $(inc) `sdl-config --cflags` LDFLAGS = -Llibs/imago -Llibs/mikmod -limago -lmikmod `sdl-config --libs` -lm -- 1.7.10.4 From 07ce18b114e1e01b2a85a04079128f3eb754de1d Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 4 Oct 2016 06:00:26 +0300 Subject: [PATCH 09/16] added texture mapping --- src/3dgfx.c | 33 ++++++++++++++++++++++++++++++--- src/3dgfx.h | 4 ++++ src/gfxutil.h | 4 ++++ src/polyfill.c | 6 +++--- src/polyfill.h | 7 +++++-- src/polytest.c | 42 ++++++++++++++++++++++++++++++++++++++++-- src/polytmpl.h | 41 ++++++++++++++++++++++++++++++----------- 7 files changed, 116 insertions(+), 21 deletions(-) diff --git a/src/3dgfx.c b/src/3dgfx.c index d7e2e41..47b3830 100644 --- a/src/3dgfx.c +++ b/src/3dgfx.c @@ -91,9 +91,9 @@ void g3d_framebuffer(int width, int height, void *pixels) st->height = height; st->pixels = pixels; - pimg_fb.pixels = pixels; - pimg_fb.width = width; - pimg_fb.height = height; + pfill_fb.pixels = pixels; + pfill_fb.width = width; + pfill_fb.height = height; } void g3d_enable(unsigned int opt) @@ -340,6 +340,33 @@ void g3d_mtl_shininess(float shin) st->mtl.shin = shin; } +static INLINE int calc_shift(unsigned int x) +{ + int res = -1; + while(x) { + x >>= 1; + ++res; + } + return res; +} + +static INLINE int calc_mask(unsigned int x) +{ + return x - 1; +} + +void g3d_set_texture(int xsz, int ysz, void *pixels) +{ + pfill_tex.pixels = pixels; + pfill_tex.width = xsz; + pfill_tex.height = ysz; + + pfill_tex.xshift = calc_shift(xsz); + pfill_tex.yshift = calc_shift(ysz); + pfill_tex.xmask = calc_mask(xsz); + pfill_tex.ymask = calc_mask(ysz); +} + void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size) { g3d_draw_indexed(prim, varr, varr_size, 0, 0); diff --git a/src/3dgfx.h b/src/3dgfx.h index ecc3f3c..fbbccf6 100644 --- a/src/3dgfx.h +++ b/src/3dgfx.h @@ -39,6 +39,8 @@ enum { G3D_WIRE, G3D_FLAT, G3D_GOURAUD, + G3D_TEX, + G3D_TEX_GOURAUD }; /* matrix stacks */ @@ -88,6 +90,8 @@ void g3d_mtl_diffuse(float r, float g, float b); void g3d_mtl_specular(float r, float g, float b); void g3d_mtl_shininess(float shin); +void g3d_set_texture(int xsz, int ysz, void *pixels); + void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size); void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, const int16_t *iarr, int iarr_size); diff --git a/src/gfxutil.h b/src/gfxutil.h index f811987..07883ef 100644 --- a/src/gfxutil.h +++ b/src/gfxutil.h @@ -4,6 +4,10 @@ #define PACK_RGB16(r, g, b) \ (((((r) >> 3) & 0x1f) << 11) | ((((g) >> 2) & 0x3f) << 5) | (((b) >> 3) & 0x1f)) +#define UNPACK_R16(c) (((c) >> 8) & 0x7c) +#define UNPACK_G16(c) (((c) >> 3) & 0xfc) +#define UNPACK_B16(c) (((c) << 3) & 0x7c) + #define PACK_RGB32(r, g, b) \ ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff)) diff --git a/src/polyfill.c b/src/polyfill.c index 634d525..0d1351e 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -19,7 +19,7 @@ void (*fillfunc[])(struct pvertex*, int) = { polyfill_tex_gouraud }; -struct pimage pimg_fb, pimg_texture; +struct pimage pfill_fb, pfill_tex; void polyfill(int mode, struct pvertex *verts, int nverts) { @@ -46,13 +46,13 @@ void polyfill_wire(struct pvertex *verts, int nverts) ++v; x1 = v->x >> 8; y1 = v->y >> 8; - if(clip_line(&x0, &y0, &x1, &y1, 0, 0, pimg_fb.width, pimg_fb.height)) { + if(clip_line(&x0, &y0, &x1, &y1, 0, 0, pfill_fb.width, pfill_fb.height)) { draw_line(x0, y0, x1, y1, color); } } x0 = verts[0].x >> 8; y0 = verts[0].y >> 8; - if(clip_line(&x1, &y1, &x0, &y0, 0, 0, pimg_fb.width, pimg_fb.height)) { + if(clip_line(&x1, &y1, &x0, &y0, 0, 0, pfill_fb.width, pfill_fb.height)) { draw_line(x1, y1, x0, y0, color); } } diff --git a/src/polyfill.h b/src/polyfill.h index a01130c..2a6b42d 100644 --- a/src/polyfill.h +++ b/src/polyfill.h @@ -21,10 +21,13 @@ struct pvertex { struct pimage { uint16_t *pixels; int width, height; + + int xshift, yshift; + unsigned int xmask, ymask; }; -extern struct pimage pimg_fb; -extern struct pimage pimg_texture; +extern struct pimage pfill_fb; +extern struct pimage pfill_tex; void polyfill(int mode, struct pvertex *verts, int nverts); void polyfill_wire(struct pvertex *verts, int nverts); diff --git a/src/polytest.c b/src/polytest.c index e7c3cdf..800dd46 100644 --- a/src/polytest.c +++ b/src/polytest.c @@ -6,6 +6,7 @@ #include "demo.h" #include "3dgfx.h" #include "gfxutil.h" +#include "polyfill.h" /* just for struct pimage */ struct mesh { int prim; @@ -23,6 +24,7 @@ static int gen_cube(struct mesh *mesh, float sz); static int gen_torus(struct mesh *mesh, float rad, float ringrad, int usub, int vsub); static void zsort(struct mesh *m); static void draw_lowres_raster(void); +static int gen_texture(struct pimage *img, int xsz, int ysz); static struct screen scr = { "polytest", @@ -35,6 +37,8 @@ static struct screen scr = { static float theta, phi = 25; static struct mesh cube, torus; +static struct pimage tex; + #define LOWRES_SCALE 10 static uint16_t *lowres_pixels; static int lowres_width, lowres_height; @@ -46,8 +50,17 @@ struct screen *polytest_screen(void) static int init(void) { + int i; + gen_cube(&cube, 1.0); gen_torus(&torus, 1.0, 0.25, 24, 12); + /* scale texcoords */ + for(i=0; ipixels = malloc(xsz * ysz * sizeof *pix))) { + return -1; + } + pix = img->pixels; + + for(i=0; iwidth = xsz; + img->height = ysz; + return 0; +} diff --git a/src/polytmpl.h b/src/polytmpl.h index 2021b3b..79660ef 100644 --- a/src/polytmpl.h +++ b/src/polytmpl.h @@ -70,13 +70,13 @@ static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex void POLYFILL(struct pvertex *pv, int nverts) { int i; - int topidx = 0, botidx = 0, sltop = pimg_fb.height, slbot = 0; + int topidx = 0, botidx = 0, sltop = pfill_fb.height, slbot = 0; struct pvertex *left, *right; uint16_t color; /* the following variables are used for interpolating horizontally accros scanlines */ #if defined(GOURAUD) || defined(TEXMAP) - int mid; - int32_t dx, tmp; + /*int mid;*/ + int32_t dx/*, tmp*/; #else /* flat version, just pack the color now */ color = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b); @@ -93,8 +93,8 @@ void POLYFILL(struct pvertex *pv, int nverts) if(pv[i].y > pv[botidx].y) botidx = i; } - left = alloca(pimg_fb.height * sizeof *left); - right = alloca(pimg_fb.height * sizeof *right); + left = alloca(pfill_fb.height * sizeof *left); + right = alloca(pfill_fb.height * sizeof *right); for(i=0; i> 8); + pixptr = pfill_fb.pixels + i * pfill_fb.width + (x >> 8); #if defined(GOURAUD) || defined(TEXMAP) if(!(dx = right[i].x - left[i].x)) dx = 256; /* 1 */ @@ -182,21 +182,40 @@ void POLYFILL(struct pvertex *pv, int nverts) #endif while(x <= right[i].x) { +#if defined(GOURAUD) || defined(TEXMAP) + int cr, cg, cb; +#endif #ifdef GOURAUD /* drop the extra 8 bits when packing */ - int cr = r >> 8; - int cg = g >> 8; - int cb = b >> 8; - color = PACK_RGB16(cr, cg, cb); + cr = r >> 8; + cg = g >> 8; + cb = b >> 8; r += rslope; g += gslope; b += bslope; #endif #ifdef TEXMAP - /* TODO */ + { + int tx = (u >> (16 - pfill_tex.xshift)) & pfill_tex.xmask; + int ty = (v >> (16 - pfill_tex.yshift)) & pfill_tex.ymask; + uint16_t texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx]; +#ifdef GOURAUD + /* XXX this is not correct, should be /255, but it might not make a huge difference */ + cr = (cr * UNPACK_R16(texel)) >> 8; + cg = (cg * UNPACK_G16(texel)) >> 8; + cb = (cb * UNPACK_B16(texel)) >> 8; +#else + cr = UNPACK_R16(texel); + cg = UNPACK_G16(texel); + cb = UNPACK_B16(texel); +#endif + } u += uslope; v += vslope; #endif +#if defined(GOURAUD) || defined(TEXMAP) + color = PACK_RGB16(cr, cg, cb); +#endif #ifdef DEBUG_OVERDRAW *pixptr++ += DEBUG_OVERDRAW; -- 1.7.10.4 From 0b870b76705b3e597da3f6a11e0499deedbeee30 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 4 Oct 2016 06:19:10 +0300 Subject: [PATCH 10/16] DOS logger now redirects stdout/stderr instead of providing a new logging function --- src/dos/gfx.c | 9 ++++----- src/dos/logger.c | 53 ++++++++++++++--------------------------------------- src/dos/logger.h | 22 +--------------------- src/dos/main.c | 3 +++ src/dos/music.c | 13 ++++++------- 5 files changed, 28 insertions(+), 72 deletions(-) diff --git a/src/dos/gfx.c b/src/dos/gfx.c index 558646b..a07d77a 100644 --- a/src/dos/gfx.c +++ b/src/dos/gfx.c @@ -7,7 +7,6 @@ #include #include "vbe.h" #include "dpmi.h" -#include "logger.h" #define REALPTR(s, o) (void*)(((uint32_t)(s) << 4) + (uint32_t)(o)) #define VBEPTR(x) REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff) @@ -36,15 +35,15 @@ void *set_video_mode(int xsz, int ysz, int bpp) return 0; } - printlog("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff); + printf("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff); if(vbe_info->version < 0x200) { fprintf(stderr, "This program requires VBE 2.0 or greater. Try running UniVBE\n"); return 0; } - printlog("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe_info->oem_vendor_name_ptr), + printf("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe_info->oem_vendor_name_ptr), VBEPTR(vbe_info->oem_product_name_ptr), VBEPTR(vbe_info->oem_product_rev_ptr)); - printlog("Video memory: %dkb\n", vbe_info->total_mem << 6); + printf("Video memory: %dkb\n", vbe_info->total_mem << 6); modes = VBEPTR(vbe_info->vid_mode_ptr); } @@ -78,7 +77,7 @@ void *set_video_mode(int xsz, int ysz, int bpp) /* attempt to set 8 bits of color per component in palettized modes */ /*if(bpp <= 8) { pal_bits = vbe_set_palette_bits(8); - printlog("palette bits per color primary: %d\n", pal_bits); + printf("palette bits per color primary: %d\n", pal_bits); } */ diff --git a/src/dos/logger.c b/src/dos/logger.c index 73860e3..f7e9256 100644 --- a/src/dos/logger.c +++ b/src/dos/logger.c @@ -1,46 +1,21 @@ -/* -colcycle - color cycling image viewer -Copyright (C) 2016 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 +#include +#include +#include #include "logger.h" -#define LOGFNAME "demo.log" - -static FILE *logfile; - -void logger_output(FILE *fp) +int init_logger(const char *fname) { - if(logfile) fclose(logfile); - logfile = fp; -} - -void printlog(const char *fmt, ...) -{ - va_list ap; - - if(!logfile) { - if(!(logfile = fopen(LOGFNAME, "w"))) { - return; - } - setvbuf(logfile, 0, _IOLBF, 0); + int fd; + if((fd = open(fname, O_WRONLY)) == -1) { + fprintf(stderr, "init_logger: failed to open %s: %s\n", fname, strerror(errno)); + return -1; } - va_start(ap, fmt); - vfprintf(logfile, fmt, ap); - va_end(ap); + close(1); + close(2); + dup(fd); + dup(fd); + return 0; } diff --git a/src/dos/logger.h b/src/dos/logger.h index 249b989..9ef9a85 100644 --- a/src/dos/logger.h +++ b/src/dos/logger.h @@ -1,31 +1,11 @@ -/* -colcycle - color cycling image viewer -Copyright (C) 2016 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 . -*/ #ifndef LOGGER_H_ #define LOGGER_H_ -#include - #ifdef __cplusplus extern "C" { #endif -void logger_output(FILE *fp); -void printlog(const char *fmt, ...); +int init_logger(const char *fname); #ifdef __cplusplus } diff --git a/src/dos/main.c b/src/dos/main.c index 10492fe..53b8888 100644 --- a/src/dos/main.c +++ b/src/dos/main.c @@ -7,6 +7,7 @@ #include "mouse.h" #include "timer.h" #include "gfx.h" +#include "logger.h" static int quit; static int use_mouse; @@ -16,6 +17,8 @@ int main(int argc, char **argv) { fbsize = fb_width * fb_height * fb_bpp / CHAR_BIT; + init_logger("demo.log"); + init_timer(100); kb_init(32); diff --git a/src/dos/music.c b/src/dos/music.c index 4005a79..5f3b84a 100644 --- a/src/dos/music.c +++ b/src/dos/music.c @@ -1,7 +1,6 @@ #include #include "music.h" #include "mikmod.h" -#include "logger.h" static void update_callback(void); @@ -32,11 +31,11 @@ static int init(void) MD_RegisterPlayer(update_callback); if(!MD_Init()) { - printlog("mikmod init failed: %s\n", myerr); + fprintf(stderr, "mikmod init failed: %s\n", myerr); return -1; } - printlog("using mikmod driver %s\n", md_driver->Name); - printlog(" %d bits, %s, %s mixing at %d Hz\n", md_mode & DMODE_16BITS ? 16 : 8, + printf("using mikmod driver %s\n", md_driver->Name); + printf(" %d bits, %s, %s mixing at %d Hz\n", md_mode & DMODE_16BITS ? 16 : 8, md_mode & DMODE_STEREO ? "stereo" : "mono", md_mode & DMODE_INTERP ? "interpolated" : "normal", md_mixfreq); @@ -55,20 +54,20 @@ int music_open(const char *fname) } if(!(mod = ML_LoadFN((const signed char*)fname))) { - printlog("failed to load music: %s: %s\n", fname, myerr); + fprintf(stderr, "failed to load music: %s: %s\n", fname, myerr); return -1; } MP_Init(mod); md_numchn = mod->numchn; - printlog("opened module %s (%d channels)\n", fname, md_numchn); + printf("opened module %s (%d channels)\n", fname, md_numchn); return 0; } void music_close(void) { if(mod) { - printlog("shutting down music playback\n"); + printf("shutting down music playback\n"); music_stop(); ML_Free(mod); mod = 0; -- 1.7.10.4 From 9e546fcbdc870e396abeb6eaacaa7bc4054a61f0 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 4 Oct 2016 07:47:51 +0300 Subject: [PATCH 11/16] optional high-quality but slower calculation of attribute slopes across each scanline, and extra color bits during interpolation. --- src/polyfill.c | 15 +++++++++++++ src/polytest.c | 6 ++++-- src/polytmpl.h | 65 ++++++++++++++++++++++++++++++++++---------------------- 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/src/polyfill.c b/src/polyfill.c index 0d1351e..e94de2f 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -60,6 +60,21 @@ void polyfill_wire(struct pvertex *verts, int nverts) #define NEXTIDX(x) (((x) - 1 + nverts) % nverts) #define PREVIDX(x) (((x) + 1) % nverts) +/* XXX + * When HIGH_QUALITY is defined, the rasterizer calculates slopes for attribute + * interpolation on each scanline separately; otherwise the slope for each + * attribute would be calculated once for the whole polygon, which is faster, + * but produces some slight quantization artifacts, due to the limited precision + * of fixed-point calculations. + */ +#undef HIGH_QUALITY + +/* extra bits of precision to use when interpolating colors. + * try tweaking this if you notice strange quantization artifacts. + */ +#define COLOR_SHIFT 12 + + #define POLYFILL polyfill_flat #define SCANEDGE scanedge_flat #undef GOURAUD diff --git a/src/polytest.c b/src/polytest.c index 800dd46..0d5187d 100644 --- a/src/polytest.c +++ b/src/polytest.c @@ -104,8 +104,8 @@ static void update(void) int dy = mouse_y - prev_my; if(dx || dy) { - theta += dx * 2.0; - phi += dy * 2.0; + theta += dx * 1.0; + phi += dy * 1.0; if(phi < -90) phi = -90; if(phi > 90) phi = 90; @@ -283,6 +283,8 @@ static int gen_torus(struct mesh *mesh, float rad, float ringrad, int usub, int nfaces = usub * vsub; mesh->icount = nfaces * 4; + printf("generating torus with %d faces (%d vertices)\n", nfaces, mesh->vcount); + if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) { return -1; } diff --git a/src/polytmpl.h b/src/polytmpl.h index 79660ef..3b3917e 100644 --- a/src/polytmpl.h +++ b/src/polytmpl.h @@ -22,12 +22,12 @@ static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex dx = v1->x - v0->x; slope = (dx << 8) / dy; #ifdef GOURAUD - r = (v0->r << 8); - g = (v0->g << 8); - b = (v0->b << 8); - dr = (v1->r << 8) - r; - dg = (v1->g << 8) - g; - db = (v1->b << 8) - b; + r = (v0->r << COLOR_SHIFT); + g = (v0->g << COLOR_SHIFT); + b = (v0->b << COLOR_SHIFT); + dr = (v1->r << COLOR_SHIFT) - r; + dg = (v1->g << COLOR_SHIFT) - g; + db = (v1->b << COLOR_SHIFT) - b; rslope = (dr << 8) / dy; gslope = (dg << 8) / dy; bslope = (db << 8) / dy; @@ -48,7 +48,7 @@ static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex edge[i].x = x; x += slope; #ifdef GOURAUD - /* we'll store the color in the edge tables with 8 extra bits of precision */ + /* we'll store the color in the edge tables with COLOR_SHIFT extra bits of precision */ edge[i].r = r; edge[i].g = g; edge[i].b = b; @@ -75,8 +75,8 @@ void POLYFILL(struct pvertex *pv, int nverts) uint16_t color; /* the following variables are used for interpolating horizontally accros scanlines */ #if defined(GOURAUD) || defined(TEXMAP) - /*int mid;*/ - int32_t dx/*, tmp*/; + int mid; + int32_t dx, tmp; #else /* flat version, just pack the color now */ color = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b); @@ -118,8 +118,10 @@ void POLYFILL(struct pvertex *pv, int nverts) } } - /* find the mid-point and calculate slopes for all attributes */ -#if 0 + /* calculate the slopes of all attributes across the largest span out + * of the three: middle, top, or bottom. + */ +#ifndef HIGH_QUALITY #if defined(GOURAUD) || defined(TEXMAP) mid = (sltop + slbot) >> 1; dx = right[mid].x - left[mid].x; @@ -131,9 +133,7 @@ void POLYFILL(struct pvertex *pv, int nverts) dx = tmp; mid = slbot; } - if(!dx) { - dx = 256; /* 1 */ - } + if(!dx) dx = 256; /* avoid division by zero */ #endif #ifdef GOURAUD dr = right[mid].r - left[mid].r; @@ -149,8 +149,9 @@ void POLYFILL(struct pvertex *pv, int nverts) uslope = (du << 8) / dx; vslope = (dv << 8) / dx; #endif -#endif /* 0 */ +#endif /* !defined(HIGH_QUALITY) */ + /* for each scanline ... */ for(i=sltop; i<=slbot; i++) { uint16_t *pixptr; int32_t x; @@ -158,13 +159,20 @@ void POLYFILL(struct pvertex *pv, int nverts) x = left[i].x; pixptr = pfill_fb.pixels + i * pfill_fb.width + (x >> 8); -#if defined(GOURAUD) || defined(TEXMAP) - if(!(dx = right[i].x - left[i].x)) dx = 256; /* 1 */ -#endif #ifdef GOURAUD r = left[i].r; g = left[i].g; b = left[i].b; +#endif +#ifdef TEXMAP + u = left[i].u; + v = left[i].v; +#endif + +#if defined(HIGH_QUALITY) && (defined(GOURAUD) || defined(TEXMAP)) + if(!(dx = right[i].x - left[i].x)) dx = 256; + +#ifdef GOURAUD dr = right[i].r - left[i].r; dg = right[i].g - left[i].g; db = right[i].b - left[i].b; @@ -173,23 +181,28 @@ void POLYFILL(struct pvertex *pv, int nverts) bslope = (db << 8) / dx; #endif #ifdef TEXMAP - u = left[i].u; - v = left[i].v; du = right[i].u - left[i].u; dv = right[i].v - left[i].v; uslope = (du << 8) / dx; vslope = (dv << 8) / dx; #endif +#endif /* HIGH_QUALITY */ + /* go across the scanline interpolating if necessary */ while(x <= right[i].x) { #if defined(GOURAUD) || defined(TEXMAP) int cr, cg, cb; #endif #ifdef GOURAUD - /* drop the extra 8 bits when packing */ - cr = r >> 8; - cg = g >> 8; - cb = b >> 8; + /* we upped the color precision to while interpolating the + * edges, now drop the extra bits before packing + */ + cr = r < 0 ? 0 : (r >> COLOR_SHIFT); + cg = g < 0 ? 0 : (g >> COLOR_SHIFT); + cb = b < 0 ? 0 : (b >> COLOR_SHIFT); + if(cr > 255) cr = 255; + if(cg > 255) cg = 255; + if(cb > 255) cb = 255; r += rslope; g += gslope; b += bslope; @@ -200,7 +213,9 @@ void POLYFILL(struct pvertex *pv, int nverts) int ty = (v >> (16 - pfill_tex.yshift)) & pfill_tex.ymask; uint16_t texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx]; #ifdef GOURAUD - /* XXX this is not correct, should be /255, but it might not make a huge difference */ + /* This is not correct, should be /255, but it's much faster + * to shift by 8 (/256), and won't make a huge difference + */ cr = (cr * UNPACK_R16(texel)) >> 8; cg = (cg * UNPACK_G16(texel)) >> 8; cb = (cb * UNPACK_B16(texel)) >> 8; -- 1.7.10.4 From b326ec9a1deb7086652fae05bb241ecc093b736f Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 4 Oct 2016 08:09:09 +0300 Subject: [PATCH 12/16] added missing open flags and mode in init_logger --- src/dos/logger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dos/logger.c b/src/dos/logger.c index f7e9256..70489ad 100644 --- a/src/dos/logger.c +++ b/src/dos/logger.c @@ -8,7 +8,7 @@ int init_logger(const char *fname) { int fd; - if((fd = open(fname, O_WRONLY)) == -1) { + if((fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { fprintf(stderr, "init_logger: failed to open %s: %s\n", fname, strerror(errno)); return -1; } -- 1.7.10.4 From 5f474fafc7e6a051f1d6809e1000894a5887c742 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 4 Oct 2016 19:05:36 +0300 Subject: [PATCH 13/16] changed the tunnel rotation to match the smaller texture --- src/tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tunnel.c b/src/tunnel.c index d10c691..56d0793 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -220,7 +220,7 @@ static void draw_tunnel_range(unsigned short *pix, int xoffs, int yoffs, int sta unsigned int *tmap = tunnel_map + (starty + yoffs) * vxsz + xoffs; unsigned char *fog = tunnel_fog + (starty + yoffs) * vxsz + xoffs; - long toffs = tm / 4; + long toffs = tm / 8; unsigned int *pixels = (unsigned int*)pix + starty * (fb_width >> 1); for(i=0; i Date: Tue, 4 Oct 2016 19:10:00 +0300 Subject: [PATCH 14/16] removed empty stop functions from bump and plasma to avoid delaying the transitions --- src/bump.c | 9 ++------- src/plasma.c | 7 +------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/bump.c b/src/bump.c index dc53337..104b127 100644 --- a/src/bump.c +++ b/src/bump.c @@ -12,7 +12,6 @@ static int init(void); static void destroy(void); static void start(long trans_time); -static void stop(long trans_time); static void draw(void); static struct screen scr = { @@ -20,11 +19,11 @@ static struct screen scr = { init, destroy, start, - stop, + 0, draw }; -static struct point { +struct point { int x, y; }; @@ -143,10 +142,6 @@ static void start(long trans_time) startingTime = time_msec; } -static void stop(long trans_time) -{ -} - static void eraseArea(struct point *p, int width, int height) { int x, y, dx; diff --git a/src/plasma.c b/src/plasma.c index 05f68e4..132cff3 100644 --- a/src/plasma.c +++ b/src/plasma.c @@ -10,7 +10,6 @@ static int init(void); static void destroy(void); static void start(long trans_time); -static void stop(long trans_time); static void draw(void); static struct screen scr = { @@ -18,7 +17,7 @@ static struct screen scr = { init, destroy, start, - stop, + 0, draw }; @@ -84,10 +83,6 @@ static void start(long trans_time) startingTime = time_msec; } -static void stop(long trans_time) -{ -} - static void draw(void) { int x, y; -- 1.7.10.4 From aefd23e483457daa7eeb4987827e72df83886eaa Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 5 Oct 2016 02:08:17 +0300 Subject: [PATCH 15/16] SDL backend set the mouse button bitmask incorrectly --- src/polytest.c | 32 ++++++++++++++++++++------------ src/sdl/main.c | 4 ++-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/polytest.c b/src/polytest.c index 0d5187d..cc64a0d 100644 --- a/src/polytest.c +++ b/src/polytest.c @@ -34,7 +34,8 @@ static struct screen scr = { draw }; -static float theta, phi = 25; +static float cam_theta, cam_phi = 25; +static float cam_dist = 3; static struct mesh cube, torus; static struct pimage tex; @@ -104,11 +105,18 @@ static void update(void) int dy = mouse_y - prev_my; if(dx || dy) { - theta += dx * 1.0; - phi += dy * 1.0; - - if(phi < -90) phi = -90; - if(phi > 90) phi = 90; + if(mouse_bmask & 1) { + cam_theta += dx * 1.0; + cam_phi += dy * 1.0; + + if(cam_phi < -90) cam_phi = -90; + if(cam_phi > 90) cam_phi = 90; + } + if(mouse_bmask & 4) { + cam_dist += dy * 0.5; + + if(cam_dist < 0) cam_dist = 0; + } } } } @@ -126,9 +134,9 @@ static void draw(void) g3d_matrix_mode(G3D_MODELVIEW); g3d_load_identity(); - g3d_translate(0, 0, -3); - g3d_rotate(phi, 1, 0, 0); - g3d_rotate(theta, 0, 1, 0); + g3d_translate(0, 0, -cam_dist); + g3d_rotate(cam_phi, 1, 0, 0); + g3d_rotate(cam_theta, 0, 1, 0); g3d_light_pos(0, -10, 10, 20); @@ -151,9 +159,9 @@ static void draw_debug(void) g3d_matrix_mode(G3D_MODELVIEW); g3d_load_identity(); - g3d_translate(0, 0, -3); - g3d_rotate(phi, 1, 0, 0); - g3d_rotate(theta, 0, 1, 0); + g3d_translate(0, 0, -cam_dist); + g3d_rotate(cam_phi, 1, 0, 0); + g3d_rotate(cam_theta, 0, 1, 0); g3d_framebuffer(lowres_width, lowres_height, lowres_pixels); /*zsort(&torus);*/ diff --git a/src/sdl/main.c b/src/sdl/main.c index 6b65796..48852f5 100644 --- a/src/sdl/main.c +++ b/src/sdl/main.c @@ -129,10 +129,10 @@ static void handle_event(SDL_Event *ev) break; case SDL_MOUSEBUTTONDOWN: - mouse_bmask |= 1 << ev->button.button; + mouse_bmask |= 1 << (ev->button.button - SDL_BUTTON_LEFT); if(0) { case SDL_MOUSEBUTTONUP: - mouse_bmask &= ~(1 << ev->button.button); + mouse_bmask &= ~(1 << (ev->button.button - SDL_BUTTON_LEFT)); } mouse_x = ev->button.x / fbscale; mouse_y = ev->button.y / fbscale; -- 1.7.10.4 From 21c4bd88e7ddd930ac83c54cbe7399af0e188b67 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 5 Oct 2016 04:19:46 +0300 Subject: [PATCH 16/16] moved the drawFps call to the backends so it works automatically for any part --- src/bump.c | 4 ---- src/demo.c | 3 +++ src/dos/main.c | 3 +++ src/fract.c | 63 ++++---------------------------------------------------- src/plasma.c | 6 ------ src/sdl/main.c | 2 ++ 6 files changed, 12 insertions(+), 69 deletions(-) diff --git a/src/bump.c b/src/bump.c index 104b127..a6f7aad 100644 --- a/src/bump.c +++ b/src/bump.c @@ -7,7 +7,6 @@ #include "demo.h" #include "screen.h" -#include "tinyfps.h" static int init(void); static void destroy(void); @@ -60,7 +59,6 @@ static int init(void) const float rgbMul[9] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - initFpsFonts(); heightmap = malloc(sizeof(*heightmap) * fb_size); lightmap = malloc(sizeof(*lightmap) * fb_size); @@ -265,7 +263,5 @@ static void draw(void) renderLights(); renderBump((unsigned short*)vmem_back); - drawFps((unsigned short*)vmem_back); - swap_buffers(0); } diff --git a/src/demo.c b/src/demo.c index 472da32..518bb53 100644 --- a/src/demo.c +++ b/src/demo.c @@ -9,6 +9,7 @@ #include "3dgfx.h" #include "music.h" #include "cfgopt.h" +#include "tinyfps.h" int fb_width = 320; int fb_height = 240; @@ -35,6 +36,8 @@ int demo_init(int argc, char **argv) return -1; } + initFpsFonts(); + if(g3d_init() == -1) { return -1; } diff --git a/src/dos/main.c b/src/dos/main.c index 53b8888..051cdb5 100644 --- a/src/dos/main.c +++ b/src/dos/main.c @@ -76,6 +76,9 @@ void swap_buffers(void *pixels) /* TODO implement page flipping */ if(pixels) { /*wait_vsync();*/ + drawFps(pixels); memcpy(vmem_front, pixels, fbsize); + } else { + drawFps(vmem_back); } } diff --git a/src/fract.c b/src/fract.c index 15da79d..a17550b 100644 --- a/src/fract.c +++ b/src/fract.c @@ -12,7 +12,6 @@ static int init(void); static void destroy(void); static void draw(void); static int julia(long x, long y, long cx, long cy, int max_iter); -static int calc_walk(struct vec2x *path, long x, long y, int max_steps); static struct screen scr = { "fract", @@ -49,9 +48,8 @@ static void destroy(void) static void draw(void) { - int i, j, len, x, y; - unsigned short *pixels = fb_pixels; - struct vec2x walkpos[WALK_SIZE]; + int i, j; + unsigned short *pixels = vmem_back; cx = mouse_x; cy = mouse_y; @@ -63,29 +61,9 @@ static void draw(void) } } - pixels = fb_pixels; - - if((len = calc_walk(walkpos, mouse_x, mouse_y, WALK_SIZE))) { - x = walkpos[0].x >> 16; - y = walkpos[0].y >> 16; - - for(i=1; i> 16; - int y1 = walkpos[i].y >> 16; - - if(clip_line(&x0, &y0, &x1, &y1, 0, 0, fb_width - 1, fb_height - 1)) { - draw_line(x0, y0, x1, y1, PACK_RGB16(32, 128, 255)); - } - x = x1; - y = y1; - } - } - + pixels = vmem_back; pixels[mouse_y * fb_width + mouse_x] = 0xffe; - - swap_buffers(fb_pixels); + swap_buffers(vmem_back); } static long normalize_coord(long x, long range) @@ -94,12 +72,6 @@ static long normalize_coord(long x, long range) return (x << 17) / range - 65536; } -static long device_coord(long x, long range) -{ - /* (x + 1) / 2 * (range - 1) */ - return ((x + 65536) >> 1) * (range - 1); -} - static int julia(long x, long y, long cx, long cy, int max_iter) { int i; @@ -124,30 +96,3 @@ static int julia(long x, long y, long cx, long cy, int max_iter) return i < max_iter ? (256 * i / max_iter) : 0; } - -static int calc_walk(struct vec2x *path, long x, long y, int max_steps) -{ - int i; - long cx, cy; - - /* convert to fixed point roughly [-1, 1] */ - x = cx = (normalize_coord(x, fb_width) >> 8) * xscale_24x8; - y = cy = (normalize_coord(y, fb_height) >> 8) * yscale_24x8; - - for(i=0; i> 8; - long py = y >> 8; - - path[i].x = device_coord((x << 8) / xscale_24x8, fb_width); - path[i].y = device_coord((y << 8) / yscale_24x8, fb_height); - - if(px * px + py * py > (4 << 16)) { - break; - } - x = px * px - py * py + cx; - y = (px * py << 1) + cy; - } - - return i; -} diff --git a/src/plasma.c b/src/plasma.c index 132cff3..c20ff63 100644 --- a/src/plasma.c +++ b/src/plasma.c @@ -5,7 +5,6 @@ #include "demo.h" #include "screen.h" -#include "tinyfps.h" static int init(void); static void destroy(void); @@ -41,8 +40,6 @@ static int init(void) { int i; - initFpsFonts(); - psin1 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE); psin2 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE); psin3 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE); @@ -67,7 +64,6 @@ static int init(void) plasmaPal[i] = (r<<11) | (g<<5) | b; } - //return 0xCAFE; return 0; } @@ -111,7 +107,5 @@ static void draw(void) } } - drawFps((unsigned short*)vmem_back); - swap_buffers(0); } diff --git a/src/sdl/main.c b/src/sdl/main.c index 48852f5..05744e8 100644 --- a/src/sdl/main.c +++ b/src/sdl/main.c @@ -3,6 +3,7 @@ #include #include #include "demo.h" +#include "tinyfps.h" static void handle_event(SDL_Event *ev); static void toggle_fullscreen(void); @@ -61,6 +62,7 @@ int main(int argc, char **argv) time_msec = SDL_GetTicks() - start_time; demo_draw(); + drawFps(fb_pixels); if(SDL_MUSTLOCK(fbsurf)) { SDL_LockSurface(fbsurf); -- 1.7.10.4