X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fvoxscape.c;h=54c0b10b3c15ebb4a736dfff0d185fa0ce0d7a08;hb=e10cd82c8f0b2a2140aa6a4792ed56329932271f;hp=df34f20ea535cfeb36a303b2de389f71ea05e20f;hpb=7efa828ba87fe6c90b8c55019f4789066d2e4af3;p=voxscape diff --git a/src/voxscape.c b/src/voxscape.c index df34f20..54c0b10 100644 --- a/src/voxscape.c +++ b/src/voxscape.c @@ -3,8 +3,17 @@ #include #include #include +#include #include #include "voxscape.h" +#include "lut.h" + +#define XLERP(a, b, t, fp) \ + ((((a) << (fp)) + ((b) - (a)) * (t)) >> fp) + +static uint32_t lerp_rgb(int r0, int g0, int b0, int r1, int g1, int b1, int32_t t); +static uint32_t lerp_color(uint32_t ca, uint32_t cb, int32_t t); +static uint32_t lerp_pcol_rgb(uint32_t pcol, int r, int g, int b, int32_t t); enum { SLICELEN = 1 @@ -16,10 +25,13 @@ struct voxscape { uint32_t *color; int xshift, xmask, ymask; + int hfilt, cfilt; + /* framebuffer */ uint32_t *fb; int fbwidth, fbheight; int *coltop; + int horizon; /* view */ int32_t x, y, angle; @@ -31,6 +43,9 @@ struct voxscape { int32_t *slicelen; int proj_dist; + int zfog; /* fog start Z (0: no fog) */ + int fogcolor[3]; + unsigned int valid; }; @@ -64,7 +79,8 @@ struct voxscape *vox_create(int xsz, int ysz) vox->xshift++; } - vox->proj_dist = 2; /* TODO */ + vox->vheight = 80; + vox->proj_dist = 4; /* TODO */ return vox; } @@ -73,7 +89,7 @@ struct voxscape *vox_open(const char *hfile, const char *cfile) { unsigned char *hpix; uint32_t *cpix; - int width, height, cwidth, cheight; + int i, width, height, cwidth, cheight; struct voxscape *vox; if(!(hpix = img_load_pixels(hfile, &width, &height, IMG_FMT_GREY8))) { @@ -97,8 +113,14 @@ struct voxscape *vox_open(const char *hfile, const char *cfile) img_free_pixels(cpix); return 0; } + memcpy(vox->height, hpix, width * height); - memcpy(vox->color, cpix, width * height * sizeof *vox->color); + + /* swap r/b and discard alpha while copying */ + for(i=0; icolor[i] = (cpix[i] & 0xff00) | ((cpix[i] & 0xff) << 16) | + ((cpix[i] & 0xff0000) >> 16); + } img_free_pixels(hpix); img_free_pixels(cpix); @@ -117,7 +139,73 @@ void vox_free(struct voxscape *vox) free(vox); } -void vox_framebuf(struct voxscape *vox, int xres, int yres, uint32_t *fb) +void vox_fog(struct voxscape *vox, int zstart, uint32_t color) +{ + vox->zfog = zstart; + + vox->fogcolor[2] = color >> 16; + vox->fogcolor[1] = (color >> 8) & 0xff; + vox->fogcolor[0] = color & 0xff; +} + +#define H(x, y) \ + vox->height[((((y) >> 16) & vox->ymask) << vox->xshift) + (((x) >> 16) & vox->xmask)] +#define C(x, y) \ + vox->color[((((y) >> 16) & vox->ymask) << vox->xshift) + (((x) >> 16) & vox->xmask)] + + +int vox_height(struct voxscape *vox, int32_t x, int32_t y) +{ + int32_t u, v; + int h00, h01, h10, h11, h0, h1; + + if(!vox->hfilt) { + return H(x, y); + } + + h00 = H(x, y); + h01 = H(x, y + 0x10000); + h10 = H(x + 0x10000, y); + h11 = H(x + 0x10000, y + 0x10000); + + u = x & 0xffff; + v = y & 0xffff; + + h0 = XLERP(h00, h01, v, 16); + h1 = XLERP(h10, h11, v, 16); + return XLERP(h0, h1, u, 16); +} + +int vox_color(struct voxscape *vox, int32_t x, int32_t y) +{ + int32_t u, v; + uint32_t c00, c01, c10, c11, c0, c1; + + if(!vox->cfilt) { + return C(x, y); + } + + c00 = C(x, y); + c01 = C(x, y + 0x10000); + c10 = C(x + 0x10000, y); + c11 = C(x + 0x10000, y + 0x10000); + + u = x & 0xffff; + v = y & 0xffff; + + c0 = lerp_color(c00, c01, v); + c1 = lerp_color(c10, c11, v); + return lerp_color(c0, c1, u); +} + + +void vox_filter(struct voxscape *vox, int hfilt, int cfilt) +{ + vox->hfilt = hfilt; + vox->cfilt = cfilt; +} + +void vox_framebuf(struct voxscape *vox, int xres, int yres, uint32_t *fb, int horizon) { if(xres != vox->fbwidth) { free(vox->coltop); @@ -129,14 +217,19 @@ void vox_framebuf(struct voxscape *vox, int xres, int yres, uint32_t *fb) vox->fb = fb; vox->fbwidth = xres; vox->fbheight = yres; + vox->horizon = horizon >= 0 ? horizon : vox->fbheight / 2; } -void vox_view(struct voxscape *vox, int32_t x, int32_t y, int32_t angle) +void vox_view(struct voxscape *vox, int32_t x, int32_t y, int h, int32_t angle) { + if(h < 0) { + h = vox_height(vox, x, y) - h; + } + vox->x = x; vox->y = y; + vox->vheight = h; vox->angle = angle; - /* TODO precalc stuff */ vox->valid &= ~SLICELEN; } @@ -177,17 +270,12 @@ void vox_begin(struct voxscape *vox) { int i; - /* - for(i=0; ifbwidth; i++) { - vox->coltop[i] = vox->fbheight; - } - */ memset(vox->coltop, 0, vox->fbwidth * sizeof *vox->coltop); if(!(vox->valid & SLICELEN)) { - float theta = (float)vox->angle * M_PI / 360.0f; /* half angle */ + float theta = (float)vox->fov * M_PI / 360.0f; /* half angle */ for(i=0; inslices; i++) { - vox->slicelen[i] = (int32_t)((vox->znear + i) * tan(theta) * 2.0f * 65536.0f); + vox->slicelen[i] = (int32_t)((vox->znear + i) * tan(theta) * 4.0f * 65536.0f); } vox->valid |= SLICELEN; } @@ -195,33 +283,128 @@ void vox_begin(struct voxscape *vox) void vox_render_slice(struct voxscape *vox, int n) { - int i, j, tx, ty, hval, colstart, colheight; - int32_t x, y, len, xstep; + int i, j, hval, colstart, colheight, z; + int32_t x, y, len, xstep, ystep, fog; uint32_t color; uint32_t *fbptr; - len = vox->slicelen[n]; - xstep = len / vox->fbwidth; + if(vox->zfog > 0 && n > vox->zfog) { + fog = ((n - vox->zfog) << 16) / (vox->zfar - vox->zfog); + } else { + fog = 0; + } - x = vox->x - xstep * (vox->fbwidth >> 1); - y = vox->y + (vox->znear << 16); - for(i=0; ifbwidth; i++) { - tx = (x >> 16) & vox->xmask; - ty = (y >> 16) & vox->ymask; + z = vox->znear + n; + + len = vox->slicelen[n] >> 8; + xstep = ((COS(vox->angle) >> 8) * len) / vox->fbwidth; + ystep = ((SIN(vox->angle) >> 8) * len) / vox->fbwidth; - hval = (vox->height[(ty << vox->xshift) + tx] - vox->vheight) * vox->proj_dist / y; + x = vox->x - SIN(vox->angle) * z - xstep * (vox->fbwidth >> 1); + y = vox->y + COS(vox->angle) * z - ystep * (vox->fbwidth >> 1); + for(i=0; ifbwidth; i++) { + hval = vox_height(vox, x, y) - vox->vheight; + hval = hval * 160 / (vox->znear + n) + vox->horizon; + if(hval > vox->fbheight) hval = vox->fbheight; if(hval > vox->coltop[i]) { - color = vox->color[(ty << vox->xshift) + tx]; - colstart = vox->fbheight - 1 - hval; + color = vox_color(vox, x, y); + colstart = vox->fbheight - hval; colheight = hval - vox->coltop[i]; fbptr = vox->fb + colstart * vox->fbwidth + i; + if(fog > 0) { + color = lerp_pcol_rgb(color, vox->fogcolor[0], vox->fogcolor[1], vox->fogcolor[2], fog); + } + for(j=0; jfbwidth; } + vox->coltop[i] = hval; } x += xstep; + y += ystep; + } +} + +void vox_sky_solid(struct voxscape *vox, uint32_t color) +{ + int i, j, colheight; + uint32_t *fbptr; + + for(i=0; ifbwidth; i++) { + fbptr = vox->fb + i; + colheight = vox->fbheight - vox->coltop[i]; + for(j=0; jfbwidth; + } + } +} + +void vox_sky_grad(struct voxscape *vox, uint32_t chor, uint32_t ctop) +{ + int i, j, colheight, t; + int r0, g0, b0, r1, g1, b1; + int d = vox->fbheight - vox->horizon; + uint32_t *grad, *fbptr; + + grad = alloca(vox->fbheight * sizeof *grad); + + b0 = ctop >> 16; + g0 = (ctop >> 8) & 0xff; + r0 = ctop & 0xff; + b1 = chor >> 16; + g1 = (chor >> 8) & 0xff; + r1 = chor & 0xff; + + for(i=0; ifbheight; i++) { + grad[i] = chor; + } + + for(i=0; ifbwidth; i++) { + fbptr = vox->fb + i; + colheight = vox->fbheight - vox->coltop[i]; + for(j=0; jfbwidth; + } + } +} + +static uint32_t lerp_rgb(int r0, int g0, int b0, int r1, int g1, int b1, int32_t t) +{ + int r = XLERP(r0, r1, t, 16); + int g = XLERP(g0, g1, t, 16); + int b = XLERP(b0, b1, t, 16); + return (b << 16) | (g << 8) | r; +} + +static uint32_t lerp_color(uint32_t ca, uint32_t cb, int32_t t) +{ + int r0, g0, b0, r1, g1, b1; + + b0 = ca >> 16; + g0 = (ca >> 8) & 0xff; + r0 = ca & 0xff; + b1 = cb >> 16; + g1 = (cb >> 8) & 0xff; + r1 = cb & 0xff; + + return lerp_rgb(r0, g0, b0, r1, g1, b1, t); } + +static uint32_t lerp_pcol_rgb(uint32_t pcol, int r, int g, int b, int32_t t) +{ + int b0 = pcol >> 16; + int g0 = (pcol >> 8) & 0xff; + int r0 = pcol & 0xff; + + return lerp_rgb(r0, g0, b0, r, g, b, t); +} +