static int32_t cam_theta = 0x10000, cam_phi = -0x8000;
+static int show_obj = 1, show_del;
+
+#define AXIS0 0x10000
+#define AXIS1 0x80000
+
+static struct xvertex gridaxes[] = {
+ {AXIS0, 0, 0, 0, 0, 0, 92},
+ {AXIS1, 0, 0, 0, 0, 0, 92},
+ {-AXIS0, 0, 0, 0, 0, 0, 92},
+ {-AXIS1, 0, 0, 0, 0, 0, 92},
+ {0, 0, AXIS0, 0, 0, 0, 93},
+ {0, 0, AXIS1, 0, 0, 0, 93},
+ {0, 0, -AXIS0, 0, 0, 0, 93},
+ {0, 0, -AXIS1, 0, 0, 0, 93},
+
+ {0, 0, 0, 0, 0, 0, 92},
+ {AXIS1, 0, 0, 0, 0, 0, 92},
+ {0, 0, 0, 0, 0, 0, 92},
+ {-AXIS1, 0, 0, 0, 0, 0, 92},
+ {0, 0, 0, 0, 0, 0, 93},
+ {0, 0, AXIS1, 0, 0, 0, 93},
+ {0, 0, -0, 0, 0, 0, 93},
+ {0, 0, -AXIS1, 0, 0, 0, 93},
+};
+
int main(void)
{
int i;
xgl_translate(0, 0, 8 << 16);
xgl_rotate_x(cam_phi);
xgl_rotate_y(cam_theta);
-// xgl_draw(XGL_QUADS, cube, sizeof cube / sizeof *cube);
- xgl_draw(XGL_TRIANGLES, suzanne, sizeof suzanne / sizeof *suzanne);
+
+ if(show_obj) {
+ if(cam_theta < X_PI) {
+ xgl_draw(XGL_LINES, gridaxes + 2, 2); /* -X */
+ } else {
+ xgl_draw(XGL_LINES, gridaxes, 2); /* +X */
+ }
+ if(cam_theta < X_HPI || cam_theta > (3 * X_HPI)) {
+ xgl_draw(XGL_LINES, gridaxes + 4, 2); /* +Z */
+ } else {
+ xgl_draw(XGL_LINES, gridaxes + 6, 2); /* -Z */
+ }
+
+ if(show_obj == 1) {
+ xgl_draw(XGL_QUADS, cube, sizeof cube / sizeof *cube);
+ } else {
+ xgl_draw(XGL_TRIANGLES, suzanne, sizeof suzanne / sizeof *suzanne);
+ }
+
+ if(cam_theta < X_PI) {
+ xgl_draw(XGL_LINES, gridaxes, 2); /* +X */
+ } else {
+ xgl_draw(XGL_LINES, gridaxes + 2, 2); /* -X */
+ }
+ if(cam_theta < X_HPI || cam_theta > (3 * X_HPI)) {
+ xgl_draw(XGL_LINES, gridaxes + 6, 2); /* -Z */
+ } else {
+ xgl_draw(XGL_LINES, gridaxes + 4, 2); /* +Z */
+ }
+ } else {
+ xgl_draw(XGL_LINES, gridaxes + 8, 8);
+ }
wait_vblank();
present(backbuf);
}
if(KEYPRESS(KEY_LEFT)) {
cam_theta += 0x2000;
+ if(cam_theta > X_2PI) cam_theta -= X_2PI;
}
if(KEYPRESS(KEY_RIGHT)) {
cam_theta -= 0x2000;
+ if(cam_theta < 0) cam_theta += X_2PI;
+ }
+ if(KEYPRESS(KEY_RT)) {
+ if(++show_obj > 2) show_obj = 0;
+ }
+ if(KEYPRESS(KEY_LT)) {
+ if(--show_obj < 0) show_obj = 2;
+ }
+
+ if(KEYPRESS(KEY_A)) {
+ show_del ^= 1;
+ }
+ if(KEYPRESS(KEY_B)) {
+ if(show_del) {
+ show_obj = 0;
+ show_del = 0;
+ }
}
}
fbptr += fbwidth;
}
}
+
+
+/* ----- line drawing and clipping ------ */
+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, unsigned short color)
+{
+ int i, dx, dy, x_inc, y_inc, error;
+ unsigned char *fbptr = fb;
+
+ fbptr += y0 * fbwidth + x0;
+
+ dx = x1 - x0;
+ dy = y1 - y0;
+
+ if(dx >= 0) {
+ x_inc = 1;
+ } else {
+ x_inc = -1;
+ dx = -dx;
+ }
+ if(dy >= 0) {
+ y_inc = fbwidth;
+ } else {
+ y_inc = -fbwidth;
+ dy = -dy;
+ }
+
+ if(dx > dy) {
+ error = dy * 2 - dx;
+ for(i=0; i<=dx; i++) {
+ *fbptr = color;
+ if(error >= 0) {
+ error -= dx * 2;
+ fbptr += y_inc;
+ }
+ error += dy * 2;
+ fbptr += x_inc;
+ }
+ } else {
+ error = dx * 2 - dy;
+ for(i=0; i<=dy; i++) {
+ *fbptr = color;
+ if(error >= 0) {
+ error -= dy * 2;
+ fbptr += x_inc;
+ }
+ error += dx * 2;
+ fbptr += y_inc;
+ }
+ }
+}
+
static unsigned int opt;
static int32_t ldir[3];
+static void draw_ptlines(int prim, const struct xvertex *varr, int vcount);
+
+
void xgl_init(void)
{
xgl_viewport(0, 0, 240, 160);
struct pvertex pv[4];
int32_t ndotl;
+ if(prim < 3) {
+ draw_ptlines(prim, varr, vcount);
+ return;
+ }
+
while(vcount >= prim) {
cidx = varr->cidx;
polyfill_flat(pv, prim, cidx);
}
}
+
+static void draw_ptlines(int prim, const struct xvertex *varr, int vcount)
+{
+ int i;
+ struct xvertex xv[2];
+
+ while(vcount >= prim) {
+ for(i=0; i<prim; i++) {
+ xform(xv + i, varr, mat[mtop]);
+
+ xv[i].x = (xv[i].x << 1) / (xv[i].z >> 8); /* assume aspect: ~2 */
+ xv[i].y = (xv[i].y << 2) / (xv[i].z >> 8); /* the shift is * PROJ_D */
+ /* projection result is 24.8 */
+ /* viewport */
+ xv[i].x = ((((xv[i].x + 0x100) >> 1) * vp[2]) >> 8) + vp[0];
+ xv[i].y = ((((0x100 - xv[i].y) >> 1) * vp[3]) >> 8) + vp[1];
+ varr++;
+ }
+ vcount -= prim;
+
+ /* line clipping */
+ clip_line((int*)&xv[0].x, (int*)&xv[0].y, (int*)&xv[1].x, (int*)&xv[1].y, vp[0], vp[1], vp[2] - 1, vp[3] - 1);
+ draw_line(xv[0].x, xv[0].y, xv[1].x, xv[1].y, varr[-2].cidx);
+ }
+}