grid axes
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 15 Mar 2021 08:33:33 +0000 (10:33 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 15 Mar 2021 08:33:33 +0000 (10:33 +0200)
src/main.c
src/polyfill.c
src/polyfill.h
src/xgl.c

index d5dc096..a519dc0 100644 (file)
@@ -38,6 +38,31 @@ extern unsigned char bgimg_pixels[];
 
 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;
@@ -91,8 +116,38 @@ int main(void)
                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);
@@ -115,8 +170,26 @@ static void handle_keys(void)
        }
        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;
+               }
        }
 }
index a068295..11e70fd 100644 (file)
@@ -97,3 +97,148 @@ void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col)
                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;
+               }
+       }
+}
+
index d637046..88166cf 100644 (file)
@@ -27,4 +27,7 @@ struct pvertex {
 void polyfill_framebuffer(unsigned char *fb, int width, int height);
 void polyfill_flat(struct pvertex *v, int vnum, unsigned char col);
 
+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);
+
 #endif /* POLYFILL_H_ */
index 6277ce5..4880aba 100644 (file)
--- a/src/xgl.c
+++ b/src/xgl.c
@@ -29,6 +29,9 @@ static int mtop;
 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);
@@ -190,6 +193,11 @@ void xgl_draw(int prim, const struct xvertex *varr, int vcount)
        struct pvertex pv[4];
        int32_t ndotl;
 
+       if(prim < 3) {
+               draw_ptlines(prim, varr, vcount);
+               return;
+       }
+
        while(vcount >= prim) {
                cidx = varr->cidx;
 
@@ -234,3 +242,28 @@ void xgl_draw(int prim, const struct xvertex *varr, int vcount)
                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);
+       }
+}