target remote localhost:1234
-symbol-file test.sym
+symbol-file bcensus.sym
*.swp
*.d
*.bin
-*.elf
+bcensus
*.map
*.sym
*.disasm
Ssrc = $(wildcard src/*.S)
obj = $(csrc:.c=.o) $(ssrc:.s=.o) $(Ssrc:.S=.o)
dep = $(obj:.o=.d)
-elf = bcensus.elf
+elf = bcensus
bin = bcensus.bin
warn = -pedantic -Wall
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+#include "3dgfx.h"
+#include "gfxutil.h"
+#include "polyfill.h"
+#include "polyclip.h"
+#include "inttypes.h"
+#include "census.h"
+#include "util.h"
+
+#define STACK_SIZE 8
+typedef float g3d_matrix[16];
+
+#define MAX_LIGHTS 4
+
+#define IMM_VBUF_SIZE 256
+
+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 polymode;
+
+ g3d_matrix mat[G3D_NUM_MATRICES][STACK_SIZE];
+ int mtop[G3D_NUM_MATRICES];
+ int mmode;
+
+ g3d_matrix norm_mat;
+
+ float ambient[3];
+ struct light lt[MAX_LIGHTS];
+ struct material mtl;
+
+ int width, height;
+ uint32_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);
+
+static struct g3d_state *st;
+static const float idmat[] = {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+};
+
+int g3d_init(void)
+{
+ int i;
+
+ if(!(st = calloc(1, sizeof *st))) {
+ fprintf(stderr, "failed to allocate G3D context\n");
+ return -1;
+ }
+ st->opt = G3D_CLIP_FRUSTUM;
+ st->polymode = 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;
+}
+
+void g3d_destroy(void)
+{
+ free(st);
+}
+
+void g3d_framebuffer(int width, int height, void *pixels)
+{
+ st->width = width;
+ st->height = height;
+ st->pixels = pixels;
+
+ pfill_fb.pixels = pixels;
+ pfill_fb.width = width;
+ pfill_fb.height = height;
+
+ g3d_viewport(0, 0, width, height);
+}
+
+/* set the framebuffer pointer, without resetting the size */
+void g3d_framebuffer_addr(void *pixels)
+{
+ st->pixels = pixels;
+ pfill_fb.pixels = pixels;
+}
+
+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->opt |= opt;
+}
+
+void g3d_disable(unsigned int opt)
+{
+ st->opt &= ~opt;
+}
+
+void g3d_setopt(unsigned int opt, unsigned int mask)
+{
+ st->opt = (st->opt & ~mask) | (opt & mask);
+}
+
+unsigned int g3d_getopt(unsigned int mask)
+{
+ return st->opt & mask;
+}
+
+void g3d_front_face(unsigned int order)
+{
+ st->frontface = order;
+}
+
+void g3d_polygon_mode(int pmode)
+{
+ st->polymode = pmode;
+}
+
+void g3d_matrix_mode(int mmode)
+{
+ st->mmode = mmode;
+}
+
+void g3d_load_identity(void)
+{
+ int top = st->mtop[st->mmode];
+ memcpy(st->mat[st->mmode][top], idmat, 16 * sizeof(float));
+}
+
+void g3d_load_matrix(const float *m)
+{
+ int top = st->mtop[st->mmode];
+ memcpy(st->mat[st->mmode][top], m, 16 * sizeof(float));
+}
+
+#define M(i,j) (((i) << 2) + (j))
+void g3d_mult_matrix(const float *m2)
+{
+ int i, j, top = st->mtop[st->mmode];
+ float m1[16];
+ float *dest = st->mat[st->mmode][top];
+
+ memcpy(m1, dest, sizeof m1);
+
+ for(i=0; i<4; i++) {
+ for(j=0; j<4; j++) {
+ *dest++ = m1[M(0,j)] * m2[M(i,0)] +
+ m1[M(1,j)] * m2[M(i,1)] +
+ m1[M(2,j)] * m2[M(i,2)] +
+ m1[M(3,j)] * m2[M(i,3)];
+ }
+ }
+}
+
+void g3d_push_matrix(void)
+{
+ int top = st->mtop[st->mmode];
+ if(top >= G3D_NUM_MATRICES) {
+ fprintf(stderr, "g3d_push_matrix overflow\n");
+ return;
+ }
+ memcpy(st->mat[st->mmode][top + 1], st->mat[st->mmode][top], 16 * sizeof(float));
+ st->mtop[st->mmode] = top + 1;
+}
+
+void g3d_pop_matrix(void)
+{
+ if(st->mtop[st->mmode] <= 0) {
+ fprintf(stderr, "g3d_pop_matrix underflow\n");
+ return;
+ }
+ --st->mtop[st->mmode];
+}
+
+void g3d_translate(float x, float y, float z)
+{
+ float m[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
+ m[12] = x;
+ m[13] = y;
+ m[14] = z;
+ g3d_mult_matrix(m);
+}
+
+void g3d_rotate(float deg, float x, float y, float z)
+{
+ float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ float angle = M_PI * deg / 180.0f;
+ float sina = sin(angle);
+ float cosa = cos(angle);
+ float one_minus_cosa = 1.0f - cosa;
+ float nxsq = x * x;
+ float nysq = y * y;
+ float nzsq = z * z;
+
+ m[0] = nxsq + (1.0f - nxsq) * cosa;
+ m[4] = x * y * one_minus_cosa - z * sina;
+ m[8] = x * z * one_minus_cosa + y * sina;
+ m[1] = x * y * one_minus_cosa + z * sina;
+ m[5] = nysq + (1.0 - nysq) * cosa;
+ m[9] = y * z * one_minus_cosa - x * sina;
+ m[2] = x * z * one_minus_cosa - y * sina;
+ m[6] = y * z * one_minus_cosa + x * sina;
+ m[10] = nzsq + (1.0 - nzsq) * cosa;
+ m[15] = 1.0f;
+
+ g3d_mult_matrix(m);
+}
+
+void g3d_scale(float x, float y, float z)
+{
+ float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ m[0] = x;
+ m[5] = y;
+ m[10] = z;
+ m[15] = 1.0f;
+ g3d_mult_matrix(m);
+}
+
+void g3d_ortho(float left, float right, float bottom, float top, float znear, float zfar)
+{
+ float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ float dx = right - left;
+ float dy = top - bottom;
+ float dz = zfar - znear;
+
+ m[0] = 2.0 / dx;
+ m[5] = 2.0 / dy;
+ m[10] = -2.0 / dz;
+ m[12] = -(right + left) / dx;
+ m[13] = -(top + bottom) / dy;
+ m[14] = -(zfar + znear) / dz;
+
+ g3d_mult_matrix(m);
+}
+
+void g3d_frustum(float left, float right, float bottom, float top, float nr, float fr)
+{
+ float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ float dx = right - left;
+ float dy = top - bottom;
+ float dz = fr - nr;
+
+ float a = (right + left) / dx;
+ float b = (top + bottom) / dy;
+ float c = -(fr + nr) / dz;
+ float d = -2.0 * fr * nr / dz;
+
+ m[0] = 2.0 * nr / dx;
+ m[5] = 2.0 * nr / dy;
+ m[8] = a;
+ m[9] = b;
+ m[10] = c;
+ m[11] = -1.0f;
+ m[14] = d;
+
+ g3d_mult_matrix(m);
+}
+
+void g3d_perspective(float vfov_deg, float aspect, float znear, float zfar)
+{
+ float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ float vfov = M_PI * vfov_deg / 180.0f;
+ float s = 1.0f / tan(vfov * 0.5f);
+ float range = znear - zfar;
+
+ m[0] = s / aspect;
+ m[5] = s;
+ m[10] = (znear + zfar) / range;
+ m[11] = -1.0f;
+ m[14] = 2.0f * znear * zfar / range;
+
+ g3d_mult_matrix(m);
+}
+
+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)
+{
+ g3d_draw_indexed(prim, varr, varr_size, 0, 0);
+}
+
+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, fill_mode;
+ struct pvertex pv[16];
+ struct g3d_vertex v[16];
+ int mvtop = st->mtop[G3D_MODELVIEW];
+ int ptop = st->mtop[G3D_PROJECTION];
+ struct g3d_vertex *tmpv;
+
+ tmpv = alloca(prim * 6 * sizeof *tmpv);
+
+ /* calc the normal matrix */
+ 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;
+
+ nfaces = (iarr ? iarr_size : varr_size) / prim;
+
+ 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_MODELVIEW][mvtop], &v[i].x);
+ xform3_vec3(st->norm_mat, &v[i].nx);
+
+ if(st->opt & G3D_LIGHTING) {
+ shade(v + i);
+ }
+ if(st->opt & G3D_TEXTURE_GEN) {
+ v[i].u = v[i].nx * 0.5 + 0.5;
+ v[i].v = v[i].ny * 0.5 + 0.5;
+ }
+ if(st->opt & G3D_TEXTURE_MAT) {
+ float *mat = st->mat[G3D_TEXTURE][st->mtop[G3D_TEXTURE]];
+ float x = mat[0] * v[i].u + mat[4] * v[i].v + mat[12];
+ float y = mat[1] * v[i].u + mat[5] * v[i].v + mat[13];
+ float w = mat[3] * v[i].u + mat[7] * v[i].v + mat[15];
+ v[i].u = x / w;
+ v[i].v = y / w;
+ }
+ xform4_vec3(st->mat[G3D_PROJECTION][ptop], &v[i].x);
+ }
+
+ /* clipping */
+ if(st->opt & G3D_CLIP_FRUSTUM) {
+ for(i=0; i<6; i++) {
+ 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) {
+ v[i].x /= v[i].w;
+ v[i].y /= v[i].w;
+ /*v[i].z /= v[i].w;*/
+ }
+
+ /* viewport transformation */
+ 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].y = cround64(v[i].y * 256.0f);
+ /* convert tex coords to 16.16 fixed point */
+ 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;
+ pv[i].b = v[i].b;
+ pv[i].a = v[i].a;
+ }
+
+ /* backface culling */
+ if(vnum > 2 && st->opt & G3D_CULL_FACE) {
+ int32_t ax = pv[1].x - pv[0].x;
+ 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 >> 4) * (by >> 4) - (ay >> 4) * (bx >> 4);
+ int sign = (cross_z >> 31) & 1;
+
+ if(!(sign ^ st->frontface)) {
+ continue; /* back-facing */
+ }
+ }
+
+ switch(vnum) {
+ case 1:
+ if(st->opt & G3D_BLEND) {
+ int r, g, b;
+ int inv_alpha = 255 - pv[0].a;
+ uint32_t *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
+ r = ((int)pv[0].r * pv[0].a + UNPACK_R32(*dest) * inv_alpha) >> 8;
+ g = ((int)pv[0].g * pv[0].a + UNPACK_G32(*dest) * inv_alpha) >> 8;
+ b = ((int)pv[0].b * pv[0].a + UNPACK_B32(*dest) * inv_alpha) >> 8;
+ *dest++ = PACK_RGB16(r, g, b);
+ } else {
+ uint32_t *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
+ *dest = PACK_RGB32(pv[0].r, pv[0].g, pv[0].b);
+ }
+ break;
+
+ case 2:
+ {
+ uint32_t col = PACK_RGB32(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:
+ 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);
+ }
+ }
+}
+
+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];
+ float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13];
+ float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
+ float w = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
+
+ vec[0] = x;
+ vec[1] = y;
+ vec[2] = z;
+ vec[3] = w;
+}
+
+static void xform3_vec3(const float *mat, float *vec)
+{
+ float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2];
+ float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2];
+ float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2];
+
+ vec[0] = x;
+ vec[1] = y;
+ 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)
+{
+ 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;
+}
--- /dev/null
+#ifndef THREEDGFX_H_
+#define THREEDGFX_H_
+
+#include "inttypes.h"
+
+struct g3d_vertex {
+ float x, y, z, w;
+ float nx, ny, nz;
+ float u, v;
+ unsigned char r, g, b, a;
+};
+
+enum {
+ G3D_POINTS = 1,
+ G3D_LINES = 2,
+ G3D_TRIANGLES = 3,
+ G3D_QUADS = 4
+};
+
+/* g3d_enable/g3d_disable bits */
+enum {
+ G3D_CULL_FACE = 0x000001,
+ G3D_DEPTH_TEST = 0x000002, /* XXX not implemented */
+ G3D_LIGHTING = 0x000004,
+ G3D_LIGHT0 = 0x000008,
+ G3D_LIGHT1 = 0x000010,
+ G3D_LIGHT2 = 0x000020,
+ G3D_LIGHT3 = 0x000040,
+ G3D_TEXTURE_2D = 0x000080, /* XXX doesn't affect anything, use g3d_polygon_mode */
+ G3D_BLEND = 0x000100,
+ G3D_TEXTURE_GEN = 0x000200,
+ G3D_CLIP_FRUSTUM = 0x000800,/* when disabled, don't clip against the frustum */
+ G3D_CLIP_PLANE0 = 0x001000, /* user-defined 3D clipping planes XXX not impl. */
+ G3D_CLIP_PLANE1 = 0x002000,
+ G3D_CLIP_PLANE2 = 0x004000,
+ G3D_CLIP_PLANE3 = 0x008000,
+
+ G3D_TEXTURE_MAT = 0x010000,
+
+ G3D_ALL = 0x7fffffff
+};
+
+/* arg to g3d_front_face */
+enum { G3D_CCW, G3D_CW };
+
+/* arg to g3d_polygon_mode */
+enum {
+ G3D_WIRE,
+ G3D_FLAT,
+ G3D_GOURAUD
+};
+
+/* matrix stacks */
+enum {
+ G3D_MODELVIEW,
+ G3D_PROJECTION,
+ G3D_TEXTURE,
+
+ G3D_NUM_MATRICES
+};
+
+int g3d_init(void);
+void g3d_destroy(void);
+
+void g3d_framebuffer(int width, int height, void *pixels);
+void g3d_framebuffer_addr(void *pixels);
+void g3d_viewport(int x, int y, int w, int h);
+
+void g3d_enable(unsigned int opt);
+void g3d_disable(unsigned int opt);
+void g3d_setopt(unsigned int opt, unsigned int mask);
+unsigned int g3d_getopt(unsigned int mask);
+
+void g3d_front_face(unsigned int order);
+void g3d_polygon_mode(int pmode);
+
+void g3d_matrix_mode(int mmode);
+
+void g3d_load_identity(void);
+void g3d_load_matrix(const float *m);
+void g3d_mult_matrix(const float *m);
+void g3d_push_matrix(void);
+void g3d_pop_matrix(void);
+
+void g3d_translate(float x, float y, float z);
+void g3d_rotate(float angle, float x, float y, float z);
+void g3d_scale(float x, float y, float z);
+void g3d_ortho(float left, float right, float bottom, float top, float znear, float zfar);
+void g3d_frustum(float left, float right, float bottom, float top, float znear, float zfar);
+void g3d_perspective(float vfov, float aspect, float znear, float zfar);
+
+/* returns pointer to the *internal* matrix, and if argument m is not null,
+ * also copies the internal matrix there. */
+const float *g3d_get_matrix(int which, float *m);
+
+void g3d_light_pos(int idx, float x, float y, float z);
+void g3d_light_color(int idx, float r, float g, float b);
+
+void g3d_light_ambient(float r, float g, float b);
+
+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 uint16_t *iarr, int iarr_size);
+
+void g3d_begin(int prim);
+void g3d_end(void);
+void g3d_vertex(float x, float y, float z);
+void g3d_normal(float x, float y, float z);
+void g3d_color3b(unsigned char r, unsigned char g, unsigned char b);
+void g3d_color4b(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+void g3d_color3f(float r, float g, float b);
+void g3d_color4f(float r, float g, float b, float a);
+void g3d_texcoord(float u, float v);
+
+#endif /* THREEDGFX_H_ */
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include "census.h"
+#include "3dgfx.h"
+#include "panic.h"
+
+void init_census(void *pixels, int xsz, int ysz)
+{
+ fb_pixels = pixels;
+ fb_width = xsz;
+ fb_height = ysz;
+
+ g3d_init();
+ g3d_framebuffer(xsz, ysz, fb_pixels);
+ g3d_polygon_mode(G3D_FLAT);
+ g3d_viewport(0, 0, xsz, ysz);
+}
+
+void draw_census(void)
+{
+ int i;
+ memset(fb_pixels, 0, fb_width * fb_height * 4);
+
+ g3d_matrix_mode(G3D_MODELVIEW);
+ g3d_load_identity();
+
+ g3d_enable(G3D_BLEND);
+
+ g3d_color4b(64, 128, 255, 255);
+ for(i=0; i<2; i++) {
+ g3d_begin(G3D_QUADS);
+ g3d_vertex(-0.4, -0.5, 0);
+ g3d_vertex(0.6, -0.2, 0);
+ g3d_vertex(0, 0.8, 0);
+ g3d_vertex(-0.5, 0.6, 0);
+ g3d_end();
+
+ g3d_translate(0.2, -0.2, 0);
+ g3d_color4b(255, 32, 255, 128);
+ }
+
+ g3d_disable(G3D_BLEND);
+}
--- /dev/null
+#ifndef CENSUS_H_
+#define CENSUS_H_
+
+#include <inttypes.h>
+
+int fb_width, fb_height;
+uint32_t *fb_pixels;
+
+void init_census(void *pixels, int xsz, int ysz);
+void draw_census(void);
+
+#endif /* CENSUS_H_ */
--- /dev/null
+#include "gfxutil.h"
+#include "census.h"
+
+enum {
+ IN = 0,
+ LEFT = 1,
+ RIGHT = 2,
+ TOP = 4,
+ BOTTOM = 8
+};
+
+static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax)
+{
+ int code = 0;
+
+ if(x < xmin) {
+ code |= LEFT;
+ } else if(x > xmax) {
+ code |= RIGHT;
+ }
+ if(y < ymin) {
+ code |= TOP;
+ } else if(y > ymax) {
+ code |= BOTTOM;
+ }
+ return code;
+}
+
+#define FIXMUL(a, b) (((a) * (b)) >> 8)
+#define FIXDIV(a, b) (((a) << 8) / (b))
+
+#define LERP(a, b, t) ((a) + FIXMUL((b) - (a), (t)))
+
+int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax)
+{
+ int oc_out;
+
+ int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax);
+ int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax);
+
+ long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax;
+
+ if(!(oc0 | oc1)) return 1; /* both points are inside */
+
+ fx0 = *x0 << 8;
+ fy0 = *y0 << 8;
+ fx1 = *x1 << 8;
+ fy1 = *y1 << 8;
+ fxmin = xmin << 8;
+ fymin = ymin << 8;
+ fxmax = xmax << 8;
+ fymax = ymax << 8;
+
+ for(;;) {
+ long x, y, t;
+
+ if(oc0 & oc1) return 0; /* both have points with the same outbit, not visible */
+ if(!(oc0 | oc1)) break; /* both points are inside */
+
+ oc_out = oc0 ? oc0 : oc1;
+
+ if(oc_out & TOP) {
+ t = FIXDIV(fymin - fy0, fy1 - fy0);
+ x = LERP(fx0, fx1, t);
+ y = fymin;
+ } else if(oc_out & BOTTOM) {
+ t = FIXDIV(fymax - fy0, fy1 - fy0);
+ x = LERP(fx0, fx1, t);
+ y = fymax;
+ } else if(oc_out & LEFT) {
+ t = FIXDIV(fxmin - fx0, fx1 - fx0);
+ x = fxmin;
+ y = LERP(fy0, fy1, t);
+ } else if(oc_out & RIGHT) {
+ t = FIXDIV(fxmax - fx0, fx1 - fx0);
+ x = fxmax;
+ y = LERP(fy0, fy1, t);
+ }
+
+ if(oc_out == oc0) {
+ fx0 = x;
+ fy0 = y;
+ oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax);
+ } else {
+ fx1 = x;
+ fy1 = y;
+ oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax);
+ }
+ }
+
+ *x0 = fx0 >> 8;
+ *y0 = fy0 >> 8;
+ *x1 = fx1 >> 8;
+ *y1 = fy1 >> 8;
+ return 1;
+}
+
+void draw_line(int x0, int y0, int x1, int y1, uint32_t color)
+{
+ int i, dx, dy, x_inc, y_inc, error;
+ uint32_t *fb = fb_pixels;
+
+ fb += y0 * fb_width + x0;
+
+ dx = x1 - x0;
+ dy = y1 - y0;
+
+ if(dx >= 0) {
+ x_inc = 1;
+ } else {
+ x_inc = -1;
+ dx = -dx;
+ }
+ if(dy >= 0) {
+ y_inc = fb_width;
+ } else {
+ y_inc = -fb_width;
+ dy = -dy;
+ }
+
+ if(dx > dy) {
+ error = dy * 2 - dx;
+ for(i=0; i<=dx; i++) {
+ *fb = color;
+ if(error >= 0) {
+ error -= dx * 2;
+ fb += y_inc;
+ }
+ error += dy * 2;
+ fb += x_inc;
+ }
+ } else {
+ error = dx * 2 - dy;
+ for(i=0; i<=dy; i++) {
+ *fb = color;
+ if(error >= 0) {
+ error -= dy * 2;
+ fb += x_inc;
+ }
+ error += dx * 2;
+ fb += y_inc;
+ }
+ }
+}
+
+
+#define BLUR(w, h, pstep, sstep) \
+ for(i=0; i<h; i++) { \
+ int sum = sptr[0] * (rad + 1); \
+ int count = (rad * 2 + 1) << 8; \
+ int midsize = w - rad * 2; \
+ int firstpix = sptr[0]; \
+ int lastpix = sptr[pstep * (w - 1)]; \
+ /* add up the contributions for the -1 pixel */ \
+ for(j=0; j<rad; j++) { \
+ sum += sptr[pstep * j]; \
+ } \
+ /* first part adding sptr[rad] and subtracting sptr[0] */ \
+ for(j=0; j<=rad; j++) { \
+ sum += (int)sptr[pstep * rad] - firstpix; \
+ sptr += pstep; \
+ *dptr = scale * sum / count; \
+ dptr += pstep; \
+ } \
+ /* middle part adding sptr[rad] and subtracting sptr[-(rad+1)] */ \
+ for(j=1; j<midsize; j++) { \
+ sum += (int)sptr[pstep * rad] - (int)sptr[-(rad + 1) * pstep]; \
+ sptr += pstep; \
+ *dptr = scale * sum / count; \
+ dptr += pstep; \
+ } \
+ /* last part adding lastpix and subtracting sptr[-(rad+1)] */ \
+ for(j=0; j<rad; j++) { \
+ sum += lastpix - (int)sptr[-(rad + 1) * pstep]; \
+ sptr += pstep; \
+ *dptr = scale * sum / count; \
+ dptr += pstep; \
+ } \
+ sptr += sstep; \
+ dptr += sstep; \
+ }
+
+/* TODO bound blur rad to image size to avoid inner loop conditionals */
+/* TODO make version with pow2 (rad*2+1) to avoid div with count everywhere */
+void blur_grey_horiz(uint32_t *dest, uint32_t *src, int xsz, int ysz, int rad, int scale)
+{
+ int i, j;
+ unsigned char *dptr = (unsigned char*)dest;
+ unsigned char *sptr = (unsigned char*)src;
+
+ BLUR(xsz, ysz, 2, 0);
+}
+
+
+void blur_grey_vert(uint32_t *dest, uint32_t *src, int xsz, int ysz, int rad, int scale)
+{
+ int i, j;
+ unsigned char *dptr = (unsigned char*)dest;
+ unsigned char *sptr = (unsigned char*)src;
+ int pixel_step = xsz * 2;
+ int scanline_step = 2 - ysz * pixel_step;
+
+ BLUR(ysz, xsz, pixel_step, scanline_step);
+}
+
+void convimg_rgb24_rgb16(uint16_t *dest, unsigned char *src, int xsz, int ysz)
+{
+ int i;
+ int npixels = xsz * ysz;
+
+ for(i=0; i<npixels; i++) {
+ int r = *src++;
+ int g = *src++;
+ int b = *src++;
+ *dest++ = PACK_RGB16(r, g, b);
+ }
+}
--- /dev/null
+#ifndef GFXUTIL_H_
+#define GFXUTIL_H_
+
+#include "inttypes.h"
+
+#define PACK_RGB16(r, g, b) \
+ ((((uint16_t)(r) << 8) & 0xf800) | \
+ (((uint16_t)(g) << 3) & 0x7e0) | \
+ (((uint16_t)(b) >> 3) & 0x1f))
+
+#define UNPACK_R16(c) (((c) >> 8) & 0xf8)
+#define UNPACK_G16(c) (((c) >> 3) & 0xfc)
+#define UNPACK_B16(c) (((c) << 3) & 0xf8)
+
+#define PACK_RGB32(r, g, b) \
+ ((((uint32_t)(r) & 0xff) << 16) | \
+ (((uint32_t)(g) & 0xff) << 8) | \
+ ((uint32_t)(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, uint32_t color);
+
+/* scale in 24.8 fixed point */
+void blur_grey_horiz(uint32_t *dest, uint32_t *src, int xsz, int ysz, int radius, int scale);
+void blur_grey_vert(uint32_t *dest, uint32_t *src, int xsz, int ysz, int radius, int scale);
+
+void convimg_rgb24_rgb16(uint16_t *dest, unsigned char *src, int xsz, int ysz);
+
+#endif /* GFXUTIL_H_ */
--- /dev/null
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+#include "polyclip.h"
+
+struct ray {
+ float origin[3];
+ float dir[3];
+};
+
+static int clip_edge(struct g3d_vertex *poly, int *vnumptr,
+ const struct g3d_vertex *v0, const struct g3d_vertex *v1,
+ const struct cplane *plane);
+static int check_clip_edge(const struct g3d_vertex *v0,
+ const struct g3d_vertex *v1, const struct cplane *plane);
+static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr,
+ const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane);
+static float distance_signed(float *pos, const struct cplane *plane);
+static int intersect(const struct ray *ray, const struct cplane *plane, float *t);
+static int inside_frustum_plane(const struct g3d_vertex *v, int fplane);
+
+
+int clip_poly(struct g3d_vertex *vout, int *voutnum,
+ const struct g3d_vertex *vin, int vnum, struct cplane *plane)
+{
+ int i, nextidx, res;
+ int edges_clipped = 0;
+
+ *voutnum = 0;
+
+ for(i=0; i<vnum; i++) {
+ nextidx = i + 1;
+ if(nextidx >= vnum) nextidx = 0;
+ res = clip_edge(vout, voutnum, vin + i, vin + nextidx, plane);
+ if(res == 0) {
+ ++edges_clipped;
+ }
+ }
+
+ if(*voutnum <= 0) {
+ assert(edges_clipped == 0);
+ return -1;
+ }
+
+ return edges_clipped > 0 ? 0 : 1;
+}
+
+int check_clip_poly(const struct g3d_vertex *v, int vnum, struct cplane *plane)
+{
+ int i, nextidx, res;
+ int edges_clipped = 0;
+
+ for(i=0; i<vnum; i++) {
+ nextidx = i + 1;
+ if(nextidx >= vnum) nextidx = 0;
+ res = check_clip_edge(v + i, v + nextidx, plane);
+ if(res == 0) {
+ ++edges_clipped;
+ }
+ }
+ return edges_clipped ? 0 : res;
+}
+
+int clip_frustum(struct g3d_vertex *vout, int *voutnum,
+ const struct g3d_vertex *vin, int vnum, int fplane)
+{
+ int i, nextidx, res;
+ int edges_clipped = 0;
+
+ if(vnum == 1) {
+ /* special case: point clipping */
+ return inside_frustum_plane(vin, fplane) ? 1 : -1;
+ }
+
+ *voutnum = 0;
+
+ for(i=0; i<vnum; i++) {
+ nextidx = i + 1;
+ if(nextidx >= vnum) nextidx = 0;
+ res = clip_edge_frustum(vout, voutnum, vin + i, vin + nextidx, fplane);
+ if(res == 0) {
+ ++edges_clipped;
+ }
+ }
+
+ if(*voutnum <= 0) {
+ assert(edges_clipped == 0);
+ return -1;
+ }
+
+ return edges_clipped > 0 ? 0 : 1;
+}
+
+#define LERP_VATTR(res, v0, v1, t) \
+ do { \
+ (res)->nx = (v0)->nx + ((v1)->nx - (v0)->nx) * (t); \
+ (res)->ny = (v0)->ny + ((v1)->ny - (v0)->ny) * (t); \
+ (res)->nz = (v0)->nz + ((v1)->nz - (v0)->nz) * (t); \
+ (res)->u = (v0)->u + ((v1)->u - (v0)->u) * (t); \
+ (res)->v = (v0)->v + ((v1)->v - (v0)->v) * (t); \
+ (res)->r = (v0)->r + ((v1)->r - (v0)->r) * (t); \
+ (res)->g = (v0)->g + ((v1)->g - (v0)->g) * (t); \
+ (res)->b = (v0)->b + ((v1)->b - (v0)->b) * (t); \
+ } while(0)
+
+
+/* returns:
+ * 1 -> both inside
+ * 0 -> straddling and clipped
+ * -1 -> both outside
+ *
+ * also returns the size of the polygon through vnumptr
+ */
+static int clip_edge(struct g3d_vertex *poly, int *vnumptr,
+ const struct g3d_vertex *v0, const struct g3d_vertex *v1,
+ const struct cplane *plane)
+{
+ float pos0[3], pos1[3];
+ float d0, d1, t;
+ struct ray ray;
+ int i, vnum = *vnumptr;
+
+ pos0[0] = v0->x; pos0[1] = v0->y; pos0[2] = v0->z;
+ pos1[0] = v1->x; pos1[1] = v1->y; pos1[2] = v1->z;
+
+ d0 = distance_signed(pos0, plane);
+ d1 = distance_signed(pos1, plane);
+
+ for(i=0; i<3; i++) {
+ ray.origin[i] = pos0[i];
+ ray.dir[i] = pos1[i] - pos0[i];
+ }
+
+ if(d0 >= 0.0) {
+ /* start inside */
+ if(d1 >= 0.0) {
+ /* all inside */
+ poly[vnum++] = *v1; /* append v1 */
+ *vnumptr = vnum;
+ return 1;
+ } else {
+ /* going out */
+ struct g3d_vertex *vptr = poly + vnum;
+
+ intersect(&ray, plane, &t);
+
+ vptr->x = ray.origin[0] + ray.dir[0] * t;
+ vptr->y = ray.origin[1] + ray.dir[1] * t;
+ vptr->z = ray.origin[2] + ray.dir[2] * t;
+ vptr->w = 1.0f;
+
+ LERP_VATTR(vptr, v0, v1, t);
+ vnum++; /* append new vertex on the intersection point */
+ }
+ } else {
+ /* start outside */
+ if(d1 >= 0) {
+ /* going in */
+ struct g3d_vertex *vptr = poly + vnum;
+
+ intersect(&ray, plane, &t);
+
+ vptr->x = ray.origin[0] + ray.dir[0] * t;
+ vptr->y = ray.origin[1] + ray.dir[1] * t;
+ vptr->z = ray.origin[2] + ray.dir[2] * t;
+ vptr->w = 1.0f;
+
+ LERP_VATTR(vptr, v0, v1, t);
+ vnum++; /* append new vertex on the intersection point */
+
+ /* then append v1 ... */
+ poly[vnum++] = *v1;
+ } else {
+ /* all outside */
+ return -1;
+ }
+ }
+
+ *vnumptr = vnum;
+ return 0;
+}
+
+/* same as above, but only checks for clipping and classifies the edge */
+static int check_clip_edge(const struct g3d_vertex *v0,
+ const struct g3d_vertex *v1, const struct cplane *plane)
+{
+ float pos0[3], pos1[3];
+ float d0, d1;
+
+ pos0[0] = v0->x; pos0[1] = v0->y; pos0[2] = v0->z;
+ pos1[0] = v1->x; pos1[1] = v1->y; pos1[2] = v1->z;
+
+ d0 = distance_signed(pos0, plane);
+ d1 = distance_signed(pos1, plane);
+
+ if(d0 > 0.0f && d1 > 0.0f) {
+ return 1;
+ }
+ if(d0 < 0.0f && d1 < 0.0f) {
+ return -1;
+ }
+ return 0;
+}
+
+static float distance_signed(float *pos, const struct cplane *plane)
+{
+ float dx = pos[0] - plane->x;
+ float dy = pos[1] - plane->y;
+ float dz = pos[2] - plane->z;
+ return dx * plane->nx + dy * plane->ny + dz * plane->nz;
+}
+
+static int intersect(const struct ray *ray, const struct cplane *plane, float *t)
+{
+ float orig_pt_dir[3];
+
+ float ndotdir = plane->nx * ray->dir[0] + plane->ny * ray->dir[1] + plane->nz * ray->dir[2];
+ if(fabs(ndotdir) < 1e-6) {
+ *t = 0.0f;
+ return 0;
+ }
+
+ orig_pt_dir[0] = plane->x - ray->origin[0];
+ orig_pt_dir[1] = plane->y - ray->origin[1];
+ orig_pt_dir[2] = plane->z - ray->origin[2];
+
+ *t = (plane->nx * orig_pt_dir[0] + plane->ny * orig_pt_dir[1] + plane->nz * orig_pt_dir[2]) / ndotdir;
+ return 1;
+}
+
+/* homogeneous frustum clipper helpers */
+
+static int inside_frustum_plane(const struct g3d_vertex *v, int fplane)
+{
+ switch(fplane) {
+ case CLIP_LEFT:
+ return v->x >= -v->w;
+ case CLIP_RIGHT:
+ return v->x <= v->w;
+ case CLIP_BOTTOM:
+ return v->y >= -v->w;
+ case CLIP_TOP:
+ return v->y <= v->w;
+ case CLIP_NEAR:
+ return v->z >= -v->w;
+ case CLIP_FAR:
+ return v->z <= v->w;
+ }
+ assert(0);
+ return 0;
+}
+
+static float intersect_frustum(const struct g3d_vertex *a, const struct g3d_vertex *b, int fplane)
+{
+ switch(fplane) {
+ case CLIP_LEFT:
+ return (-a->w - a->x) / (b->x - a->x + b->w - a->w);
+ case CLIP_RIGHT:
+ return (a->w - a->x) / (b->x - a->x - b->w + a->w);
+ case CLIP_BOTTOM:
+ return (-a->w - a->y) / (b->y - a->y + b->w - a->w);
+ case CLIP_TOP:
+ return (a->w - a->y) / (b->y - a->y - b->w + a->w);
+ case CLIP_NEAR:
+ return (-a->w - a->z) / (b->z - a->z + b->w - a->w);
+ case CLIP_FAR:
+ return (a->w - a->z) / (b->z - a->z - b->w + a->w);
+ }
+
+ assert(0);
+ return 0;
+}
+
+static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr,
+ const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane)
+{
+ int vnum = *vnumptr;
+ int in0, in1;
+ float t;
+
+ in0 = inside_frustum_plane(v0, fplane);
+ in1 = inside_frustum_plane(v1, fplane);
+
+ if(in0) {
+ /* start inside */
+ if(in1) {
+ /* all inside */
+ poly[vnum++] = *v1; /* append v1 */
+ *vnumptr = vnum;
+ return 1;
+ } else {
+ /* going out */
+ struct g3d_vertex *vptr = poly + vnum;
+
+ t = intersect_frustum(v0, v1, fplane);
+
+ vptr->x = v0->x + (v1->x - v0->x) * t;
+ vptr->y = v0->y + (v1->y - v0->y) * t;
+ vptr->z = v0->z + (v1->z - v0->z) * t;
+ vptr->w = v0->w + (v1->w - v0->w) * t;
+
+ LERP_VATTR(vptr, v0, v1, t);
+ ++vnum; /* append new vertex on the intersection point */
+ }
+ } else {
+ /* start outside */
+ if(in1) {
+ /* going in */
+ struct g3d_vertex *vptr = poly + vnum;
+
+ t = intersect_frustum(v0, v1, fplane);
+
+ vptr->x = v0->x + (v1->x - v0->x) * t;
+ vptr->y = v0->y + (v1->y - v0->y) * t;
+ vptr->z = v0->z + (v1->z - v0->z) * t;
+ vptr->w = v0->w + (v1->w - v0->w) * t;
+
+ LERP_VATTR(vptr, v0, v1, t);
+ ++vnum; /* append new vertex on the intersection point */
+
+ /* then append v1 ... */
+ poly[vnum++] = *v1;
+ } else {
+ /* all outside */
+ return -1;
+ }
+ }
+
+ *vnumptr = vnum;
+ return 0;
+}
--- /dev/null
+#ifndef POLYCLIP_H_
+#define POLYCLIP_H_
+
+#include "3dgfx.h"
+
+struct cplane {
+ float x, y, z;
+ float nx, ny, nz;
+};
+
+enum {
+ CLIP_LEFT, CLIP_RIGHT,
+ CLIP_BOTTOM, CLIP_TOP,
+ CLIP_NEAR, CLIP_FAR
+};
+
+/* Generic polygon clipper
+ * returns:
+ * 1 -> fully inside, not clipped
+ * 0 -> straddling the plane and clipped
+ * -1 -> fully outside, not clipped
+ * in all cases, vertices are copied to vout, and the vertex count is written
+ * to wherever voutnum is pointing
+ */
+int clip_poly(struct g3d_vertex *vout, int *voutnum,
+ const struct g3d_vertex *vin, int vnum, struct cplane *plane);
+
+/* only checks if the polygon would be clipped by the plane, and classifies it
+ * as inside/outside/straddling, without actually producing a clipped polygon.
+ * return values are the same as clip_poly.
+ */
+int check_clip_poly(const struct g3d_vertex *v, int vnum, struct cplane *plane);
+
+/* Special-case frustum clipper (might be slightly faster) */
+int clip_frustum(struct g3d_vertex *vout, int *voutnum,
+ const struct g3d_vertex *vin, int vnum, int fplane);
+
+#endif /* POLYCLIP_H_ */
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+#include "polyfill.h"
+#include "gfxutil.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,
+ 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(int mode, struct pvertex *verts, int nverts)
+{
+#ifndef NDEBUG
+ if(!fillfunc[mode]) {
+ fprintf(stderr, "polyfill mode %d not implemented\n", mode);
+ abort();
+ }
+#endif
+
+ fillfunc[mode](verts, nverts);
+}
+
+void polyfill_wire(struct pvertex *verts, int nverts)
+{
+ int i, x0, y0, x1, y1;
+ struct pvertex *v = verts;
+ unsigned short color = ((v->r << 8) & 0xf800) |
+ ((v->g << 3) & 0x7e0) | ((v->b >> 3) & 0x1f);
+
+ for(i=0; i<nverts - 1; i++) {
+ x0 = v->x >> 8;
+ y0 = v->y >> 8;
+ ++v;
+ x1 = v->x >> 8;
+ y1 = v->y >> 8;
+ 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, pfill_fb.width, pfill_fb.height)) {
+ draw_line(x1, y1, x0, y0, color);
+ }
+}
+
+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)
+
+/* XXX
+ * When HIGH_QUALITY is defined, the rasterizer calculates slopes for attribute
+ * interpolation on each scanline separately; otherwise the slope for each
+ * attribute would be calculated once for the whole polygon, which is faster,
+ * but produces some slight quantization artifacts, due to the limited precision
+ * of fixed-point calculations.
+ */
+#define HIGH_QUALITY
+
+/* extra bits of precision to use when interpolating colors.
+ * try tweaking this if you notice strange quantization artifacts.
+ */
+#define COLOR_SHIFT 12
+
+
+#define POLYFILL polyfill_flat
+#define SCANEDGE scanedge_flat
+#undef GOURAUD
+#undef TEXMAP
+#undef BLEND
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_gouraud
+#define SCANEDGE scanedge_gouraud
+#define GOURAUD
+#undef TEXMAP
+#undef BLEND
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_tex_flat
+#define SCANEDGE scanedge_tex_flat
+#undef GOURAUD
+#define TEXMAP
+#undef BLEND
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_tex_gouraud
+#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
--- /dev/null
+#ifndef POLYFILL_H_
+#define POLYFILL_H_
+
+#include "inttypes.h"
+
+#define POLYFILL_MODE_MASK 0x03
+#define POLYFILL_TEX_BIT 0x04
+#define POLYFILL_BLEND_BIT 0x08
+
+enum {
+ POLYFILL_WIRE = 0,
+ POLYFILL_FLAT,
+ POLYFILL_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 pvertex {
+ int32_t x, y; /* 24.8 fixed point */
+ int32_t u, v; /* 16.16 fixed point */
+ int32_t r, g, b, a; /* int 0-255 */
+};
+
+struct pimage {
+ uint32_t *pixels;
+ int width, height;
+
+ int xshift, yshift;
+ unsigned int xmask, ymask;
+};
+
+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);
+void polyfill_flat(struct pvertex *verts, int nverts);
+void polyfill_gouraud(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_ */
--- /dev/null
+static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge)
+{
+ int i;
+ int32_t x, dx, dy, slope;
+#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
+ int32_t start_idx, end_idx;
+
+ if(v0->y > v1->y) {
+ struct pvertex *tmp = v0;
+ v0 = v1;
+ v1 = tmp;
+ }
+
+ x = v0->x;
+ dy = v1->y - v0->y;
+ dx = v1->x - v0->x;
+ slope = (dx << 8) / dy;
+#ifdef GOURAUD
+ r = (v0->r << COLOR_SHIFT);
+ g = (v0->g << COLOR_SHIFT);
+ b = (v0->b << COLOR_SHIFT);
+ dr = (v1->r << COLOR_SHIFT) - r;
+ dg = (v1->g << COLOR_SHIFT) - g;
+ db = (v1->b << COLOR_SHIFT) - b;
+ rslope = (dr << 8) / dy;
+ gslope = (dg << 8) / dy;
+ bslope = (db << 8) / dy;
+#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;
+ du = v1->u - v0->u;
+ dv = v1->v - v0->v;
+ uslope = (du << 8) / dy;
+ vslope = (dv << 8) / dy;
+#endif
+
+ start_idx = v0->y >> 8;
+ end_idx = v1->y >> 8;
+
+ for(i=start_idx; i<end_idx; i++) {
+ edge[i].x = x;
+ x += slope;
+#ifdef GOURAUD
+ /* we'll store the color in the edge tables with COLOR_SHIFT extra bits of precision */
+ edge[i].r = r;
+ edge[i].g = g;
+ edge[i].b = b;
+ 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;
+ u += uslope;
+ v += vslope;
+#endif
+ }
+
+ return (uint32_t)start_idx | ((uint32_t)(end_idx - 1) << 16);
+}
+
+void POLYFILL(struct pvertex *pv, int nverts)
+{
+ int i, winding;
+ int topidx = 0, botidx = 0, sltop = pfill_fb.height, slbot = 0;
+ struct pvertex *left, *right;
+ uint32_t 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_RGB32(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;
+#endif
+
+ for(i=1; i<nverts; i++) {
+ if(pv[i].y < pv[topidx].y) topidx = i;
+ if(pv[i].y > pv[botidx].y) botidx = i;
+ }
+
+ winding = 0;
+ for(i=0; i<nverts; i++) {
+ int next = NEXTIDX(i);
+ winding += ((pv[next].x - pv[i].x) >> 4) * ((pv[next].y + pv[i].y) >> 4);
+ }
+
+ /* +1 to avoid crashing due to off-by-one rounding errors in the rasterization */
+ left = alloca((pfill_fb.height + 1) * sizeof *left);
+ right = alloca((pfill_fb.height + 1) * sizeof *right);
+
+ for(i=0; i<nverts; i++) {
+ int next = NEXTIDX(i);
+ int32_t y0 = pv[i].y;
+ int32_t y1 = pv[next].y;
+
+ if((y0 >> 8) == (y1 >> 8)) {
+ /*if(y0 > y1) {*/
+ int i0, i1;
+ int idx = y0 >> 8;
+ if(pv[i].x < pv[next].x) {
+ i0 = i;
+ i1 = next;
+ } else {
+ i0 = next;
+ i1 = i;
+ }
+ left[idx].x = pv[i0].x;
+ right[idx].x = pv[i1].x;
+#ifdef GOURAUD
+ left[idx].r = pv[i0].r << COLOR_SHIFT;
+ left[idx].g = pv[i0].g << COLOR_SHIFT;
+ left[idx].b = pv[i0].b << COLOR_SHIFT;
+ 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;
+ left[idx].v = pv[i0].v;
+ right[idx].u = pv[i1].u;
+ right[idx].v = pv[i1].v;
+#endif
+ if(idx > slbot) slbot = idx;
+ if(idx < sltop) sltop = idx;
+ /*}*/
+ } else {
+ struct pvertex *edge;
+ uint32_t res, tmp;
+
+ if(winding < 0) {
+ // clockwise
+ edge = y0 > y1 ? left : right;
+ } else {
+ // counter-clockwise
+ edge = y0 > y1 ? right : left;
+ }
+ res = SCANEDGE(pv + i, pv + next, edge);
+ tmp = (res >> 16) & 0xffff;
+ if(tmp > slbot) slbot = tmp;
+ if((tmp = res & 0xffff) < sltop) {
+ sltop = tmp;
+ }
+ }
+ }
+
+ /* calculate the slopes of all attributes across the largest span out
+ * of the three: middle, top, or bottom.
+ */
+#ifndef HIGH_QUALITY
+#if defined(GOURAUD) || defined(TEXMAP)
+ mid = (sltop + slbot) >> 1;
+ dx = right[mid].x - left[mid].x;
+ if((tmp = right[sltop].x - left[sltop].x) > dx) {
+ dx = tmp;
+ mid = sltop;
+ }
+ if((tmp = right[slbot].x - left[slbot].x) > dx) {
+ dx = tmp;
+ mid = slbot;
+ }
+ if(!dx) dx = 256; /* avoid division by zero */
+#endif
+#ifdef GOURAUD
+ dr = right[mid].r - left[mid].r;
+ dg = right[mid].g - left[mid].g;
+ db = right[mid].b - left[mid].b;
+ 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;
+ dv = right[mid].v - left[mid].v;
+ uslope = (du << 8) / dx;
+ vslope = (dv << 8) / dx;
+#endif
+#endif /* !defined(HIGH_QUALITY) */
+
+ /* for each scanline ... */
+ for(i=sltop; i<=slbot; i++) {
+ uint32_t *pixptr;
+ int32_t x;
+
+ x = left[i].x;
+ pixptr = pfill_fb.pixels + i * pfill_fb.width + (x >> 8);
+
+#ifdef GOURAUD
+ 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;
+ v = left[i].v;
+#endif
+
+#if defined(HIGH_QUALITY) && (defined(GOURAUD) || defined(TEXMAP))
+ if(!(dx = right[i].x - left[i].x)) dx = 256;
+
+#ifdef GOURAUD
+ dr = right[i].r - left[i].r;
+ dg = right[i].g - left[i].g;
+ db = right[i].b - left[i].b;
+ rslope = (dr << 8) / dx;
+ gslope = (dg << 8) / dx;
+ bslope = (db << 8) / dx;
+#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;
+ uslope = (du << 8) / dx;
+ vslope = (dv << 8) / dx;
+#endif
+#endif /* HIGH_QUALITY */
+
+ /* go across the scanline interpolating if necessary */
+ while(x <= right[i].x) {
+#if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND)
+ int cr, cg, cb;
+#endif
+#ifdef BLEND
+ uint32_t 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);
+ r += rslope;
+ g += gslope;
+ b += bslope;
+#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;
+ uint32_t 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_R32(texel)) >> 8;
+ cg = (cg * UNPACK_G32(texel)) >> 8;
+ cb = (cb * UNPACK_B32(texel)) >> 8;
+#else
+ cr = UNPACK_R32(texel);
+ cg = UNPACK_G32(texel);
+ cb = UNPACK_B32(texel);
+#endif
+ }
+ u += uslope;
+ v += vslope;
+#endif
+
+#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 + UNPACK_R32(fbcol) * inv_alpha) >> 8;
+ cg = (cg * alpha + UNPACK_G32(fbcol) * inv_alpha) >> 8;
+ cb = (cb * alpha + UNPACK_B32(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 = PACK_RGB32(cr, cg, cb);
+#endif
+
+#ifdef DEBUG_OVERDRAW
+ *pixptr++ += DEBUG_OVERDRAW;
+#else
+ *pixptr++ = color;
+#endif
+ x += 256;
+ }
+ }
+}
+
--- /dev/null
+#include "util.h"
+
+uint32_t perf_start_count, perf_interval_count;
--- /dev/null
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include "inttypes.h"
+
+#ifdef __GNUC__
+#define INLINE __inline
+
+#elif defined(__WATCOMC__)
+#define INLINE __inline
+
+#else
+#define INLINE
+#endif
+
+/* fast conversion of double -> 32bit int
+ * for details see:
+ * - http://chrishecker.com/images/f/fb/Gdmfp.pdf
+ * - http://stereopsis.com/FPU.html#convert
+ */
+static INLINE int32_t cround64(double val)
+{
+ val += 6755399441055744.0;
+ return *(int32_t*)&val;
+}
+
+extern uint32_t perf_start_count, perf_interval_count;
+
+#ifdef __WATCOMC__
+void perf_start(void);
+#pragma aux perf_start = \
+ "xor eax, eax" \
+ "cpuid" \
+ "rdtsc" \
+ "mov [perf_start_count], eax" \
+ modify[eax ebx ecx edx];
+
+void perf_end(void);
+#pragma aux perf_end = \
+ "xor eax, eax" \
+ "cpuid" \
+ "rdtsc" \
+ "sub eax, [perf_start_count]" \
+ "mov [perf_interval_count], eax" \
+ modify [eax ebx ecx edx];
+
+void debug_break(void);
+#pragma aux debug_break = "int 3";
+#endif
+
+#ifdef __GNUC__
+#define perf_start() asm volatile ( \
+ "xor %%eax, %%eax\n" \
+ "cpuid\n" \
+ "rdtsc\n" \
+ "mov %%eax, %0\n" \
+ : "=m"(perf_start_count) \
+ :: "%eax", "%ebx", "%ecx", "%edx")
+
+#define perf_end() asm volatile ( \
+ "xor %%eax, %%eax\n" \
+ "cpuid\n" \
+ "rdtsc\n" \
+ "sub %1, %%eax\n" \
+ "mov %%eax, %0\n" \
+ : "=m"(perf_interval_count) \
+ : "m"(perf_start_count) \
+ : "%eax", "%ebx", "%ecx", "%edx")
+
+#define debug_break() \
+ asm volatile ("int $3")
+#endif
+
+#ifdef _MSC_VER
+#define perf_start() \
+ do { \
+ __asm { \
+ xor eax, eax \
+ cpuid \
+ rdtsc \
+ mov [perf_start_count], eax \
+ } \
+ } while(0)
+
+#define perf_end() \
+ do { \
+ __asm { \
+ xor eax, eax \
+ cpuid \
+ rdtsc \
+ sub eax, [perf_start_count] \
+ mov [perf_interval_count], eax \
+ } \
+ } while(0)
+
+#define debug_break() \
+ do { \
+ __asm { int 3 } \
+ } while(0)
+#endif
+
+#endif /* UTIL_H_ */
#include "vbe.h"
#include "audio.h"
#include "panic.h"
+#include "census/census.h"
static int video_init(void);
static int modecmp(const void *a, const void *b);
static struct video_mode vmode;
-static void *fbptr;
+static void *fbptr, *backbuf;
+static int fbsize;
void pcboot_main(void)
if(video_init() == -1) {
panic("Failed to find suitable video mode");
}
+ fbsize = vmode.width * vmode.height * vmode.bpp / 8;
+ if(!(backbuf = malloc(fbsize))) {
+ panic("Failed to allocate back buffer");
+ }
+ init_census(backbuf, vmode.width, vmode.height);
for(;;) {
+ draw_census();
+
wait_vsync();
- memset(fbptr, 0x80, vmode.width * vmode.height * vmode.bpp / 8);
+ memcpy(fbptr, backbuf, fbsize);
}
}
const char *vendor;
if(mode_idx == -1 && (vendor = get_video_vendor()) && strstr(vendor, "SeaBIOS")) {
- mode_idx = find_video_mode_idx(800, 600, 0);
+ mode_idx = find_video_mode_idx(800, 600, 32);
}
if(mode_idx == -1 && vbe_get_edid(&edid) == 0 && edid_preferred_resolution(&edid, &xres, &yres) == 0) {