Basic 3D graphics for the MBED application-shield on-board LCD (initial/incomplete).
g3d_render.cpp
- Committer:
- co657_frmb
- Date:
- 2015-11-28
- Revision:
- 8:55ee7af49f47
- Parent:
- 7:393b963e7988
- Child:
- 9:db4ec6f7d8b2
File content as of revision 8:55ee7af49f47:
/* * g3d_render.cpp -- rendering stuff for G3D library * Copyright (C) 2015 Fred Barnes, University of Kent * GPL >= 2.0 */ #include "mbed.h" #include "C12832.h" #include "gfx3d.h" #define DISPLAY_WIDTH (128) #define DISPLAY_HEIGHT (32) #define ZB_YSHIFT (7) /* grotty: single global Z buffer that matches the LCD size */ static int16_t zbuffer[DISPLAY_HEIGHT * DISPLAY_WIDTH]; #define ZBUFFER(X,Y) zbuffer[(Y << ZB_YSHIFT) | X] /** * clears the Z buffer (sets all to maximum) */ void gfx3d_clear_zb (void) { int i; int lim = (DISPLAY_HEIGHT * DISPLAY_WIDTH) >> 1; uint32_t *halfbuf = (uint32_t *)zbuffer; for (i=0; i<lim; i++) { halfbuf[i] = 0x7fff7fff; } } #if 0 /** * fixes scan-line starts/ends in a g3d_polyscan_t structure based on edge */ static void gfx3d_polyfix (g3d_polyscan_t *dst, int16_t x1, int16_t y1, int32_t z1, int16_t x2, int16_t y2, int32_t z2, const float co_a, const float co_b, const float co_c, const float co_d) { if (y2 < y1) { /* swap around: make sure we go in the same direction (down) */ int16_t t16; int32_t t32; t16 = x1; x1 = x2; x2 = t16; t16 = y1; y1 = y2; y2 = t16; t32 = z1; z1 = z2; z2 = t32; } /* scan limit */ if (y1 < dst->scan_s) { dst->scan_s = y1; } if (y2 > dst->scan_e) { dst->scan_e = y2; } if (y1 == y2) { /* flat polygon */ dst->scans[y1][0] = x1; dst->scans[y1][1] = x2; dst->zscan[y1][0] = z1; dst->zscan[y1][1] = z2; } else { /* vaguely complex polygon */ int x, y, z, step, z_step; x = (int)x1 << 16; step = ((int)(x2 - x1) << 16) / (int)(y2 - y1); x += step; z = z1; z_step = (z2 - z1) / ((y2 - y1) + 1); y1++; for (y=y1; y<=y2; y++) { if ((y >= 0) && (y < 32)) { int shx = x >> 16; if (x < 0) { shx = shx - 65536; } if (dst->scans[y][0] == 0xff) { /* start of scan */ uint8_t x8 = (uint8_t)(shx & 0xff); if (x8 == 0xff) { x8 = 128; } dst->scans[y][0] = x8; if (co_c != 0.0f) { dst->zscan[y][0] = (int32_t)(((-(co_a * (float)shx) - (co_b * (float)y)) - co_d) / co_c); } else { dst->zscan[y][0] = z; } } else { /* end of scan */ uint8_t x8 = (uint8_t)(shx & 0xff); if (x8 == 0xff) { x8 = 128; } dst->scans[y][1] = x8; if (co_c != 0.0f) { dst->zscan[y][1] = (int32_t)(((-(co_a * (float)shx) - (co_b * (float)y)) - co_d) / co_c); } else { dst->zscan[y][1] = z; } } } x += step; z += z_step; } } } /** * takes a polygon structure and generates a set of scanline data from it */ void gfx3d_polyscan (const g3d_poly_t *src, g3d_polyscan_t *dst) { int i; float co_a, co_b, co_c, co_d; float x1 = (float)src->x[0]; float y1 = (float)src->y[0]; float z1 = (float)src->z[0]; float x2 = (float)src->x[1]; float y2 = (float)src->y[1]; float z2 = (float)src->z[1]; float x3 = (float)src->x[2]; float y3 = (float)src->y[2]; float z3 = (float)src->z[2]; for (i=0; i<32; i++) { dst->scans[i][0] = 0xff; dst->scans[i][1] = 0xff; dst->zscan[i][0] = 0; dst->zscan[i][1] = 0; } dst->scan_s = 32; dst->scan_e = 0; dst->norm = src->norm; /* coefficients for plane equations, Herne & Baker p308 */ co_a = ((y1 * (z2 - z3)) + (y2 * (z3 - z1))) + (y3 * (z1 - z2)); co_b = ((z1 * (x2 - x3)) + (z2 * (x3 - x1))) + (z3 * (x1 - x2)); co_c = ((x1 * (y2 - y3)) + (x2 * (y3 - y1))) + (x3 * (y1 - y2)); co_d = ((-x1 * ((y2 * z3) - (y3 * z2))) - (x2 * ((y3 * z1) - (y1 * z3)))) - (x3 * ((y1 * z2) - (y2 * z1))); gfx3d_polyfix (dst, src->x[0], src->y[0], src->z[0], src->x[1], src->y[1], src->z[1], co_a, co_b, co_c, co_d); gfx3d_polyfix (dst, src->x[1], src->y[1], src->z[1], src->x[2], src->y[2], src->z[2], co_a, co_b, co_c, co_d); gfx3d_polyfix (dst, src->x[2], src->y[2], src->z[2], src->x[0], src->y[0], src->z[0], co_a, co_b, co_c, co_d); if (dst->scan_s < 0) { dst->scan_s = 0; } else if (dst->scan_s >= 32) { dst->scan_s = 31; } if (dst->scan_e < 0) { dst->scan_e = 0; } else if (dst->scan_e >= 32) { dst->scan_e = 31; } } #endif static inline void gfx3d_swap_points (g3d_2p3_t *p1, g3d_2p3_t *p2) { uint32_t *v1 = (uint32_t *)p1; uint32_t *v2 = (uint32_t *)p2; uint32_t tmp; tmp = *v1; *v1 = *v2; *v2 = tmp; v1++, v2++; tmp = *v1; *v1 = *v2; *v2 = tmp; } static inline void gfx3d_swap_txpoints (uint16_t *p1, uint16_t *p2) { uint16_t tmp = *p1; *p1 = *p2; *p2 = tmp; return; } void gfx3d_sort_poly (g3d_poly_t *p) { /* arranges points in the polygon into left->right order -- crude */ if (p->pts[1].x < p->pts[0].x) { /* point in 1 left of 0, swap */ gfx3d_swap_points (&(p->pts[0]), &(p->pts[1])); gfx3d_swap_txpoints (&(p->tx_pts[0]), &(p->tx_pts[1])); } if (p->pts[2].x < p->pts[0].x) { /* point in 2 left of 0, swap */ gfx3d_swap_points (&(p->pts[0]), &(p->pts[2])); gfx3d_swap_txpoints (&(p->tx_pts[0]), &(p->tx_pts[2])); } if (p->pts[2].x < p->pts[1].x) { /* point in 2 left of 1, swap */ gfx3d_swap_points (&(p->pts[1]), &(p->pts[2])); gfx3d_swap_txpoints (&(p->tx_pts[1]), &(p->tx_pts[2])); } } static inline void gfx3d_edgebuf_z_fixin (const g3d_2p3_t *p0, const g3d_2p3_t *p1, uint8_t *yedge, uint16_t *zedge, uint16_t xoff) { int32_t y = (p0->y << 16) | 0x8000; /* half-way... */ int32_t ydelta; int32_t z = (p0->z << 16) | 0x8000; /* half-way... */ int32_t zdelta; int x; if (p0->x == p1->x) { /* same X position -- should have been dealt with */ return; } ydelta = ((int32_t)(p1->y - p0->y) << 16) / (int32_t)(p1->x - p0->x); zdelta = ((int32_t)(p1->z - p0->z) << 16) / (int32_t)(p1->x - p0->x); for (x = p0->x; x <= p1->x; x++) { int16_t rc_y; int16_t rc_z; if (x < 0) { y += ydelta; z += zdelta; continue; } if (x >= DISPLAY_WIDTH) { /* can't have any more */ return; } rc_y = (y >> 16); if (rc_y < 0) { y += ydelta; z += zdelta; continue; } if (rc_y >= DISPLAY_HEIGHT) { y += ydelta; z += zdelta; continue; } yedge[x - xoff] = rc_y; y += ydelta; rc_z = (z >> 16); zedge[x - xoff] = rc_z; z += zdelta; } } /** * takes a polygon and fills an edge-buffer with it. Assumes triangular and sorted poly. */ void gfx3d_edgebuf_z (const g3d_poly_t *src, g3d_edgebuf_t *dst) { if (src->pts[0].x < 0) { /* left-hand point off-screen */ dst->xoff = 0; } else { dst->xoff = src->pts[0].x; } dst->s_end = (src->pts[2].x - src->pts[0].x) + 1; if (src->pts[0].x == src->pts[2].x) { /* vertical line only */ if (src->pts[0].y <= src->pts[1].y) { /* p0 is above p1 */ if (src->pts[1].y < 0) { /* off top */ dst->s_end = 0; } else if (src->pts[0].y >= DISPLAY_HEIGHT) { /* off bottom */ dst->s_end = 0; } else { if (src->pts[0].y < 0) { dst->start[0] = 0; } else { dst->start[0] = src->pts[0].y; } if (src->pts[1].y >= DISPLAY_HEIGHT) { dst->end[0] = DISPLAY_HEIGHT - 1; } else { dst->end[0] = src->pts[1].y; } /* if we over-shot, this will be wrong */ dst->zstart[0] = src->pts[0].z; dst->zend[0] = src->pts[1].z; } } else { if (src->pts[0].y < 0) { /* off top */ dst->s_end = 0; } else if (src->pts[1].y >= DISPLAY_HEIGHT) { /* off bottom */ dst->s_end = 0; } else { if (src->pts[1].y < 0) { dst->start[0] = 0; } else { dst->start[0] = src->pts[1].y; } if (src->pts[0].y >= DISPLAY_HEIGHT) { dst->end[0] = DISPLAY_HEIGHT - 1; } else { dst->end[0] = src->pts[0].y; } /* if we over-shot, this will be wrong */ dst->zstart[0] = src->pts[1].z; dst->zend[0] = src->pts[0].z; } } return; } /* figure out whether the middle point belongs above or below the longest edge */ if (((src->pts[2].y - src->pts[0].y) * (src->pts[1].x - src->pts[0].x)) < ((src->pts[1].y - src->pts[0].y) * (src->pts[2].x - src->pts[0].x))) { /* middle point is on the top-portion */ gfx3d_edgebuf_z_fixin (&(src->pts[0]), &(src->pts[1]), dst->start, dst->zstart, dst->xoff); gfx3d_edgebuf_z_fixin (&(src->pts[1]), &(src->pts[2]), dst->start, dst->zstart, dst->xoff); gfx3d_edgebuf_z_fixin (&(src->pts[0]), &(src->pts[2]), dst->end, dst->zend, dst->xoff); } else { /* middle point is on the bottom-portion */ gfx3d_edgebuf_z_fixin (&(src->pts[0]), &(src->pts[2]), dst->start, dst->zstart, dst->xoff); gfx3d_edgebuf_z_fixin (&(src->pts[0]), &(src->pts[1]), dst->end, dst->zend, dst->xoff); gfx3d_edgebuf_z_fixin (&(src->pts[1]), &(src->pts[2]), dst->end, dst->zend, dst->xoff); } } /** * takes a polygon (containing a texture) and an LCD and draws it. * * @param src Source polygon. * @param lcd Display LCD to use (size fixed in various places..). */ void gfx3d_polytxmap (const g3d_poly_t *src, C12832 &lcd) { /* assert: polygon points are in order left-to-right */ int16_t x, use_z = src->pts[0].z; int32_t dydx_ab, dydx_ac, dydx_bc; int32_t dudx_ab, dudx_ac, dudx_bc; int32_t dvdx_ab, dvdx_ac, dvdx_bc; if (src->pts[1].x > src->pts[0].x) { /* we have a left-hand side */ dydx_ab = ((src->pts[1].y - src->pts[0].y) << 16) / (src->pts[1].x - src->pts[0].x); dudx_ab = (((int32_t)(src->tx_pts[1] & 0xff) - (int32_t)(src->tx_pts[0] & 0xff)) << 16) / (int32_t)(src->pts[1].x - src->pts[0].x); dvdx_ab = (((int32_t)(src->tx_pts[1] >> 8) - (int32_t)(src->tx_pts[0] >> 8)) << 16) / (int32_t)(src->pts[1].x - src->pts[0].x); } else { dydx_ab = 0; dudx_ab = 0; dvdx_ab = 0; } if (src->pts[2].x > src->pts[0].x) { /* we have the long X edge */ dydx_ac = ((src->pts[2].y - src->pts[0].y) << 16) / (src->pts[2].x - src->pts[0].x); dudx_ac = (((int32_t)(src->tx_pts[2] & 0xff) - (int32_t)(src->tx_pts[0] & 0xff)) << 16) / (int32_t)(src->pts[2].x - src->pts[0].x); dvdx_ac = (((int32_t)(src->tx_pts[2] >> 8) - (int32_t)(src->tx_pts[0] >> 8)) << 16) / (int32_t)(src->pts[2].x - src->pts[0].x); } else { dydx_ac = 0; dudx_ac = 0; dvdx_ac = 0; } if (src->pts[2].x > src->pts[1].x) { /* we have a right-hand side */ dydx_bc = ((src->pts[2].y - src->pts[1].y) << 16) / (src->pts[2].x - src->pts[1].x); dudx_bc = (((int32_t)(src->tx_pts[2] & 0xff) - (int32_t)(src->tx_pts[1] & 0xff)) << 16) / (int32_t)(src->pts[2].x - src->pts[1].x); dvdx_bc = (((int32_t)(src->tx_pts[2] >> 8) - (int32_t)(src->tx_pts[1] >> 8)) << 16) / (int32_t)(src->pts[2].x - src->pts[1].x); } else { dydx_bc = 0; dudx_bc = 0; dvdx_bc = 0; } /* Note: * - mostly 16.16 fixpoint stuff. * - could optimise more by better pixel plotting (directly into the buffer). */ int32_t y_top = (src->pts[0].y << 16) + 0x8000; int32_t y_bot = (src->pts[0].y << 16) + 0x8000; int32_t tx_top_x = (src->tx_pts[0] & 0xff) << 16; int32_t tx_top_y = (src->tx_pts[0] >> 8) << 16; int32_t tx_bot_x = (src->tx_pts[0] & 0xff) << 16; int32_t tx_bot_y = (src->tx_pts[0] >> 8) << 16; int32_t tx_dudy, tx_dvdy; int16_t ys; /* the texture gradients (tx_dudy, tx_dvdy) are constant for any particular triangle */ int32_t tx_ctemp, tx_tall, p_y, tp_x, tp_y; if (src->pts[2].x == src->pts[0].x) { /* skinny */ tx_ctemp = 0; } else { tx_ctemp = ((src->pts[1].x - src->pts[0].x) << 16) / (src->pts[2].x - src->pts[0].x); /* factor of AB to AC, (fixpoint 0->1) */ } p_y = y_top + ((src->pts[2].y - src->pts[0].y) * tx_ctemp); tp_x = ((int32_t)(src->tx_pts[0] & 0xff) << 16) + ((int32_t)((src->tx_pts[2] & 0xff) - (src->tx_pts[0] & 0xff)) * tx_ctemp); tp_y = ((int32_t)(src->tx_pts[0] >> 8) << 16) + ((int32_t)((src->tx_pts[2] >> 8) - (src->tx_pts[0] >> 8)) * tx_ctemp); tx_tall = abs ((p_y - (src->pts[1].y << 16)) >> 8); /* height of tallest scan -- positive 24.8 fixpoint */ if (tx_tall == 0) { /* flat in effect */ tx_dudy = 0; tx_dvdy = 0; ys = 1; } else { tx_dudy = (tp_x - ((int32_t)(src->tx_pts[1] & 0xff) << 16)); tx_dudy = (tx_dudy / tx_tall) << 8; tx_dvdy = (tp_y - ((int32_t)(src->tx_pts[1] >> 8) << 16)); tx_dvdy = (tx_dvdy / tx_tall) << 8; ys = (p_y > (src->pts[1].y << 16)) ? 1 : -1; } /* left-hand side */ for (x=src->pts[0].x; x<src->pts[1].x; x++) { int16_t pix_y = (y_top >> 16); int16_t bpix_y = (y_bot >> 16) + ys; /* make sure we include the bottom pixel */ int16_t y; int16_t tpix_y, tpix_x; int32_t stx_y = tx_top_y; int32_t stx_x = tx_top_x; y_top += dydx_ab; y_bot += dydx_ac; tx_top_x += dudx_ab; tx_top_y += dvdx_ab; tx_bot_x += dudx_ac; tx_bot_y += dvdx_ac; if ((x < 0) || (x >= DISPLAY_WIDTH)) { continue; } for (y=pix_y; y != bpix_y; y += ys) { if ((y < 0) || (y >= DISPLAY_HEIGHT)) { goto yl_loop_advance; } if (use_z > ZBUFFER (x, y)) { goto yl_loop_advance; } ZBUFFER (x, y) = use_z; tpix_y = (stx_y >> 16) & (DISPLAY_HEIGHT - 1); tpix_x = (stx_x >> 16) & (DISPLAY_WIDTH - 1); lcd.pixel_nochk_norm (x, y, g3d_texture_bit (src->txptr, tpix_x, tpix_y)); yl_loop_advance: stx_x += tx_dudy; stx_y += tx_dvdy; } } y_top = (src->pts[1].y << 16) + 0x8000; tx_top_x = (src->tx_pts[1] & 0xff) << 16; tx_top_y = (src->tx_pts[1] >> 8) << 16; /* right-hand side */ for (; x<src->pts[2].x; x++) { int16_t pix_y = (y_top >> 16); int16_t bpix_y = (y_bot >> 16) + ys; int16_t y; int16_t tpix_y, tpix_x; int32_t stx_y = tx_top_y; int32_t stx_x = tx_top_x; y_top += dydx_bc; y_bot += dydx_ac; tx_top_x += dudx_bc; tx_top_y += dvdx_bc; tx_bot_x += dudx_ac; tx_bot_y += dvdx_ac; if ((x < 0) || (x >= DISPLAY_WIDTH)) { continue; } for (y=pix_y; y != bpix_y; y += ys) { if ((y < 0) || (y >= DISPLAY_HEIGHT)) { goto yr_loop_advance; } if (use_z > ZBUFFER (x, y)) { goto yr_loop_advance; } ZBUFFER (x, y) = use_z; tpix_y = (stx_y >> 16) & (DISPLAY_HEIGHT - 1); tpix_x = (stx_x >> 16) & (DISPLAY_WIDTH - 1); lcd.pixel_nochk_norm (x, y, g3d_texture_bit (src->txptr, tpix_x, tpix_y)); yr_loop_advance: stx_x += tx_dudy; stx_y += tx_dvdy; } } } /** * takes a polygon, drawing it on the given LCD with shading based on normal value. * * @param src Source polygon. * @param lcd Display LCD to use (size fixed in various places..). */ void gfx3d_polynormmap (const g3d_poly_t *src, C12832 &lcd) { /* assert: polygon points are in order left-to-right */ int16_t x, use_z = src->pts[0].z; int32_t dydx_ab, dydx_ac, dydx_bc; if (src->pts[1].x > src->pts[0].x) { /* we have a left-hand side */ dydx_ab = ((src->pts[1].y - src->pts[0].y) << 16) / (src->pts[1].x - src->pts[0].x); } else { dydx_ab = 0; } if (src->pts[2].x > src->pts[0].x) { /* we have the long X edge */ dydx_ac = ((src->pts[2].y - src->pts[0].y) << 16) / (src->pts[2].x - src->pts[0].x); } else { dydx_ac = 0; } if (src->pts[2].x > src->pts[1].x) { /* we have a right-hand side */ dydx_bc = ((src->pts[2].y - src->pts[1].y) << 16) / (src->pts[2].x - src->pts[1].x); } else { dydx_bc = 0; } /* Note: * - mostly 16.16 fixpoint stuff. * - could optimise more by better pixel plotting (directly into the buffer). */ int32_t y_top = (src->pts[0].y << 16) + 0x8000; int32_t y_bot = (src->pts[0].y << 16) + 0x8000; int16_t ys; int32_t tx_ctemp, tx_tall, p_y; int bitstep = (32 - __CLZ (src->norm)) >> 2; int pcount = 0; if (bitstep == 0) { bitstep = 1; } if (src->pts[2].x == src->pts[0].x) { /* skinny */ tx_ctemp = 0; } else { tx_ctemp = ((src->pts[1].x - src->pts[0].x) << 16) / (src->pts[2].x - src->pts[0].x); /* factor of AB to AC, (fixpoint 0->1) */ } p_y = y_top + ((src->pts[2].y - src->pts[0].y) * tx_ctemp); tx_tall = abs ((p_y - (src->pts[1].y << 16)) >> 8); /* height of tallest scan -- positive 24.8 fixpoint */ if (tx_tall == 0) { /* flat in effect */ ys = 1; } else { ys = (p_y > (src->pts[1].y << 16)) ? 1 : -1; } /* left-hand side */ for (x=src->pts[0].x; x<src->pts[1].x; x++) { int16_t pix_y = (y_top >> 16); int16_t bpix_y = (y_bot >> 16) + ys; /* make sure we include the bottom pixel */ int16_t y; y_top += dydx_ab; y_bot += dydx_ac; if ((x < 0) || (x >= DISPLAY_WIDTH)) { continue; } pcount = 0; for (y=pix_y; y != bpix_y; y += ys) { if ((y < 0) || (y >= DISPLAY_HEIGHT)) { continue; } if (use_z > ZBUFFER (x, y)) { continue; } ZBUFFER (x, y) = use_z; lcd.pixel_nochk_norm (x, y, (pcount == 0) ? 1 : 0); if (!pcount) { pcount = bitstep; } pcount--; } } y_top = (src->pts[1].y << 16) + 0x8000; /* right-hand side */ for (; x<src->pts[2].x; x++) { int16_t pix_y = (y_top >> 16); int16_t bpix_y = (y_bot >> 16) + ys; int16_t y; y_top += dydx_bc; y_bot += dydx_ac; if ((x < 0) || (x >= DISPLAY_WIDTH)) { continue; } pcount = 0; for (y=pix_y; y != bpix_y; y += ys) { if ((y < 0) || (y >= DISPLAY_HEIGHT)) { continue; } if (use_z > ZBUFFER (x, y)) { continue; } ZBUFFER (x, y) = use_z; lcd.pixel_nochk_norm (x, y, (pcount == 0) ? 1 : 0); if (!pcount) { pcount = bitstep; } pcount--; } } } /** * takes an edge-buffer and draws its wireframe on the given LCD (start and end). */ void gfx3d_wireedge (const g3d_edgebuf_t *edge, C12832 &lcd) { int x; if (edge->s_end == 1) { /* special case: vertical line */ int xp = edge->xoff; int y0 = edge->start[0]; int y1 = edge->end[0]; int ys = (y1 >= y0) ? 1 : -1; int y; int16_t z0 = edge->zstart[0]; int16_t z1 = edge->zend[0]; int32_t zval = (z0 << 16) | 0x8000; /* half-way.. */ if ((y0 == y1) || ((y0 + ys) == y1)) { /* one or two point, since we're narrow, just y0 */ if (z0 <= ZBUFFER (xp, y0)) { ZBUFFER (xp, y0) = z0; lcd.pixel_nochk_norm (xp, y0, 1); } } else { /* long vertical poly, set all points except at y1 */ int32_t zdelta = ((int32_t)(z1 - z0) << 16) / (int32_t)(y1 - y0); int16_t rc_z = z0; for (y = y0; y != y1; y += ys) { zval += zdelta; rc_z = (zval >> 16); if (rc_z <= ZBUFFER (xp, y)) { ZBUFFER (xp, y) = rc_z; lcd.pixel_nochk_norm (xp, y, 1); } } } return; } for (x=0; x<edge->s_end; x++) { int xp = x + edge->xoff; int y0 = edge->start[x]; int y1 = edge->end[x]; int ys = (y1 >= y0) ? 1 : -1; int y; int16_t z0 = edge->zstart[x]; int16_t z1 = edge->zend[x]; int32_t zval = (z0 << 16) | 0x8000; /* half-way.. */ if (y0 == y1) { /* point, but we don't plot assuming it belongs to the adjoining polygon */ } else if ((y0 + ys) == y1) { /* two-point poly, just plot y0 */ if (z0 <= ZBUFFER (xp, y0)) { ZBUFFER (xp, y0) = z0; lcd.pixel_nochk_norm (xp, y0, 1); } } else { /* more than two points, shrink y1 to avoid plotting the last one here */ int32_t zdelta = ((int32_t)(z1 - z0) << 16) / (int32_t)(y1 - y0); int16_t rc_z = z0; y1 -= ys; /* start at y0 */ y = y0; if (rc_z <= ZBUFFER (xp, y)) { ZBUFFER (xp, y) = rc_z; lcd.pixel_nochk_norm (xp, y, 1); } for (y += ys; y != y1; y += ys) { zval += zdelta; rc_z = (zval >> 16); if (rc_z <= ZBUFFER (xp, y)) { ZBUFFER (xp, y) = rc_z; lcd.pixel_nochk_norm (xp, y, 0); } } /* last pixel at y1,z1 */ rc_z = z1; if (rc_z <= ZBUFFER (xp, y1)) { ZBUFFER (xp, y1) = rc_z; lcd.pixel_nochk_norm (xp, y1, 1); } } /* end of x-loop */ } }