00001
00002
00003
00004
00005
00006
00007
00008
00009
00041
00042
00043
00044
00045 #ifdef _UNIX_
00046 #include <memory.h>
00047 #else
00048 #include <string.h>
00049 #endif
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <math.h>
00053
00054 #include "cd.h"
00055 #include "zbf.h"
00056
00057
00058
00059
00060
00061
00062 #ifndef UINT_MAX
00063 #define UINT_MAX 0xffffffff
00064 #endif
00065
00066 #ifndef MAX
00067 #define MAX(a,b) (((a)>(b))?(a):(b))
00068 #endif
00069
00070 #ifndef MIN
00071 #define MIN(a,b) (((a)<(b))?(a):(b))
00072 #endif
00073
00076 typedef struct {
00077 double x, y, z;
00078 } NscPnt;
00079
00082 static NscPnt *zbf_poly = NULL;
00083
00086 static int sizepoly = 0;
00087
00090 static int npolyverts = 0;
00091
00094 typedef struct {
00096 int y_max;
00098 int y_min;
00100 double xs;
00102 double dxs;
00104 double zs;
00106 double dzs;
00107 } Edge;
00108
00111 static Edge *poly_edge = NULL;
00112
00115 typedef struct {
00117 int x;
00119 double z;
00120 } Pixel;
00121
00124 static Pixel *scanline_vtx = NULL;
00125
00128 static long int curr_color;
00129
00131 static int cv_width;
00132
00134 static int cv_height;
00135
00136
00137 static unsigned *zbuff;
00138
00139
00140
00141
00142
00143
00144
00145
00163 void zbfNSCtoRaster( double xnsc, double ynsc, double znsc,
00164 int *xr, int *yr, unsigned *zr )
00165 {
00166 double zconvfac = (double)((UINT_MAX-1)/2);
00167
00168
00169
00170 *zr = (unsigned)(zconvfac * (1.0 - znsc));
00171
00172 if ( *xr < 0 ) *xr = 0;
00173 else if( *xr > cv_width-1 ) *xr = cv_width-1;
00174 if ( *yr < 0 ) *yr = 0;
00175 else if( *yr > cv_height-1 ) *yr = cv_height-1;
00176 if ( *zr < 0 ) *zr = 0;
00177 else if( *zr > UINT_MAX ) *zr = UINT_MAX;
00178 }
00179
00180
00181
00182 static void zbfOrderIntersections( Pixel *vtx, int left, int right )
00183 {
00184 register int i, j;
00185 int mid;
00186
00187 i = left;
00188 j = right;
00189 mid = vtx[(left + right) / 2].x;
00190
00191 do
00192 {
00193 while( i < right && vtx[i].x < mid )
00194 i++;
00195 while( j > left && mid < vtx[j].x )
00196 j--;
00197 if( i <= j )
00198 {
00199 Pixel aux;
00200
00201 aux = vtx[i];
00202 vtx[i] = vtx[j];
00203 vtx[j] = aux;
00204 i++;
00205 j--;
00206 }
00207 } while( i <= j );
00208
00209 if( left < j )
00210 zbfOrderIntersections( vtx, left, j );
00211 if( i < right )
00212 zbfOrderIntersections( vtx, i, right );
00213 }
00214
00215
00223 static void zbfScanLine( Pixel *vtx_lft, Pixel *vtx_rgt, int ys )
00224 {
00225 unsigned int offset;
00226 int xl = vtx_lft->x + 1;
00227 int xr = vtx_rgt->x;
00228 int dx = vtx_rgt->x - vtx_lft->x;
00229 double z = vtx_lft->z;
00230 double dz;
00231
00232 if( dx == 0 )
00233 return;
00234
00235 dz = (vtx_rgt->z - vtx_lft->z) / dx;
00236 z += dz;
00237 offset = (unsigned int)( cv_width * ys );
00238
00239 while( xl <= xr )
00240 {
00241 if( z >= zbuff[offset+xl] )
00242 {
00243 int x0 = xl;
00244 do
00245 {
00246 zbuff[offset+xl] = (unsigned)z;
00247 xl++;
00248 z += dz;
00249 } while( xl <= xr && z >= zbuff[offset+xl] );
00250 if( (xl-x0) == 1 )
00251 cdPixel( x0, ys, curr_color );
00252 else
00253 cdLine( x0, ys, xl-1, ys );
00254 }
00255 else
00256 {
00257 xl++;
00258 z += dz;
00259 }
00260 }
00261 }
00262
00263
00267 static int zbfMountEdges( Edge *edge, int *ymin, int *ymax,
00268 int npoints, NscPnt *poly )
00269 {
00270 int i, nedges = 0;
00271 int x0, y0;
00272 unsigned z0;
00273
00274 zbfNSCtoRaster(poly[0].x, poly[0].y, poly[0].z, &x0, &y0, &z0);
00275 *ymin = y0;
00276 *ymax = y0;
00277 for( i = 0; i < npoints; i++ )
00278 {
00279 int j = (i+1)%npoints;
00280 int xi, yi;
00281 unsigned zi, zj;
00282 int xj, yj;
00283
00284 zbfNSCtoRaster( poly[i].x, poly[i].y, poly[i].z, &xi, &yi, &zi );
00285 zbfNSCtoRaster( poly[j].x, poly[j].y, poly[j].z, &xj, &yj, &zj );
00286
00287 if( yi != yj )
00288 {
00289 int dy = (yj - yi);
00290 edge[nedges].y_max = MAX(yi, yj);
00291 edge[nedges].y_min = MIN(yi, yj);
00292 edge[nedges].dxs = (double)(xj - xi) / dy;
00293 edge[nedges].dzs = (double)((double)zj - zi) / dy;
00294 if( edge[nedges].y_max == yi )
00295 {
00296 edge[nedges].xs = xi;
00297 edge[nedges].zs = zi;
00298 }
00299 else
00300 {
00301 edge[nedges].xs = xj;
00302 edge[nedges].zs = zj;
00303 }
00304 if( edge[nedges].y_max > *ymax )
00305 *ymax = edge[nedges].y_max;
00306 if( edge[nedges].y_min < *ymin )
00307 *ymin = edge[nedges].y_min;
00308 nedges++;
00309 }
00310 }
00311 return( nedges );
00312 }
00313
00314
00318 static int zbfMountInt( Pixel *vtx, Edge *edge, int *nedges, int ys )
00319 {
00320 int i, ninters = 0;
00321 for( i = 0; i < *nedges; i++ )
00322 {
00323
00324 if( edge[i].y_min > ys )
00325 {
00326 edge[i] = edge[*nedges-1];
00327 *nedges = *nedges-1;
00328 }
00329
00330 if( (ys >= edge[i].y_min) && (ys < edge[i].y_max) )
00331 {
00332
00333 edge[i].xs -= edge[i].dxs;
00334 vtx[ninters].x = (int)edge[i].xs;
00335
00336
00337 edge[i].zs -= edge[i].dzs;
00338 vtx[ninters].z = edge[i].zs;
00339
00340 ninters++;
00341 }
00342 }
00343 return( ninters );
00344 }
00345
00346
00354 static void zbfFillPoly( int npoints, NscPnt *poly )
00355 {
00356 static int old_npts = 0;
00357 int ymin, ymax;
00358 int nedges;
00359 int ys;
00360 int ninters;
00361 int i;
00362
00363
00364
00365 if (npoints > old_npts)
00366 {
00367 old_npts = 0;
00368 if( scanline_vtx )
00369 free( scanline_vtx );
00370 if( poly_edge )
00371 free( poly_edge );
00372 scanline_vtx = (Pixel*)malloc( (npoints+1)*sizeof(Pixel) );
00373 poly_edge = (Edge*)malloc( (npoints+1)*sizeof(Edge) );
00374 if( !scanline_vtx || !poly_edge )
00375 return;
00376 old_npts = npoints;
00377 }
00378
00379
00380
00381 nedges = zbfMountEdges( poly_edge, &ymin, &ymax, npoints, poly );
00382
00383
00384
00385 for( ys = ymax; ys >= ymin; ys-- )
00386 {
00387
00388 ninters = zbfMountInt( scanline_vtx, poly_edge, &nedges, ys );
00389
00390
00391 zbfOrderIntersections( scanline_vtx, 0, ninters-1 );
00392
00393
00394 for( i = 0; i < ninters; i += 2 )
00395 {
00396 if( scanline_vtx[i].x < scanline_vtx[i+1].x )
00397 {
00398 zbfScanLine( &scanline_vtx[i], &scanline_vtx[i+1], ys );
00399 }
00400 }
00401 }
00402 }
00403
00404
00405
00406 static void zbfRelease( void )
00407 {
00408 if( zbuff )
00409 free( zbuff );
00410 zbuff = NULL;
00411
00412 if( zbf_poly )
00413 free( zbf_poly );
00414 zbf_poly = NULL;
00415 sizepoly = 0;
00416 npolyverts = 0;
00417 }
00418
00419
00420
00421 static int zbfAlloc( void )
00422 {
00423 long int size = (long int)(cv_width*cv_height);
00424
00425 zbfRelease( );
00426
00427 zbuff = (unsigned *)calloc( size, sizeof(unsigned) );
00428 if( zbuff == NULL )
00429 return( 0 );
00430
00431 sizepoly = 10;
00432 zbf_poly = (NscPnt *)calloc( sizepoly, sizeof(NscPnt) );
00433
00434 return( 1 );
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 int zbfInit( int w, int h )
00446 {
00447 cv_width = w;
00448 cv_height = h;
00449 if( ! zbfAlloc( ) )
00450 return( 0 );
00451
00452
00453
00454 memset( zbuff, 0, cv_width*cv_height*sizeof(unsigned) );
00455
00456 return( 1 );
00457 }
00458
00459
00460
00461 void zbfClose( void )
00462 {
00463 zbfRelease( );
00464 cv_width = 0;
00465 cv_height = 0;
00466 }
00467
00468
00469
00470 void zbfBeginPoly( long int color )
00471 {
00472 if( ! zbuff )
00473 return;
00474
00475 curr_color = color;
00476 cdForeground( curr_color );
00477
00478 npolyverts = 0;
00479 }
00480
00481
00482
00483 void zbfVertex( double x, double y, double z )
00484 {
00485 if( ! zbuff )
00486 return;
00487
00488 if( npolyverts == sizepoly )
00489 {
00490 sizepoly *= 2;
00491 zbf_poly = (NscPnt *)realloc( zbf_poly, sizepoly * sizeof(NscPnt) );
00492 }
00493
00494 zbf_poly[npolyverts].x = x;
00495 zbf_poly[npolyverts].y = y;
00496 zbf_poly[npolyverts].z = z;
00497 npolyverts++;
00498 }
00499
00500
00501
00502 void zbfEndPoly( void )
00503 {
00504 int i;
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 for( i = 0; i < npolyverts; i++ )
00515 {
00516 if ( zbf_poly[i].x < -1.0 )
00517 return;
00518 else if( zbf_poly[i].x > 1.0 )
00519 return;
00520 if ( zbf_poly[i].y < -1.0 )
00521 return;
00522 else if( zbf_poly[i].y > 1.0 )
00523 return;
00524 if ( zbf_poly[i].z < -1.0 )
00525 return;
00526 else if( zbf_poly[i].z > 1.0 )
00527 return;
00528 }
00529
00530 zbfFillPoly( npolyverts, zbf_poly );
00531 }
00532
00534 ew volume.
00535 * The z-buffer algorithm will not work for polygon points
00536 * outside the ranges of -1 to +1 of the normalize screen
00537 * coordinates.
00538 */
00539 for( i = 0; i < npolyverts; i++ )
00540 {
00541 if ( zbf_poly[i].x < -1.0 )
00542 return;
00543 else if( zbf_poly[i].x > 1.0 )
00544 return;
00545 if ( zbf_poly[i].y < -1.0 )
00546 return;
00547 else if( zbf_poly[i].y > 1.0 )
00548 return;
00549 if ( zbf_poly[i].z < -1.0 )
00550 return;
00551 else if( zbf_poly[i].z > 1.0 )
00552 return;
00553 }
00554
00555 zbfFillPoly( npolyverts, zbf_poly );
00556 }
00557