added texture mapping
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Tue, 4 Oct 2016 03:00:26 +0000 (06:00 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Tue, 4 Oct 2016 03:00:26 +0000 (06:00 +0300)
src/3dgfx.c
src/3dgfx.h
src/gfxutil.h
src/polyfill.c
src/polyfill.h
src/polytest.c
src/polytmpl.h

index d7e2e41..47b3830 100644 (file)
@@ -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);
index ecc3f3c..fbbccf6 100644 (file)
@@ -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);
index f811987..07883ef 100644 (file)
@@ -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))
 
index 634d525..0d1351e 100644 (file)
@@ -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);
        }
 }
index a01130c..2a6b42d 100644 (file)
@@ -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);
index e7c3cdf..800dd46 100644 (file)
@@ -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; i<torus.vcount; i++) {
+               torus.varr[i].u *= 4.0;
+               torus.varr[i].v *= 2.0;
+       }
+
+       gen_texture(&tex, 128, 128);
 
 #ifdef DEBUG_POLYFILL
        lowres_width = fb_width / LOWRES_SCALE;
@@ -77,7 +90,7 @@ static void start(long trans_time)
        g3d_enable(G3D_LIGHTING);
        g3d_enable(G3D_LIGHT0);
 
-       g3d_polygon_mode(G3D_GOURAUD);
+       g3d_polygon_mode(G3D_TEX_GOURAUD);
 }
 
 static void update(void)
@@ -121,7 +134,9 @@ static void draw(void)
 
        zsort(&torus);
 
-       g3d_mtl_diffuse(0.3, 0.6, 1.0);
+       g3d_mtl_diffuse(0.4, 0.7, 1.0);
+       g3d_set_texture(tex.width, tex.height, tex.pixels);
+
        draw_mesh(&torus);
 
        /*draw_mesh(&cube);*/
@@ -378,3 +393,26 @@ static void draw_lowres_raster(void)
                dptr += fb_width * LOWRES_SCALE - fb_width;
        }
 }
+
+static int gen_texture(struct pimage *img, int xsz, int ysz)
+{
+       int i, j;
+       uint16_t *pix;
+
+       if(!(img->pixels = malloc(xsz * ysz * sizeof *pix))) {
+               return -1;
+       }
+       pix = img->pixels;
+
+       for(i=0; i<ysz; i++) {
+               for(j=0; j<xsz; j++) {
+                       int val = i ^ j;
+
+                       *pix++ = PACK_RGB16(val, val, val);
+               }
+       }
+
+       img->width = xsz;
+       img->height = ysz;
+       return 0;
+}
index 2021b3b..79660ef 100644 (file)
@@ -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<nverts; i++) {
                int next = NEXTIDX(i);
@@ -156,7 +156,7 @@ void POLYFILL(struct pvertex *pv, int nverts)
                int32_t x;
 
                x = left[i].x;
-               pixptr = pimg_fb.pixels + i * pimg_fb.width + (x >> 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;