Basic 3D graphics for the MBED application-shield on-board LCD (initial/incomplete).
Embed:
(wiki syntax)
Show/hide line numbers
g3d_render.cpp
00001 /* 00002 * g3d_render.cpp -- rendering stuff for G3D library 00003 * Copyright (C) 2015 Fred Barnes, University of Kent 00004 * GPL >= 2.0 00005 */ 00006 00007 00008 #include "mbed.h" 00009 #include "C12832.h" 00010 #include "gfx3d.h" 00011 00012 #define DISPLAY_WIDTH (128) 00013 #define DISPLAY_HEIGHT (32) 00014 00015 #define ZB_YSHIFT (7) 00016 00017 /* grotty: single global Z buffer that matches the LCD size */ 00018 static int16_t zbuffer[DISPLAY_HEIGHT * DISPLAY_WIDTH]; 00019 00020 #define ZBUFFER(X,Y) zbuffer[(Y << ZB_YSHIFT) | X] 00021 00022 /** 00023 * clears the Z buffer (sets all to maximum) 00024 */ 00025 void gfx3d_clear_zb (void) 00026 { 00027 int i; 00028 int lim = (DISPLAY_HEIGHT * DISPLAY_WIDTH) >> 1; 00029 uint32_t *halfbuf = (uint32_t *)zbuffer; 00030 00031 for (i=0; i<lim; i++) { 00032 halfbuf[i] = 0x7fff7fff; 00033 } 00034 } 00035 00036 #if 0 00037 /** 00038 * fixes scan-line starts/ends in a g3d_polyscan_t structure based on edge 00039 */ 00040 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) 00041 { 00042 if (y2 < y1) { 00043 /* swap around: make sure we go in the same direction (down) */ 00044 int16_t t16; 00045 int32_t t32; 00046 00047 t16 = x1; 00048 x1 = x2; 00049 x2 = t16; 00050 00051 t16 = y1; 00052 y1 = y2; 00053 y2 = t16; 00054 00055 t32 = z1; 00056 z1 = z2; 00057 z2 = t32; 00058 } 00059 00060 /* scan limit */ 00061 if (y1 < dst->scan_s) { 00062 dst->scan_s = y1; 00063 } 00064 if (y2 > dst->scan_e) { 00065 dst->scan_e = y2; 00066 } 00067 if (y1 == y2) { 00068 /* flat polygon */ 00069 dst->scans[y1][0] = x1; 00070 dst->scans[y1][1] = x2; 00071 dst->zscan[y1][0] = z1; 00072 dst->zscan[y1][1] = z2; 00073 } else { 00074 /* vaguely complex polygon */ 00075 int x, y, z, step, z_step; 00076 00077 x = (int)x1 << 16; 00078 step = ((int)(x2 - x1) << 16) / (int)(y2 - y1); 00079 x += step; 00080 00081 z = z1; 00082 z_step = (z2 - z1) / ((y2 - y1) + 1); 00083 y1++; 00084 00085 for (y=y1; y<=y2; y++) { 00086 if ((y >= 0) && (y < 32)) { 00087 int shx = x >> 16; 00088 00089 if (x < 0) { 00090 shx = shx - 65536; 00091 } 00092 if (dst->scans[y][0] == 0xff) { 00093 /* start of scan */ 00094 uint8_t x8 = (uint8_t)(shx & 0xff); 00095 00096 if (x8 == 0xff) { 00097 x8 = 128; 00098 } 00099 dst->scans[y][0] = x8; 00100 if (co_c != 0.0f) { 00101 dst->zscan[y][0] = (int32_t)(((-(co_a * (float)shx) - (co_b * (float)y)) - co_d) / co_c); 00102 } else { 00103 dst->zscan[y][0] = z; 00104 } 00105 } else { 00106 /* end of scan */ 00107 uint8_t x8 = (uint8_t)(shx & 0xff); 00108 00109 if (x8 == 0xff) { 00110 x8 = 128; 00111 } 00112 dst->scans[y][1] = x8; 00113 if (co_c != 0.0f) { 00114 dst->zscan[y][1] = (int32_t)(((-(co_a * (float)shx) - (co_b * (float)y)) - co_d) / co_c); 00115 } else { 00116 dst->zscan[y][1] = z; 00117 } 00118 } 00119 } 00120 x += step; 00121 z += z_step; 00122 } 00123 } 00124 } 00125 00126 00127 /** 00128 * takes a polygon structure and generates a set of scanline data from it 00129 */ 00130 void gfx3d_polyscan (const g3d_poly_t *src, g3d_polyscan_t *dst) 00131 { 00132 int i; 00133 float co_a, co_b, co_c, co_d; 00134 float x1 = (float)src->x[0]; 00135 float y1 = (float)src->y[0]; 00136 float z1 = (float)src->z[0]; 00137 float x2 = (float)src->x[1]; 00138 float y2 = (float)src->y[1]; 00139 float z2 = (float)src->z[1]; 00140 float x3 = (float)src->x[2]; 00141 float y3 = (float)src->y[2]; 00142 float z3 = (float)src->z[2]; 00143 00144 for (i=0; i<32; i++) { 00145 dst->scans[i][0] = 0xff; 00146 dst->scans[i][1] = 0xff; 00147 dst->zscan[i][0] = 0; 00148 dst->zscan[i][1] = 0; 00149 } 00150 dst->scan_s = 32; 00151 dst->scan_e = 0; 00152 dst->norm = src->norm; 00153 00154 /* coefficients for plane equations, Herne & Baker p308 */ 00155 co_a = ((y1 * (z2 - z3)) + (y2 * (z3 - z1))) + (y3 * (z1 - z2)); 00156 co_b = ((z1 * (x2 - x3)) + (z2 * (x3 - x1))) + (z3 * (x1 - x2)); 00157 co_c = ((x1 * (y2 - y3)) + (x2 * (y3 - y1))) + (x3 * (y1 - y2)); 00158 co_d = ((-x1 * ((y2 * z3) - (y3 * z2))) - (x2 * ((y3 * z1) - (y1 * z3)))) - (x3 * ((y1 * z2) - (y2 * z1))); 00159 00160 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); 00161 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); 00162 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); 00163 00164 if (dst->scan_s < 0) { 00165 dst->scan_s = 0; 00166 } else if (dst->scan_s >= 32) { 00167 dst->scan_s = 31; 00168 } 00169 if (dst->scan_e < 0) { 00170 dst->scan_e = 0; 00171 } else if (dst->scan_e >= 32) { 00172 dst->scan_e = 31; 00173 } 00174 00175 } 00176 #endif 00177 00178 static inline void gfx3d_swap_points (g3d_2p3_t *p1, g3d_2p3_t *p2) 00179 { 00180 uint32_t *v1 = (uint32_t *)p1; 00181 uint32_t *v2 = (uint32_t *)p2; 00182 uint32_t tmp; 00183 00184 tmp = *v1; 00185 *v1 = *v2; 00186 *v2 = tmp; 00187 00188 v1++, v2++; 00189 tmp = *v1; 00190 *v1 = *v2; 00191 *v2 = tmp; 00192 } 00193 00194 static inline void gfx3d_swap_txpoints (uint16_t *p1, uint16_t *p2) 00195 { 00196 uint16_t tmp = *p1; 00197 00198 *p1 = *p2; 00199 *p2 = tmp; 00200 return; 00201 } 00202 00203 void gfx3d_sort_poly (g3d_poly_t *p) 00204 { 00205 /* arranges points in the polygon into left->right order -- crude */ 00206 if (p->pts[1].x < p->pts[0].x) { 00207 /* point in 1 left of 0, swap */ 00208 gfx3d_swap_points (&(p->pts[0]), &(p->pts[1])); 00209 gfx3d_swap_txpoints (&(p->tx_pts[0]), &(p->tx_pts[1])); 00210 } 00211 if (p->pts[2].x < p->pts[0].x) { 00212 /* point in 2 left of 0, swap */ 00213 gfx3d_swap_points (&(p->pts[0]), &(p->pts[2])); 00214 gfx3d_swap_txpoints (&(p->tx_pts[0]), &(p->tx_pts[2])); 00215 } 00216 if (p->pts[2].x < p->pts[1].x) { 00217 /* point in 2 left of 1, swap */ 00218 gfx3d_swap_points (&(p->pts[1]), &(p->pts[2])); 00219 gfx3d_swap_txpoints (&(p->tx_pts[1]), &(p->tx_pts[2])); 00220 } 00221 } 00222 00223 00224 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) 00225 { 00226 int32_t y = (p0->y << 16) | 0x8000; /* half-way... */ 00227 int32_t ydelta; 00228 int32_t z = (p0->z << 16) | 0x8000; /* half-way... */ 00229 int32_t zdelta; 00230 int x; 00231 00232 if (p0->x == p1->x) { 00233 /* same X position -- should have been dealt with */ 00234 return; 00235 } 00236 00237 ydelta = ((int32_t)(p1->y - p0->y) << 16) / (int32_t)(p1->x - p0->x); 00238 zdelta = ((int32_t)(p1->z - p0->z) << 16) / (int32_t)(p1->x - p0->x); 00239 00240 for (x = p0->x; x <= p1->x; x++) { 00241 int16_t rc_y; 00242 int16_t rc_z; 00243 00244 if (x < 0) { 00245 y += ydelta; 00246 z += zdelta; 00247 continue; 00248 } 00249 if (x >= DISPLAY_WIDTH) { 00250 /* can't have any more */ 00251 return; 00252 } 00253 00254 rc_y = (y >> 16); 00255 if (rc_y < 0) { 00256 y += ydelta; 00257 z += zdelta; 00258 continue; 00259 } 00260 if (rc_y >= DISPLAY_HEIGHT) { 00261 y += ydelta; 00262 z += zdelta; 00263 continue; 00264 } 00265 yedge[x - xoff] = rc_y; 00266 y += ydelta; 00267 00268 rc_z = (z >> 16); 00269 zedge[x - xoff] = rc_z; 00270 z += zdelta; 00271 } 00272 } 00273 00274 00275 /** 00276 * takes a polygon and fills an edge-buffer with it. Assumes triangular and sorted poly. 00277 */ 00278 void gfx3d_edgebuf_z (const g3d_poly_t *src, g3d_edgebuf_t *dst) 00279 { 00280 if (src->pts[0].x < 0) { 00281 /* left-hand point off-screen */ 00282 dst->xoff = 0; 00283 } else { 00284 dst->xoff = src->pts[0].x; 00285 } 00286 dst->s_end = (src->pts[2].x - src->pts[0].x) + 1; 00287 00288 if (src->pts[0].x == src->pts[2].x) { 00289 /* vertical line only */ 00290 if (src->pts[0].y <= src->pts[1].y) { 00291 /* p0 is above p1 */ 00292 if (src->pts[1].y < 0) { 00293 /* off top */ 00294 dst->s_end = 0; 00295 } else if (src->pts[0].y >= DISPLAY_HEIGHT) { 00296 /* off bottom */ 00297 dst->s_end = 0; 00298 } else { 00299 if (src->pts[0].y < 0) { 00300 dst->start[0] = 0; 00301 } else { 00302 dst->start[0] = src->pts[0].y; 00303 } 00304 if (src->pts[1].y >= DISPLAY_HEIGHT) { 00305 dst->end[0] = DISPLAY_HEIGHT - 1; 00306 } else { 00307 dst->end[0] = src->pts[1].y; 00308 } 00309 /* if we over-shot, this will be wrong */ 00310 dst->zstart[0] = src->pts[0].z; 00311 dst->zend[0] = src->pts[1].z; 00312 } 00313 } else { 00314 if (src->pts[0].y < 0) { 00315 /* off top */ 00316 dst->s_end = 0; 00317 } else if (src->pts[1].y >= DISPLAY_HEIGHT) { 00318 /* off bottom */ 00319 dst->s_end = 0; 00320 } else { 00321 if (src->pts[1].y < 0) { 00322 dst->start[0] = 0; 00323 } else { 00324 dst->start[0] = src->pts[1].y; 00325 } 00326 if (src->pts[0].y >= DISPLAY_HEIGHT) { 00327 dst->end[0] = DISPLAY_HEIGHT - 1; 00328 } else { 00329 dst->end[0] = src->pts[0].y; 00330 } 00331 /* if we over-shot, this will be wrong */ 00332 dst->zstart[0] = src->pts[1].z; 00333 dst->zend[0] = src->pts[0].z; 00334 } 00335 } 00336 return; 00337 } 00338 00339 /* figure out whether the middle point belongs above or below the longest edge */ 00340 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))) { 00341 /* middle point is on the top-portion */ 00342 gfx3d_edgebuf_z_fixin (&(src->pts[0]), &(src->pts[1]), dst->start, dst->zstart, dst->xoff); 00343 gfx3d_edgebuf_z_fixin (&(src->pts[1]), &(src->pts[2]), dst->start, dst->zstart, dst->xoff); 00344 gfx3d_edgebuf_z_fixin (&(src->pts[0]), &(src->pts[2]), dst->end, dst->zend, dst->xoff); 00345 } else { 00346 /* middle point is on the bottom-portion */ 00347 gfx3d_edgebuf_z_fixin (&(src->pts[0]), &(src->pts[2]), dst->start, dst->zstart, dst->xoff); 00348 gfx3d_edgebuf_z_fixin (&(src->pts[0]), &(src->pts[1]), dst->end, dst->zend, dst->xoff); 00349 gfx3d_edgebuf_z_fixin (&(src->pts[1]), &(src->pts[2]), dst->end, dst->zend, dst->xoff); 00350 } 00351 } 00352 00353 00354 /** 00355 * takes a polygon (containing a texture) and an LCD and draws it. 00356 * 00357 * @param src Source polygon. 00358 * @param lcd Display LCD to use (size fixed in various places..). 00359 */ 00360 void gfx3d_polytxmap (const g3d_poly_t *src, C12832 &lcd) 00361 { 00362 /* assert: polygon points are in order left-to-right */ 00363 int16_t x, use_z = src->pts[0].z; 00364 int32_t dydx_ab, dydx_ac, dydx_bc; 00365 int32_t dudx_ab, dudx_ac, dudx_bc; 00366 int32_t dvdx_ab, dvdx_ac, dvdx_bc; 00367 00368 if (src->pts[1].x > src->pts[0].x) { 00369 /* we have a left-hand side */ 00370 dydx_ab = ((src->pts[1].y - src->pts[0].y) << 16) / (src->pts[1].x - src->pts[0].x); 00371 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); 00372 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); 00373 } else { 00374 dydx_ab = 0; 00375 dudx_ab = 0; 00376 dvdx_ab = 0; 00377 } 00378 if (src->pts[2].x > src->pts[0].x) { 00379 /* we have the long X edge */ 00380 dydx_ac = ((src->pts[2].y - src->pts[0].y) << 16) / (src->pts[2].x - src->pts[0].x); 00381 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); 00382 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); 00383 } else { 00384 dydx_ac = 0; 00385 dudx_ac = 0; 00386 dvdx_ac = 0; 00387 } 00388 if (src->pts[2].x > src->pts[1].x) { 00389 /* we have a right-hand side */ 00390 dydx_bc = ((src->pts[2].y - src->pts[1].y) << 16) / (src->pts[2].x - src->pts[1].x); 00391 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); 00392 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); 00393 } else { 00394 dydx_bc = 0; 00395 dudx_bc = 0; 00396 dvdx_bc = 0; 00397 } 00398 00399 /* Note: 00400 * - mostly 16.16 fixpoint stuff. 00401 * - could optimise more by better pixel plotting (directly into the buffer). 00402 */ 00403 00404 int32_t y_top = (src->pts[0].y << 16) + 0x8000; 00405 int32_t y_bot = (src->pts[0].y << 16) + 0x8000; 00406 int32_t tx_top_x = (src->tx_pts[0] & 0xff) << 16; 00407 int32_t tx_top_y = (src->tx_pts[0] >> 8) << 16; 00408 int32_t tx_bot_x = (src->tx_pts[0] & 0xff) << 16; 00409 int32_t tx_bot_y = (src->tx_pts[0] >> 8) << 16; 00410 int32_t tx_dudy, tx_dvdy; 00411 int16_t ys; 00412 00413 /* the texture gradients (tx_dudy, tx_dvdy) are constant for any particular triangle */ 00414 00415 int32_t tx_ctemp, tx_tall, p_y, tp_x, tp_y; 00416 00417 if (src->pts[2].x == src->pts[0].x) { 00418 /* skinny */ 00419 tx_ctemp = 0; 00420 } else { 00421 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) */ 00422 } 00423 00424 p_y = y_top + ((src->pts[2].y - src->pts[0].y) * tx_ctemp); 00425 tp_x = ((int32_t)(src->tx_pts[0] & 0xff) << 16) + ((int32_t)((src->tx_pts[2] & 0xff) - (src->tx_pts[0] & 0xff)) * tx_ctemp); 00426 tp_y = ((int32_t)(src->tx_pts[0] >> 8) << 16) + ((int32_t)((src->tx_pts[2] >> 8) - (src->tx_pts[0] >> 8)) * tx_ctemp); 00427 00428 tx_tall = abs ((p_y - (src->pts[1].y << 16)) >> 8); /* height of tallest scan -- positive 24.8 fixpoint */ 00429 00430 if (tx_tall == 0) { 00431 /* flat in effect */ 00432 tx_dudy = 0; 00433 tx_dvdy = 0; 00434 ys = 1; 00435 } else { 00436 tx_dudy = (tp_x - ((int32_t)(src->tx_pts[1] & 0xff) << 16)); 00437 tx_dudy = (tx_dudy / tx_tall) << 8; 00438 tx_dvdy = (tp_y - ((int32_t)(src->tx_pts[1] >> 8) << 16)); 00439 tx_dvdy = (tx_dvdy / tx_tall) << 8; 00440 ys = (p_y > (src->pts[1].y << 16)) ? 1 : -1; 00441 } 00442 00443 /* left-hand side */ 00444 for (x=src->pts[0].x; x<src->pts[1].x; x++) { 00445 int16_t pix_y = (y_top >> 16); 00446 int16_t bpix_y = (y_bot >> 16) + ys; /* make sure we include the bottom pixel */ 00447 int16_t y; 00448 int16_t tpix_y, tpix_x; 00449 00450 int32_t stx_y = tx_top_y; 00451 int32_t stx_x = tx_top_x; 00452 00453 y_top += dydx_ab; y_bot += dydx_ac; 00454 tx_top_x += dudx_ab; tx_top_y += dvdx_ab; 00455 tx_bot_x += dudx_ac; tx_bot_y += dvdx_ac; 00456 00457 if ((x < 0) || (x >= DISPLAY_WIDTH)) { 00458 continue; 00459 } 00460 00461 for (y=pix_y; y != bpix_y; y += ys) { 00462 if ((y < 0) || (y >= DISPLAY_HEIGHT)) { 00463 goto yl_loop_advance; 00464 } 00465 if (use_z > ZBUFFER (x, y)) { 00466 goto yl_loop_advance; 00467 } 00468 ZBUFFER (x, y) = use_z; 00469 00470 tpix_y = (stx_y >> 16) & (DISPLAY_HEIGHT - 1); 00471 tpix_x = (stx_x >> 16) & (DISPLAY_WIDTH - 1); 00472 00473 lcd.pixel_nochk_norm (x, y, g3d_texture_bit (src->txptr, tpix_x, tpix_y)); 00474 yl_loop_advance: 00475 stx_x += tx_dudy; 00476 stx_y += tx_dvdy; 00477 } 00478 } 00479 00480 y_top = (src->pts[1].y << 16) + 0x8000; 00481 tx_top_x = (src->tx_pts[1] & 0xff) << 16; 00482 tx_top_y = (src->tx_pts[1] >> 8) << 16; 00483 00484 /* right-hand side */ 00485 for (; x<src->pts[2].x; x++) { 00486 int16_t pix_y = (y_top >> 16); 00487 int16_t bpix_y = (y_bot >> 16) + ys; 00488 int16_t y; 00489 int16_t tpix_y, tpix_x; 00490 00491 int32_t stx_y = tx_top_y; 00492 int32_t stx_x = tx_top_x; 00493 00494 y_top += dydx_bc; y_bot += dydx_ac; 00495 tx_top_x += dudx_bc; tx_top_y += dvdx_bc; 00496 tx_bot_x += dudx_ac; tx_bot_y += dvdx_ac; 00497 00498 if ((x < 0) || (x >= DISPLAY_WIDTH)) { 00499 continue; 00500 } 00501 00502 for (y=pix_y; y != bpix_y; y += ys) { 00503 if ((y < 0) || (y >= DISPLAY_HEIGHT)) { 00504 goto yr_loop_advance; 00505 } 00506 if (use_z > ZBUFFER (x, y)) { 00507 goto yr_loop_advance; 00508 } 00509 ZBUFFER (x, y) = use_z; 00510 00511 tpix_y = (stx_y >> 16) & (DISPLAY_HEIGHT - 1); 00512 tpix_x = (stx_x >> 16) & (DISPLAY_WIDTH - 1); 00513 00514 lcd.pixel_nochk_norm (x, y, g3d_texture_bit (src->txptr, tpix_x, tpix_y)); 00515 00516 yr_loop_advance: 00517 stx_x += tx_dudy; 00518 stx_y += tx_dvdy; 00519 } 00520 } 00521 } 00522 00523 00524 /** 00525 * takes a polygon, drawing it on the given LCD with shading based on normal value. 00526 * 00527 * @param src Source polygon. 00528 * @param lcd Display LCD to use (size fixed in various places..). 00529 */ 00530 void gfx3d_polynormmap (const g3d_poly_t *src, C12832 &lcd) 00531 { 00532 /* assert: polygon points are in order left-to-right */ 00533 int16_t x, use_z = src->pts[0].z; 00534 int32_t dydx_ab, dydx_ac, dydx_bc; 00535 00536 if (src->pts[1].x > src->pts[0].x) { 00537 /* we have a left-hand side */ 00538 dydx_ab = ((src->pts[1].y - src->pts[0].y) << 16) / (src->pts[1].x - src->pts[0].x); 00539 } else { 00540 dydx_ab = 0; 00541 } 00542 if (src->pts[2].x > src->pts[0].x) { 00543 /* we have the long X edge */ 00544 dydx_ac = ((src->pts[2].y - src->pts[0].y) << 16) / (src->pts[2].x - src->pts[0].x); 00545 } else { 00546 dydx_ac = 0; 00547 } 00548 if (src->pts[2].x > src->pts[1].x) { 00549 /* we have a right-hand side */ 00550 dydx_bc = ((src->pts[2].y - src->pts[1].y) << 16) / (src->pts[2].x - src->pts[1].x); 00551 } else { 00552 dydx_bc = 0; 00553 } 00554 00555 /* Note: 00556 * - mostly 16.16 fixpoint stuff. 00557 * - could optimise more by better pixel plotting (directly into the buffer). 00558 */ 00559 00560 int32_t y_top = (src->pts[0].y << 16) + 0x8000; 00561 int32_t y_bot = (src->pts[0].y << 16) + 0x8000; 00562 int16_t ys; 00563 int32_t tx_ctemp, tx_tall, p_y; 00564 int bitstep = (32 - __CLZ (src->norm)) >> 2; 00565 int pcount = 0; 00566 00567 if (bitstep == 0) { 00568 bitstep = 1; 00569 } 00570 if (src->pts[2].x == src->pts[0].x) { 00571 /* skinny */ 00572 tx_ctemp = 0; 00573 } else { 00574 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) */ 00575 } 00576 00577 p_y = y_top + ((src->pts[2].y - src->pts[0].y) * tx_ctemp); 00578 tx_tall = abs ((p_y - (src->pts[1].y << 16)) >> 8); /* height of tallest scan -- positive 24.8 fixpoint */ 00579 00580 if (tx_tall == 0) { 00581 /* flat in effect */ 00582 ys = 1; 00583 } else { 00584 ys = (p_y > (src->pts[1].y << 16)) ? 1 : -1; 00585 } 00586 00587 /* left-hand side */ 00588 for (x=src->pts[0].x; x<src->pts[1].x; x++) { 00589 int16_t pix_y = (y_top >> 16); 00590 int16_t bpix_y = (y_bot >> 16) + ys; /* make sure we include the bottom pixel */ 00591 int16_t y; 00592 00593 y_top += dydx_ab; y_bot += dydx_ac; 00594 00595 if ((x < 0) || (x >= DISPLAY_WIDTH)) { 00596 continue; 00597 } 00598 00599 pcount = 0; 00600 for (y=pix_y; y != bpix_y; y += ys) { 00601 if ((y < 0) || (y >= DISPLAY_HEIGHT)) { 00602 continue; 00603 } 00604 if (use_z > ZBUFFER (x, y)) { 00605 continue; 00606 } 00607 ZBUFFER (x, y) = use_z; 00608 00609 lcd.pixel_nochk_norm (x, y, (pcount == 0) ? 1 : 0); 00610 if (!pcount) { 00611 pcount = bitstep; 00612 } 00613 pcount--; 00614 } 00615 } 00616 00617 y_top = (src->pts[1].y << 16) + 0x8000; 00618 00619 /* right-hand side */ 00620 for (; x<src->pts[2].x; x++) { 00621 int16_t pix_y = (y_top >> 16); 00622 int16_t bpix_y = (y_bot >> 16) + ys; 00623 int16_t y; 00624 00625 y_top += dydx_bc; y_bot += dydx_ac; 00626 00627 if ((x < 0) || (x >= DISPLAY_WIDTH)) { 00628 continue; 00629 } 00630 00631 pcount = 0; 00632 for (y=pix_y; y != bpix_y; y += ys) { 00633 if ((y < 0) || (y >= DISPLAY_HEIGHT)) { 00634 continue; 00635 } 00636 if (use_z > ZBUFFER (x, y)) { 00637 continue; 00638 } 00639 ZBUFFER (x, y) = use_z; 00640 00641 lcd.pixel_nochk_norm (x, y, (pcount == 0) ? 1 : 0); 00642 if (!pcount) { 00643 pcount = bitstep; 00644 } 00645 pcount--; 00646 } 00647 } 00648 } 00649 00650 00651 /** 00652 * takes an edge-buffer and draws its wireframe on the given LCD (start and end). 00653 */ 00654 void gfx3d_wireedge (const g3d_edgebuf_t *edge, C12832 &lcd) 00655 { 00656 int x; 00657 00658 if (edge->s_end == 1) { 00659 /* special case: vertical line */ 00660 int xp = edge->xoff; 00661 int y0 = edge->start[0]; 00662 int y1 = edge->end[0]; 00663 int ys = (y1 >= y0) ? 1 : -1; 00664 int y; 00665 00666 int16_t z0 = edge->zstart[0]; 00667 int16_t z1 = edge->zend[0]; 00668 int32_t zval = (z0 << 16) | 0x8000; /* half-way.. */ 00669 00670 if (xp >= DISPLAY_WIDTH) { 00671 /* off right-hand edge */ 00672 return; 00673 } else if (xp < 0) { 00674 /* off left-hand edge */ 00675 return; 00676 } 00677 00678 if ((y0 == y1) || ((y0 + ys) == y1)) { 00679 /* one or two point, since we're narrow, just y0 */ 00680 if (z0 <= ZBUFFER (xp, y0)) { 00681 ZBUFFER (xp, y0) = z0; 00682 lcd.pixel_nochk_norm (xp, y0, 1); 00683 } 00684 } else { 00685 /* long vertical poly, set all points except at y1 */ 00686 int32_t zdelta = ((int32_t)(z1 - z0) << 16) / (int32_t)(y1 - y0); 00687 int16_t rc_z = z0; 00688 00689 for (y = y0; y != y1; y += ys) { 00690 zval += zdelta; 00691 rc_z = (zval >> 16); 00692 if (rc_z <= ZBUFFER (xp, y)) { 00693 ZBUFFER (xp, y) = rc_z; 00694 lcd.pixel_nochk_norm (xp, y, 1); 00695 } 00696 } 00697 } 00698 return; 00699 } 00700 00701 for (x=0; x<edge->s_end; x++) { 00702 int xp = x + edge->xoff; 00703 int y0 = edge->start[x]; 00704 int y1 = edge->end[x]; 00705 int ys = (y1 >= y0) ? 1 : -1; 00706 int y; 00707 00708 int16_t z0 = edge->zstart[x]; 00709 int16_t z1 = edge->zend[x]; 00710 00711 int32_t zval = (z0 << 16) | 0x8000; /* half-way.. */ 00712 00713 if ((xp >= DISPLAY_WIDTH) || (xp < 0)) { 00714 continue; 00715 } 00716 00717 if (y0 == y1) { 00718 /* point, but we don't plot assuming it belongs to the adjoining polygon */ 00719 } else if ((y0 + ys) == y1) { 00720 /* two-point poly, just plot y0 */ 00721 if (z0 <= ZBUFFER (xp, y0)) { 00722 ZBUFFER (xp, y0) = z0; 00723 lcd.pixel_nochk_norm (xp, y0, 1); 00724 } 00725 } else { 00726 /* more than two points, shrink y1 to avoid plotting the last one here */ 00727 int32_t zdelta = ((int32_t)(z1 - z0) << 16) / (int32_t)(y1 - y0); 00728 int16_t rc_z = z0; 00729 00730 y1 -= ys; 00731 00732 /* start at y0 */ 00733 y = y0; 00734 if (rc_z <= ZBUFFER (xp, y)) { 00735 ZBUFFER (xp, y) = rc_z; 00736 lcd.pixel_nochk_norm (xp, y, 1); 00737 } 00738 00739 for (y += ys; y != y1; y += ys) { 00740 zval += zdelta; 00741 rc_z = (zval >> 16); 00742 if (rc_z <= ZBUFFER (xp, y)) { 00743 ZBUFFER (xp, y) = rc_z; 00744 lcd.pixel_nochk_norm (xp, y, 0); 00745 } 00746 } 00747 /* last pixel at y1,z1 */ 00748 rc_z = z1; 00749 if (rc_z <= ZBUFFER (xp, y1)) { 00750 ZBUFFER (xp, y1) = rc_z; 00751 lcd.pixel_nochk_norm (xp, y1, 1); 00752 } 00753 } 00754 00755 /* end of x-loop */ 00756 } 00757 } 00758
Generated on Wed Jul 13 2022 15:11:24 by 1.7.2