#include <math.h>
#include <assert.h>
#include "3dgfx.h"
+#include "gfxutil.h"
#include "polyfill.h"
+#include "polyclip.h"
#include "inttypes.h"
+#include "demo.h"
#include "util.h"
#define STACK_SIZE 8
typedef float g3d_matrix[16];
-#define MAX_VBUF_SIZE 256
#define MAX_LIGHTS 4
+#define IMM_VBUF_SIZE 256
+
struct light {
float x, y, z;
float r, g, b;
struct material mtl;
int width, height;
- void *pixels;
+ uint16_t *pixels;
+
+ int vport[4];
+
+ /* immediate mode */
+ int imm_prim;
+ int imm_numv, imm_pcount;
+ struct g3d_vertex imm_curv;
+ struct g3d_vertex imm_vbuf[IMM_VBUF_SIZE];
};
+static void imm_flush(void);
static void xform4_vec3(const float *mat, float *vec);
static void xform3_vec3(const float *mat, float *vec);
static void shade(struct g3d_vertex *v);
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;
+
+ g3d_viewport(0, 0, width, height);
+}
+
+void g3d_viewport(int x, int y, int w, int h)
+{
+ st->vport[0] = x;
+ st->vport[1] = y;
+ st->vport[2] = w;
+ st->vport[3] = h;
}
void g3d_enable(unsigned int opt)
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);
const int16_t *iarr, int iarr_size)
{
int i, j, nfaces;
- struct pvertex pv[4];
- struct g3d_vertex v[4];
+ struct pvertex pv[16];
+ struct g3d_vertex v[16];
int vnum = prim; /* primitive vertex counts correspond to enum values */
int mvtop = st->mtop[G3D_MODELVIEW];
int ptop = st->mtop[G3D_PROJECTION];
nfaces = (iarr ? iarr_size : varr_size) / vnum;
for(j=0; j<nfaces; j++) {
+ vnum = prim; /* reset vnum for each iteration */
for(i=0; i<vnum; i++) {
v[i] = iarr ? varr[*iarr++] : *varr++;
xform4_vec3(st->mat[G3D_PROJECTION][ptop], &v[i].x);
}
- /* TODO clipping */
+ /* clipping */
+ for(i=0; i<6; i++) {
+ struct g3d_vertex tmpv[16];
+ memcpy(tmpv, v, vnum * sizeof *v);
+
+ if(clip_frustum(v, &vnum, tmpv, vnum, i) < 0) {
+ /* polygon completely outside of view volume. discard */
+ vnum = 0;
+ break;
+ }
+ }
+
+ if(!vnum) continue;
for(i=0; i<vnum; i++) {
if(v[i].w != 0.0f) {
}
/* viewport transformation */
- v[i].x = (v[i].x * 0.5f + 0.5f) * (float)st->width;
- v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->height;
+ v[i].x = (v[i].x * 0.5f + 0.5f) * (float)st->vport[2] + st->vport[0];
+ v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->vport[3] + st->vport[1];
/* convert pos to 24.8 fixed point */
pv[i].x = cround64(v[i].x * 256.0f);
pv[i].r = v[i].r;
pv[i].g = v[i].g;
pv[i].b = v[i].b;
+ pv[i].a = v[i].a;
}
/* backface culling */
int32_t ay = pv[1].y - pv[0].y;
int32_t bx = pv[2].x - pv[0].x;
int32_t by = pv[2].y - pv[0].y;
- int32_t cross_z = ax * (by >> 8) - ay * (bx >> 8);
+ int32_t cross_z = (ax >> 4) * (by >> 4) - (ay >> 4) * (bx >> 4);
int sign = (cross_z >> 31) & 1;
if(!(sign ^ st->frontface)) {
}
}
- polyfill(st->fill_mode, pv, vnum);
+ switch(vnum) {
+ case 1:
+ 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);
+ } 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);
+ }
+ break;
+
+ case 2:
+ /* TODO: draw line */
+ break;
+
+ default:
+ polyfill(st->fill_mode, pv, vnum);
+ }
}
}
+void g3d_begin(int prim)
+{
+ st->imm_prim = prim;
+ st->imm_pcount = prim;
+ st->imm_numv = 0;
+}
+
+void g3d_end(void)
+{
+ imm_flush();
+}
+
+static void imm_flush(void)
+{
+ int numv = st->imm_numv;
+ st->imm_numv = 0;
+ g3d_draw_indexed(st->imm_prim, st->imm_vbuf, numv, 0, 0);
+}
+
+void g3d_vertex(float x, float y, float z)
+{
+ struct g3d_vertex *vptr = st->imm_vbuf + st->imm_numv++;
+ *vptr = st->imm_curv;
+ vptr->x = x;
+ vptr->y = y;
+ vptr->z = z;
+ vptr->w = 1.0f;
+
+ if(!--st->imm_pcount) {
+ if(st->imm_numv >= IMM_VBUF_SIZE - st->imm_prim) {
+ imm_flush();
+ }
+ st->imm_pcount = st->imm_prim;
+ }
+}
+
+void g3d_normal(float x, float y, float z)
+{
+ st->imm_curv.nx = x;
+ st->imm_curv.ny = y;
+ st->imm_curv.nz = z;
+}
+
+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.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;
+}
+
+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.a = 255;
+}
+
+void g3d_color4f(float r, float g, float b, float a)
+{
+ int ir = r * 255.0f;
+ 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;
+}
+
+void g3d_texcoord(float u, float v)
+{
+ st->imm_curv.u = u;
+ st->imm_curv.v = v;
+}
+
static void xform4_vec3(const float *mat, float *vec)
{
float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12];