#include "3dgfx.h"
#include "polyfill.h"
#include "inttypes.h"
+#include "util.h"
#define STACK_SIZE 8
typedef float g3d_matrix[16];
#define MAX_VBUF_SIZE 256
+#define MAX_LIGHTS 4
+
+struct light {
+ float x, y, z;
+ float r, g, b;
+};
+
+struct material {
+ float kd[3];
+ float ks[3];
+ float shin;
+};
struct g3d_state {
unsigned int opt;
int frontface;
+ int fill_mode;
g3d_matrix mat[G3D_NUM_MATRICES][STACK_SIZE];
int mtop[G3D_NUM_MATRICES];
g3d_matrix norm_mat;
+ float ambient[3];
+ struct light lt[MAX_LIGHTS];
+ struct material mtl;
+
int width, height;
void *pixels;
};
fprintf(stderr, "failed to allocate G3D context\n");
return -1;
}
+ st->fill_mode = POLYFILL_FLAT;
for(i=0; i<G3D_NUM_MATRICES; i++) {
g3d_matrix_mode(i);
g3d_load_identity();
}
+
+ for(i=0; i<MAX_LIGHTS; i++) {
+ g3d_light_color(i, 1, 1, 1);
+ }
+ g3d_light_ambient(0.1, 0.1, 0.1);
+
+ g3d_mtl_diffuse(1, 1, 1);
return 0;
}
st->width = width;
st->height = height;
st->pixels = pixels;
+
+ pfill_fb.pixels = pixels;
+ pfill_fb.width = width;
+ pfill_fb.height = height;
}
void g3d_enable(unsigned int opt)
st->frontface = order;
}
+void g3d_polygon_mode(int pmode)
+{
+ st->fill_mode = pmode;
+}
+
void g3d_matrix_mode(int mmode)
{
st->mmode = mmode;
g3d_mult_matrix(m);
}
-#define CROSS(res, a, b) \
- do { \
- (res)[0] = (a)[1] * (b)[2] - (a)[2] * (b)[1]; \
- (res)[1] = (a)[2] * (b)[0] - (a)[0] * (b)[2]; \
- (res)[2] = (a)[0] * (b)[1] - (a)[1] * (b)[0]; \
- } while(0)
+const float *g3d_get_matrix(int which, float *m)
+{
+ int top = st->mtop[which];
+
+ if(m) {
+ memcpy(m, st->mat[which][top], 16 * sizeof(float));
+ }
+ return st->mat[which][top];
+}
+
+void g3d_light_pos(int idx, float x, float y, float z)
+{
+ int mvtop = st->mtop[G3D_MODELVIEW];
+
+ st->lt[idx].x = x;
+ st->lt[idx].y = y;
+ st->lt[idx].z = z;
+
+ xform4_vec3(st->mat[G3D_MODELVIEW][mvtop], &st->lt[idx].x);
+}
+
+void g3d_light_color(int idx, float r, float g, float b)
+{
+ st->lt[idx].r = r;
+ st->lt[idx].g = g;
+ st->lt[idx].b = b;
+}
+
+void g3d_light_ambient(float r, float g, float b)
+{
+ st->ambient[0] = r;
+ st->ambient[1] = g;
+ st->ambient[2] = b;
+}
+
+void g3d_mtl_diffuse(float r, float g, float b)
+{
+ st->mtl.kd[0] = r;
+ st->mtl.kd[1] = g;
+ st->mtl.kd[2] = b;
+}
+
+void g3d_mtl_specular(float r, float g, float b)
+{
+ st->mtl.ks[0] = r;
+ st->mtl.ks[1] = g;
+ st->mtl.ks[2] = b;
+}
+
+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)
{
- int i;
+ g3d_draw_indexed(prim, varr, varr_size, 0, 0);
+}
+
+void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
+ const int16_t *iarr, int iarr_size)
+{
+ int i, j, nfaces;
struct pvertex pv[4];
struct g3d_vertex v[4];
int vnum = prim; /* primitive vertex counts correspond to enum values */
memcpy(st->norm_mat, st->mat[G3D_MODELVIEW][mvtop], 16 * sizeof(float));
st->norm_mat[12] = st->norm_mat[13] = st->norm_mat[14] = 0.0f;
- while(varr_size >= vnum) {
- varr_size -= vnum;
+ nfaces = (iarr ? iarr_size : varr_size) / vnum;
+
+ for(j=0; j<nfaces; j++) {
for(i=0; i<vnum; i++) {
- v[i] = *varr++;
+ v[i] = iarr ? varr[*iarr++] : *varr++;
xform4_vec3(st->mat[G3D_MODELVIEW][mvtop], &v[i].x);
xform3_vec3(st->norm_mat, &v[i].nx);
v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->height;
/* convert pos to 24.8 fixed point */
- pv[i].x = (int32_t)(v[i].x * 256.0f);
- pv[i].y = (int32_t)(v[i].y * 256.0f);
+ pv[i].x = cround64(v[i].x * 256.0f);
+ pv[i].y = cround64(v[i].y * 256.0f);
/* convert tex coords to 16.16 fixed point */
- pv[i].u = (int32_t)(v[i].u * 65536.0f);
- pv[i].v = (int32_t)(v[i].v * 65536.0f);
+ pv[i].u = cround64(v[i].u * 65536.0f);
+ pv[i].v = cround64(v[i].v * 65536.0f);
/* pass the color through as is */
pv[i].r = v[i].r;
pv[i].g = v[i].g;
}
}
- polyfill_flat(pv, vnum);
+ polyfill(st->fill_mode, pv, vnum);
}
}
vec[2] = z;
}
+#define NORMALIZE(v) \
+ do { \
+ float len = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); \
+ if(len != 0.0) { \
+ float s = 1.0 / len; \
+ v[0] *= s; \
+ v[1] *= s; \
+ v[2] *= s; \
+ } \
+ } while(0)
+
static void shade(struct g3d_vertex *v)
{
- v->r = v->g = v->b = 255;
+ int i, r, g, b;
+ float color[3];
+
+ color[0] = st->ambient[0] * st->mtl.kd[0];
+ color[1] = st->ambient[1] * st->mtl.kd[1];
+ color[2] = st->ambient[2] * st->mtl.kd[2];
+
+ for(i=0; i<MAX_LIGHTS; i++) {
+ float ldir[3];
+ float ndotl;
+
+ if(!(st->opt & (G3D_LIGHT0 << i))) {
+ continue;
+ }
+
+ ldir[0] = st->lt[i].x - v->x;
+ ldir[1] = st->lt[i].y - v->y;
+ ldir[2] = st->lt[i].z - v->z;
+ NORMALIZE(ldir);
+
+ if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
+ ndotl = 0.0f;
+ }
+
+ color[0] += st->mtl.kd[0] * st->lt[i].r * ndotl;
+ color[1] += st->mtl.kd[1] * st->lt[i].g * ndotl;
+ color[2] += st->mtl.kd[2] * st->lt[i].b * ndotl;
+ }
+
+ r = cround64(color[0] * 255.0);
+ g = cround64(color[1] * 255.0);
+ b = cround64(color[2] * 255.0);
+
+ v->r = r > 255 ? 255 : r;
+ v->g = g > 255 ? 255 : g;
+ v->b = b > 255 ? 255 : b;
}