interpolation
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 16 Oct 2022 23:01:04 +0000 (02:01 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 16 Oct 2022 23:01:04 +0000 (02:01 +0300)
src/main.c
src/voxscape.c
src/voxscape.h

index f0c89eb..bcf2250 100644 (file)
@@ -34,6 +34,7 @@ int win_width, win_height;
 unsigned int fb[FB_W * FB_H];
 
 int mouse_x, mouse_y, mwarp, mbstate[3];
+int hfilt = VOX_LINEAR, cfilt = VOX_LINEAR;
 
 unsigned int input;
 int32_t pos[2], angle;
@@ -82,6 +83,7 @@ int init(void)
        vox_framebuf(vox, FB_W, FB_H, fb, -1);
        vox_proj(vox, 45, 1, 300);
        vox_fog(vox, 260, COLOR_HORIZON);
+       vox_filter(vox, hfilt, cfilt);
 
        glfb_setup(FB_W, FB_H, GLFB_RGBA32, FB_W * 4);
        return 0;
@@ -186,6 +188,20 @@ void keyb(unsigned char key, int x, int y)
                input |= INP_RTURN;
                break;
 
+       case 'h':
+               hfilt ^= 1;
+               printf("filtering: height(%s) color(%s)\n", hfilt ? "linear" : "nearest",
+                               cfilt ? "linear" : "nearest");
+               vox_filter(vox, hfilt, cfilt);
+               break;
+
+       case 'c':
+               cfilt ^= 1;
+               vox_filter(vox, hfilt, cfilt);
+               printf("filtering: height(%s) color(%s)\n", hfilt ? "linear" : "nearest",
+                               cfilt ? "linear" : "nearest");
+               break;
+
        default:
                break;
        }
index 60d80a0..0b538d9 100644 (file)
@@ -8,6 +8,13 @@
 #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
 };
@@ -18,6 +25,8 @@ struct voxscape {
        uint32_t *color;
        int xshift, xmask, ymask;
 
+       int hfilt, cfilt;
+
        /* framebuffer */
        uint32_t *fb;
        int fbwidth, fbheight;
@@ -137,12 +146,61 @@ void vox_fog(struct voxscape *vox, int zstart, uint32_t color)
        vox->fogcolor[2] = 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)
 {
-       int tx = (x >> 16) & vox->xmask;
-       int ty = (y >> 16) & vox->ymask;
+       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;
 
-       return vox->height[(ty << vox->xshift) + tx];
+       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)
@@ -223,7 +281,7 @@ void vox_begin(struct voxscape *vox)
 
 void vox_render_slice(struct voxscape *vox, int n)
 {
-       int i, j, tx, ty, hval, colstart, colheight, z, r, g, b;
+       int i, j, hval, colstart, colheight, z;
        int32_t x, y, len, xstep, ystep, fog;
        uint32_t color;
        uint32_t *fbptr;
@@ -243,26 +301,17 @@ void vox_render_slice(struct voxscape *vox, int n)
        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; i<vox->fbwidth; i++) {
-               tx = (x >> 16) & vox->xmask;
-               ty = (y >> 16) & vox->ymask;
-
-               hval = vox->height[(ty << vox->xshift) + tx] - vox->vheight;
+               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];
+                       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) {
-                               r = color >> 16;
-                               g = (color >> 8) & 0xff;
-                               b = color & 0xff;
-                               r = ((r << 8) + (vox->fogcolor[0] - r) * fog) >> 8;
-                               g = ((g << 8) + (vox->fogcolor[1] - g) * fog) >> 8;
-                               b = ((b << 8) + (vox->fogcolor[2] - b) * fog) >> 8;
-                               color = (r << 16) | (g << 8) | b;
+                               color = lerp_pcol_rgb(color, vox->fogcolor[0], vox->fogcolor[1], vox->fogcolor[2], fog);
                        }
 
                        for(j=0; j<colheight; j++) {
@@ -295,7 +344,7 @@ void vox_sky_solid(struct voxscape *vox, uint32_t color)
 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, r, g, b;
+       int r0, g0, b0, r1, g1, b1;
        int d = vox->fbheight - vox->horizon;
        uint32_t *grad, *fbptr;
 
@@ -310,13 +359,7 @@ void vox_sky_grad(struct voxscape *vox, uint32_t chor, uint32_t ctop)
 
        for(i=0; i<d; i++) {
                t = (i << 8) / d;
-               r = ((r0 << 8) + (r1 - r0) * t) >> 8;
-               g = ((g0 << 8) + (g1 - g0) * t) >> 8;
-               b = ((b0 << 8) + (b1 - b0) * t) >> 8;
-               assert(r >= 0 && r < 256);
-               assert(g >= 0 && g < 256);
-               assert(b >= 0 && b < 256);
-               grad[i] = (r << 16) | (g << 8) | b;
+               grad[i] = lerp_rgb(r0, g0, b0, r1, g1, b1, t);
        }
        for(i=d; i<vox->fbheight; i++) {
                grad[i] = chor;
@@ -331,3 +374,35 @@ void vox_sky_grad(struct voxscape *vox, uint32_t chor, uint32_t ctop)
                }
        }
 }
+
+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 (r << 16) | (g << 8) | b;
+}
+
+static uint32_t lerp_color(uint32_t ca, uint32_t cb, int32_t t)
+{
+       int r0, g0, b0, r1, g1, b1;
+
+       r0 = ca >> 16;
+       g0 = (ca >> 8) & 0xff;
+       b0 = ca & 0xff;
+       r1 = cb >> 16;
+       g1 = (cb >> 8) & 0xff;
+       b1 = 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 r0 = pcol >> 16;
+       int g0 = (pcol >> 8) & 0xff;
+       int b0 = pcol & 0xff;
+
+       return lerp_rgb(r0, g0, b0, r, g, b, t);
+}
+
index 9bd5164..0602831 100644 (file)
@@ -3,6 +3,11 @@
 
 #include <stdint.h>
 
+enum {
+       VOX_NEAREST,
+       VOX_LINEAR
+};
+
 struct voxscape;
 
 #define VOX_RGB(r, g, b)       \
@@ -15,6 +20,8 @@ void vox_free(struct voxscape *vox);
 void vox_fog(struct voxscape *vox, int zstart, uint32_t color);
 int vox_height(struct voxscape *vox, int32_t x, int32_t y);
 
+void vox_filter(struct voxscape *vox, int hfilt, int cfilt);
+
 void vox_framebuf(struct voxscape *vox, int xres, int yres, uint32_t *fb, int horizon);
 /* negative height for auto at -h above terrain */
 void vox_view(struct voxscape *vox, int32_t x, int32_t y, int h, int32_t angle);