Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

zbf.c

Go to the documentation of this file.
00001 /*
00002 ** -------------------------------------------------------------------
00003 **
00004 ** zbf.c - Module to fill polygons in raster (image) coordinates
00005 **         using the z-buffer algorithm.
00006 **
00007 ** -------------------------------------------------------------------
00008 */
00009 
00041 /*
00042 ** -------------------------------------------------------------------
00043 ** Global variables and definitions:
00044 */
00045 #ifdef _UNIX_
00046 #include <memory.h>    /* function memset */
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 ** Local variables and definitions:
00060 */
00061 
00062 #ifndef UINT_MAX
00063 #define UINT_MAX      0xffffffff    /* maximum unsigned int value */
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 /* Memory for z-buffer */
00137 static unsigned *zbuff;
00138 
00139 
00140 /*
00141 ** -------------------------------------------------------------------
00142 ** Local functions:
00143 */
00144 
00145 /* =========================== zbfNSCtoRaster ======================== */
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 /*** COMPLETE HERE: 55 ***/
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 /* =======================  zbfOrderIntersections  ====================== */
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 /* =========================  zbfScanLine  ======================== */
00223 static void zbfScanLine( Pixel *vtx_lft, Pixel *vtx_rgt, int ys )
00224 {
00225  unsigned int offset;
00226  int    xl = vtx_lft->x + 1; /* Step over first point */
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; /* Step over first point */
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 /* ========================  zbfMountEdges  ====================== */
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 /* ========================  zbfMountInt  ======================== */
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   /* delete from edge list */
00324   if( edge[i].y_min > ys )
00325   {
00326    edge[i] = edge[*nedges-1];
00327    *nedges = *nedges-1;
00328   }
00329   /* intersection */
00330   if( (ys >= edge[i].y_min) && (ys < edge[i].y_max) )
00331   {
00332    /* update xs for this scanline */
00333    edge[i].xs -= edge[i].dxs;
00334    vtx[ninters].x = (int)edge[i].xs;
00335 
00336    /* update zs for this scanline */
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 /* ========================  zbfFillPoly  ======================== */
00354 static void zbfFillPoly( int npoints, NscPnt *poly )
00355 {
00356  static int   old_npts = 0;     /* number of points of last call */
00357  int          ymin, ymax;       /* polygon limits */
00358  int          nedges;           /* number of edges */
00359  int          ys;               /* current y coordinate of scanline */
00360  int          ninters;          /* number of intersections of scanline */
00361  int          i;
00362  
00363 /* Reallocation
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 /* Mount edge table
00380  */
00381  nedges = zbfMountEdges( poly_edge, &ymin, &ymax, npoints, poly );
00382 
00383 /* Paint scanlines
00384  */
00385  for( ys = ymax; ys >= ymin; ys-- )
00386  {
00387   /* Mount intersection vector for current scanline */
00388   ninters = zbfMountInt( scanline_vtx, poly_edge, &nedges, ys );
00389 
00390   /* Sort intersection vector */
00391   zbfOrderIntersections( scanline_vtx, 0, ninters-1 );
00392 
00393   /* Paint it */
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 /* =======================  zbfRelease  ======================= */
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 /* =======================  zbfAlloc  ========================= */
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 ** Public functions:
00441 */
00442 
00443 /* =========================  zbfInit  ======================== */
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 /* Clear zbuffer
00453  */
00454  memset( zbuff, 0, cv_width*cv_height*sizeof(unsigned) );
00455 
00456  return( 1 );
00457 }
00458 
00459 /* ========================  zbfClose  ======================== */
00460 
00461 void zbfClose( void )
00462 {
00463  zbfRelease( );
00464  cv_width = 0;
00465  cv_height = 0;
00466 }
00467 
00468 /* ======================  zbfBeginPoly  ====================== */
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 /* =======================  zbfVertex  ======================== */
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 /* =======================  zbfEndPoly  ======================= */
00501 
00502 void zbfEndPoly( void )
00503 {
00504  int  i;
00505 
00506 /* Verify whether one of the polygon vertex is outside 
00507  * the view volume.  If that is the case, reject the polygon.
00508  * This is necessary because the polygons are not being 
00509  * clipped against the view volume.
00510  * The z-buffer algorithm will not work for polygon points
00511  * outside the ranges of -1 to +1 of the normalize screen
00512  * coordinates.
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 

Generated on Tue Nov 8 10:58:00 2005 for Trab3 by doxygen1.2.18