struct g3d_state {
unsigned int opt;
int frontface;
- int fill_mode;
+ int polymode;
g3d_matrix mat[G3D_NUM_MATRICES][STACK_SIZE];
int mtop[G3D_NUM_MATRICES];
struct material mtl;
int width, height;
- uint16_t *pixels;
+ g3d_pixel *pixels;
int vport[4];
return -1;
}
st->opt = G3D_CLIP_FRUSTUM;
- st->fill_mode = POLYFILL_FLAT;
+ st->polymode = POLYFILL_FLAT;
for(i=0; i<G3D_NUM_MATRICES; i++) {
g3d_matrix_mode(i);
void g3d_polygon_mode(int pmode)
{
- st->fill_mode = pmode;
+ st->polymode = pmode;
}
void g3d_matrix_mode(int mmode)
void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
const uint16_t *iarr, int iarr_size)
{
- int i, j, vnum, nfaces;
+ int i, j, vnum, nfaces, fill_mode;
struct pvertex pv[16];
struct g3d_vertex v[16];
int mvtop = st->mtop[G3D_MODELVIEW];
if(st->opt & G3D_BLEND) {
int r, g, b;
int inv_alpha = 255 - pv[0].a;
- uint16_t *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
- r = ((int)pv[0].r * pv[0].a + UNPACK_R16(*dest) * inv_alpha) >> 8;
- g = ((int)pv[0].g * pv[0].a + UNPACK_G16(*dest) * inv_alpha) >> 8;
- b = ((int)pv[0].b * pv[0].a + UNPACK_B16(*dest) * inv_alpha) >> 8;
- *dest++ = PACK_RGB16(r, g, b);
+ g3d_pixel *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
+ r = ((int)pv[0].r * pv[0].a + G3D_UNPACK_R(*dest) * inv_alpha) >> 8;
+ g = ((int)pv[0].g * pv[0].a + G3D_UNPACK_G(*dest) * inv_alpha) >> 8;
+ b = ((int)pv[0].b * pv[0].a + G3D_UNPACK_B(*dest) * inv_alpha) >> 8;
+ *dest++ = G3D_PACK_RGB(r, g, b);
} else {
- uint16_t *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
- *dest = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b);
+ g3d_pixel *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
+ *dest = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
}
break;
case 2:
{
- uint16_t col = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b);
+ g3d_pixel col = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
draw_line(pv[0].x >> 8, pv[0].y >> 8, pv[1].x >> 8, pv[1].y >> 8, col);
}
break;
default:
- polyfill(st->fill_mode, pv, vnum);
+ fill_mode = st->polymode;
+ if(st->opt & G3D_TEXTURE_2D) {
+ fill_mode |= POLYFILL_TEX_BIT;
+ }
+ if(st->opt & G3D_BLEND) {
+ fill_mode |= POLYFILL_BLEND_BIT;
+ }
+ polyfill(fill_mode, pv, vnum);
}
}
}
st->imm_curv.nz = z;
}
+#define CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
+
void g3d_color3b(unsigned char r, unsigned char g, unsigned char b)
{
- st->imm_curv.r = r;
- st->imm_curv.g = g;
- st->imm_curv.b = b;
+ st->imm_curv.r = CLAMP(r, 0, 255);
+ st->imm_curv.g = CLAMP(g, 0, 255);
+ st->imm_curv.b = CLAMP(b, 0, 255);
st->imm_curv.a = 255;
}
void g3d_color4b(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
- st->imm_curv.r = r;
- st->imm_curv.g = g;
- st->imm_curv.b = b;
- st->imm_curv.a = a;
+ st->imm_curv.r = CLAMP(r, 0, 255);
+ st->imm_curv.g = CLAMP(g, 0, 255);
+ st->imm_curv.b = CLAMP(b, 0, 255);
+ st->imm_curv.a = CLAMP(a, 0, 255);
}
void g3d_color3f(float r, float g, float b)
int ir = r * 255.0f;
int ig = g * 255.0f;
int ib = b * 255.0f;
- st->imm_curv.r = ir > 255 ? 255 : ir;
- st->imm_curv.g = ig > 255 ? 255 : ig;
- st->imm_curv.b = ib > 255 ? 255 : ib;
+ st->imm_curv.r = CLAMP(ir, 0, 255);
+ st->imm_curv.g = CLAMP(ig, 0, 255);
+ st->imm_curv.b = CLAMP(ib, 0, 255);
st->imm_curv.a = 255;
}
int ig = g * 255.0f;
int ib = b * 255.0f;
int ia = a * 255.0f;
- st->imm_curv.r = ir > 255 ? 255 : ir;
- st->imm_curv.g = ig > 255 ? 255 : ig;
- st->imm_curv.b = ib > 255 ? 255 : ib;
- st->imm_curv.a = ia > 255 ? 255 : ia;
+ st->imm_curv.r = CLAMP(ir, 0, 255);
+ st->imm_curv.g = CLAMP(ig, 0, 255);
+ st->imm_curv.b = CLAMP(ib, 0, 255);
+ st->imm_curv.a = CLAMP(ia, 0, 255);
}
void g3d_texcoord(float u, float v)
#define THREEDGFX_H_
#include "inttypes.h"
+#include "gfxutil.h"
+
+#define G3D_PIXFMT16
+typedef uint16_t g3d_pixel;
+
+#ifdef G3D_PIXFMT16
+#define G3D_PACK_RGB(r, g, b) PACK_RGB16(r, g, b)
+#define G3D_UNPACK_R(c) UNPACK_R16(c)
+#define G3D_UNPACK_G(c) UNPACK_G16(c)
+#define G3D_UNPACK_B(c) UNPACK_B16(c)
+#endif
+#ifdef G3D_PIXFMT32
+#define G3D_PACK_RGB(r, g, b) PACK_RGB32(r, g, b)
+#define G3D_UNPACK_R(c) UNPACK_R32(c)
+#define G3D_UNPACK_G(c) UNPACK_G32(c)
+#define G3D_UNPACK_B(c) UNPACK_B32(c)
+#endif
+
struct g3d_vertex {
float x, y, z, w;
enum {
G3D_WIRE,
G3D_FLAT,
- G3D_GOURAUD,
- G3D_TEX,
- G3D_TEX_GOURAUD
+ G3D_GOURAUD
};
/* matrix stacks */
#define PACK_RGB32(r, g, b) \
((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff))
+#define UNPACK_R32(c) (((c) >> 16) & 0xff)
+#define UNPACK_G32(c) (((c) >> 8) & 0xff)
+#define UNPACK_B32(c) ((c) & 0xff)
+
int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax);
void draw_line(int x0, int y0, int x1, int y1, unsigned short color);
memset(fb_pixels, 0, fb_width * fb_height * 2);
- g3d_polygon_mode(G3D_TEX);
+ g3d_polygon_mode(G3D_FLAT);
+ g3d_enable(G3D_TEXTURE_2D);
g3d_enable(G3D_TEXTURE_GEN);
g3d_push_matrix();
#endif
#include "polyfill.h"
#include "gfxutil.h"
-#include "demo.h"
+#define FILL_POLY_BITS 0x03
+
+/* mode bits: 00-wire 01-flat 10-gouraud 11-reserved
+ * bit 2: texture
+ * bit 3: blend
+ */
void (*fillfunc[])(struct pvertex*, int) = {
polyfill_wire,
polyfill_flat,
polyfill_gouraud,
- polyfill_tex,
- polyfill_tex_gouraud
+ 0,
+ polyfill_tex_wire,
+ polyfill_tex_flat,
+ polyfill_tex_gouraud,
+ 0,
+ polyfill_blend_wire,
+ polyfill_blend_flat,
+ polyfill_blend_gouraud,
+ 0,
+ polyfill_blend_tex_wire,
+ polyfill_blend_tex_flat,
+ polyfill_blend_tex_gouraud,
+ 0
};
struct pimage pfill_fb, pfill_tex;
}
}
+void polyfill_tex_wire(struct pvertex *verts, int nverts)
+{
+ polyfill_wire(verts, nverts); /* TODO */
+}
+
+void polyfill_blend_wire(struct pvertex *verts, int nverts)
+{
+ polyfill_wire(verts, nverts); /* TODO */
+}
+
+void polyfill_blend_tex_wire(struct pvertex *verts, int nverts)
+{
+ polyfill_wire(verts, nverts); /* TODO */
+}
+
#define NEXTIDX(x) (((x) - 1 + nverts) % nverts)
#define PREVIDX(x) (((x) + 1) % nverts)
#define SCANEDGE scanedge_flat
#undef GOURAUD
#undef TEXMAP
+#undef BLEND
#include "polytmpl.h"
#undef POLYFILL
#undef SCANEDGE
#define SCANEDGE scanedge_gouraud
#define GOURAUD
#undef TEXMAP
+#undef BLEND
#include "polytmpl.h"
#undef POLYFILL
#undef SCANEDGE
-#define POLYFILL polyfill_tex
-#define SCANEDGE scanedge_tex
+#define POLYFILL polyfill_tex_flat
+#define SCANEDGE scanedge_tex_flat
#undef GOURAUD
#define TEXMAP
+#undef BLEND
#include "polytmpl.h"
#undef POLYFILL
#undef SCANEDGE
#define SCANEDGE scanedge_tex_gouraud
#define GOURAUD
#define TEXMAP
+#undef BLEND
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_blend_flat
+#define SCANEDGE scanedge_blend_flat
+#undef GOURAUD
+#undef TEXMAP
+#define BLEND
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_blend_gouraud
+#define SCANEDGE scanedge_blend_gouraud
+#define GOURAUD
+#undef TEXMAP
+#define BLEND
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_blend_tex_flat
+#define SCANEDGE scanedge_blend_tex_flat
+#undef GOURAUD
+#define TEXMAP
+#define BLEND
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_blend_tex_gouraud
+#define SCANEDGE scanedge_blend_tex_gouraud
+#define GOURAUD
+#define TEXMAP
+#define BLEND
#include "polytmpl.h"
#undef POLYFILL
#undef SCANEDGE
#define POLYFILL_H_
#include "inttypes.h"
+#include "3dgfx.h"
+
+#define POLYFILL_MODE_MASK 0x03
+#define POLYFILL_TEX_BIT 0x04
+#define POLYFILL_BLEND_BIT 0x08
enum {
- POLYFILL_WIRE,
+ POLYFILL_WIRE = 0,
POLYFILL_FLAT,
POLYFILL_GOURAUD,
- POLYFILL_TEX,
- POLYFILL_TEX_GOURAUD
+
+ POLYFILL_TEX_WIRE = 4,
+ POLYFILL_TEX_FLAT,
+ POLYFILL_TEX_GOURAUD,
+
+ POLYFILL_BLEND_WIRE = 8,
+ POLYFILL_BLEND_FLAT,
+ POLYFILL_BLEND_GOURAUD,
+
+ POLYFILL_BLEND_TEX_WIRE = 12,
+ POLYFILL_BLEND_TEX_FLAT,
+ POLYFILL_BLEND_TEX_GOURAUD
};
/* projected vertices for the rasterizer */
};
struct pimage {
- uint16_t *pixels;
+ g3d_pixel *pixels;
int width, height;
int xshift, yshift;
extern struct pimage pfill_tex;
void polyfill(int mode, struct pvertex *verts, int nverts);
+
void polyfill_wire(struct pvertex *verts, int nverts);
void polyfill_flat(struct pvertex *verts, int nverts);
void polyfill_gouraud(struct pvertex *verts, int nverts);
-void polyfill_tex(struct pvertex *verts, int nverts);
+void polyfill_tex_wire(struct pvertex *verts, int nverts);
+void polyfill_tex_flat(struct pvertex *verts, int nverts);
void polyfill_tex_gouraud(struct pvertex *verts, int nverts);
+void polyfill_blend_wire(struct pvertex *verts, int nverts);
+void polyfill_blend_flat(struct pvertex *verts, int nverts);
+void polyfill_blend_gouraud(struct pvertex *verts, int nverts);
+void polyfill_blend_tex_wire(struct pvertex *verts, int nverts);
+void polyfill_blend_tex_flat(struct pvertex *verts, int nverts);
+void polyfill_blend_tex_gouraud(struct pvertex *verts, int nverts);
#endif /* POLYFILL_H_ */
g3d_enable(G3D_LIGHTING);
g3d_enable(G3D_LIGHT0);
- g3d_polygon_mode(G3D_TEX_GOURAUD);
+ g3d_polygon_mode(G3D_GOURAUD);
+ g3d_enable(G3D_TEXTURE_2D);
}
static void update(void)
#ifdef GOURAUD
int r, g, b, dr, dg, db;
int32_t rslope, gslope, bslope;
+#ifdef BLEND
+ int32_t a, da, aslope;
#endif
+#endif /* GOURAUD */
#ifdef TEXMAP
int32_t u, v, du, dv, uslope, vslope;
#endif
rslope = (dr << 8) / dy;
gslope = (dg << 8) / dy;
bslope = (db << 8) / dy;
-#endif
+#ifdef BLEND
+ a = (v0->a << COLOR_SHIFT);
+ da = (v1->a << COLOR_SHIFT) - a;
+ aslope = (da << 8) / dy;
+#endif /* BLEND */
+#endif /* GOURAUD */
#ifdef TEXMAP
u = v0->u;
v = v0->v;
r += rslope;
g += gslope;
b += bslope;
+#ifdef BLEND
+ edge[i].a = a;
+ a += aslope;
#endif
+#endif /* GOURAUD */
#ifdef TEXMAP
edge[i].u = u;
edge[i].v = v;
int i, winding;
int topidx = 0, botidx = 0, sltop = pfill_fb.height, slbot = 0;
struct pvertex *left, *right;
- uint16_t color;
+ g3d_pixel color;
/* the following variables are used for interpolating horizontally accros scanlines */
#if defined(GOURAUD) || defined(TEXMAP)
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);
+ color = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
#endif
#ifdef GOURAUD
int32_t r, g, b, dr, dg, db, rslope, gslope, bslope;
+#ifdef BLEND
+ int32_t a, da, aslope;
+#endif
#endif
#ifdef TEXMAP
int32_t u, v, du, dv, uslope, vslope;
right[idx].r = pv[i1].r << COLOR_SHIFT;
right[idx].g = pv[i1].g << COLOR_SHIFT;
right[idx].b = pv[i1].b << COLOR_SHIFT;
+#ifdef BLEND
+ left[idx].a = pv[i0].a << COLOR_SHIFT;
+ right[idx].a = pv[i1].a << COLOR_SHIFT;
+#endif /* BLEND */
#endif
#ifdef TEXMAP
left[idx].u = pv[i0].u;
rslope = (dr << 8) / dx;
gslope = (dg << 8) / dx;
bslope = (db << 8) / dx;
+#ifdef BLEND
+ da = right[mid].a - left[mid].a;
+ aslope = (da << 8) / dx;
+#endif /* BLEND */
#endif
#ifdef TEXMAP
du = right[mid].u - left[mid].u;
/* for each scanline ... */
for(i=sltop; i<=slbot; i++) {
- uint16_t *pixptr;
+ g3d_pixel *pixptr;
int32_t x;
x = left[i].x;
r = left[i].r;
g = left[i].g;
b = left[i].b;
+#ifdef BLEND
+ a = left[i].a;
+#endif /* BLEND */
#endif
#ifdef TEXMAP
u = left[i].u;
rslope = (dr << 8) / dx;
gslope = (dg << 8) / dx;
bslope = (db << 8) / dx;
-#endif
+#ifdef BLEND
+ da = right[i].a - left[i].a;
+ aslope = (da << 8) / dx;
+#endif /* BLEND */
+#endif /* GOURAUD */
#ifdef TEXMAP
du = right[i].u - left[i].u;
dv = right[i].v - left[i].v;
/* go across the scanline interpolating if necessary */
while(x <= right[i].x) {
-#if defined(GOURAUD) || defined(TEXMAP)
+#if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND)
int cr, cg, cb;
#endif
+#ifdef BLEND
+ g3d_pixel fbcol;
+ int alpha, inv_alpha;
+#endif
#ifdef GOURAUD
/* 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;
-#endif
+#ifdef BLEND
+ a += aslope;
+#else
+ if(cr > 255) cr = 255;
+ if(cg > 255) cg = 255;
+ if(cb > 255) cb = 255;
+#endif /* BLEND */
+#endif /* GOURAUD */
#ifdef TEXMAP
{
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];
+ g3d_pixel texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx];
#ifdef GOURAUD
/* 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;
+ cr = (cr * G3D_UNPACK_R(texel)) >> 8;
+ cg = (cg * G3D_UNPACK_G(texel)) >> 8;
+ cb = (cb * G3D_UNPACK_B(texel)) >> 8;
#else
- cr = UNPACK_R16(texel);
- cg = UNPACK_G16(texel);
- cb = UNPACK_B16(texel);
+ cr = G3D_UNPACK_R(texel);
+ cg = G3D_UNPACK_G(texel);
+ cb = G3D_UNPACK_B(texel);
#endif
}
u += uslope;
v += vslope;
#endif
-#if defined(GOURAUD) || defined(TEXMAP)
- color = PACK_RGB16(cr, cg, cb);
+
+#ifdef BLEND
+#if !defined(GOURAUD) && !defined(TEXMAP)
+ /* flat version: cr,cg,cb are uninitialized so far */
+ cr = pv[0].r;
+ cg = pv[0].g;
+ cb = pv[0].b;
+#endif
+#ifdef GOURAUD
+ alpha = a >> COLOR_SHIFT;
+#else
+ alpha = pv[0].a;
+#endif
+ fbcol = *pixptr;
+ inv_alpha = 255 - alpha;
+ cr = (cr * alpha + G3D_UNPACK_R(fbcol) * inv_alpha) >> 8;
+ cg = (cg * alpha + G3D_UNPACK_G(fbcol) * inv_alpha) >> 8;
+ cb = (cb * alpha + G3D_UNPACK_B(fbcol) * inv_alpha) >> 8;
+ if(cr > 255) cr = 255;
+ if(cg > 255) cg = 255;
+ if(cb > 255) cb = 255;
+#endif /* BLEND */
+
+#if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND)
+ color = G3D_PACK_RGB(cr, cg, cb);
#endif
#ifdef DEBUG_OVERDRAW