Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

zbf.cpp

Go to the documentation of this file.
00001 /*
00002 ** -------------------------------------------------------------------
00003 **
00004 ** zbf.cpp - Class to fill polygons in raster (image) coordinates
00005 **           using the z-buffer algorithm.
00006 **
00007 ** -------------------------------------------------------------------
00008 */
00009 
00038 /*
00039 ** -------------------------------------------------------------------
00040 ** Global variables and definitions:
00041 */
00042 #ifdef _UNIX_
00043 #include <memory.h>    /* function memset */
00044 #else
00045 #include <string.h>
00046 #endif
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 #include <math.h>
00050 
00051 #include "cd.h"
00052 #include "zbf.h"
00053 
00054 /*
00055 ** ---------------------------------------------------------------
00056 ** Initialization of class variables:
00057 */
00060 Zbf::NscPnt* Zbf::poly = NULL;
00061 
00064 int Zbf::sizepoly = 0;
00065 
00068 int Zbf::npolyverts = 0;
00069 
00072 Zbf::Edge* Zbf::poly_edge = NULL;
00073 
00076 Zbf::Pixel* Zbf::scanline_vtx = NULL;
00077 
00080 long int Zbf::curr_color = 0x0L;
00081 
00083 int Zbf::cv_width = 100;
00084 
00086 int Zbf::cv_height = 100;
00087 
00088 /* Memory for z-buffer */
00089 unsigned int* Zbf::zbuff = NULL;
00090 
00091 /*
00092 ** ---------------------------------------------------------------
00093 ** Private class functions:
00094 */
00095 /* =========================== Zbf::NSCtoRaster ======================== */
00096 
00097 void Zbf::NSCtoRaster( double xnsc, double ynsc, double znsc,
00098                        int* xr, int* yr, unsigned int* zr )
00099 {
00100  double zconvfac = (double)((UINT_MAX-1)/2);
00101  // UINT_MAX is the maximum unsigned int value
00102 
00103 /*** COMPLETE HERE: 20 ***/
00104
00105
00106 /*** COMPLETE HERE: 20 ***/
00107  *zr = (unsigned int)(zconvfac * (1.0 - znsc));
00108 
00109  if     ( *xr < 0 )            *xr = 0;
00110  else if( *xr > cv_width-1 )   *xr = cv_width-1;
00111  if     ( *yr < 0 )            *yr = 0;
00112  else if( *yr > cv_height-1 )  *yr = cv_height-1;
00113  if     ( *zr < 0 )            *zr = 0;
00114  else if( *zr > UINT_MAX )     *zr = UINT_MAX;
00115 }
00116 
00117 /* =======================  Zbf::OrderIntersections  ====================== */
00118 
00119 void Zbf::OrderIntersections( Zbf::Pixel* vtx, int left, int right )
00120 {
00121  int i, j;
00122  int mid;
00123  
00124  i = left;
00125  j = right;
00126  mid = vtx[(left + right) / 2].x;
00127  
00128  do
00129  {
00130   while( i < right && vtx[i].x < mid )
00131    i++;
00132   while( j > left && mid < vtx[j].x )
00133    j--;
00134   if( i <= j )
00135   {
00136    Pixel aux;
00137 
00138    aux = vtx[i];
00139    vtx[i] = vtx[j];
00140    vtx[j] = aux;
00141    i++;
00142    j--;
00143   }    
00144  } while( i <= j );
00145     
00146  if( left < j )
00147   OrderIntersections( vtx, left, j );
00148  if( i < right )
00149   OrderIntersections( vtx, i, right );
00150 }
00151 
00152 /* =========================  Zbf::ScanLine  ======================== */
00153 
00154 void Zbf::ScanLine( Zbf::Pixel* vtx_lft, Zbf::Pixel* vtx_rgt, int ys )
00155 {
00156  unsigned int offset;
00157  int    xl = vtx_lft->x + 1; /* Step over first point */
00158  int    xr = vtx_rgt->x;   
00159  int    dx = vtx_rgt->x - vtx_lft->x;
00160  double z  = vtx_lft->z;
00161  double dz;
00162  
00163  if( dx == 0 )
00164   return;
00165 
00166  dz = (vtx_rgt->z - vtx_lft->z) / dx;
00167  z += dz; /* Step over first point */
00168  offset = (unsigned int)( cv_width * ys );
00169 
00170  while( xl <= xr )
00171  {
00172   if( z >= zbuff[offset+xl] )
00173   {    
00174    int x0 = xl;
00175    do
00176    {
00177     zbuff[offset+xl] = (unsigned int)z;
00178     xl++;
00179     z += dz;
00180    } while( xl <= xr && z >= zbuff[offset+xl] );
00181    if( (xl-x0) == 1 )
00182     cdPixel( x0,  ys, curr_color );
00183    else
00184     cdLine( x0,  ys, xl-1, ys );
00185   }
00186   else
00187   {
00188    xl++;
00189    z += dz;
00190   }
00191  }
00192 }
00193 
00194 /* ========================  Zbf::MountEdges  ====================== */
00195 
00196 int Zbf::MountEdges( Zbf::Edge* edge, int* ymin, int* ymax, 
00197                      int npoints, Zbf::NscPnt *poly )
00198 {
00199  int i, nedges = 0;
00200  int x0, y0;
00201  unsigned int z0;
00202 
00203  NSCtoRaster(poly[0].x, poly[0].y, poly[0].z, &x0, &y0, &z0);
00204  *ymin = y0;
00205  *ymax = y0;
00206  for( i = 0; i < npoints; i++ )
00207  {
00208   int j = (i+1)%npoints;
00209   int xi, yi;
00210   unsigned int zi, zj;
00211   int xj, yj;
00212 
00213   NSCtoRaster( poly[i].x, poly[i].y, poly[i].z, &xi, &yi, &zi );
00214   NSCtoRaster( poly[j].x, poly[j].y, poly[j].z, &xj, &yj, &zj );
00215 
00216   if( yi != yj )
00217   {
00218    int dy = (yj - yi);
00219    edge[nedges].y_max = MAX(yi, yj);
00220    edge[nedges].y_min = MIN(yi, yj);
00221    edge[nedges].dxs = (double)(xj - xi) / dy;
00222    edge[nedges].dzs = (double)((double)zj - zi) / dy;
00223    if( edge[nedges].y_max == yi )
00224    {
00225     edge[nedges].xs = xi;
00226     edge[nedges].zs = zi;
00227    }
00228    else
00229    {
00230     edge[nedges].xs = xj;
00231     edge[nedges].zs = zj;
00232    }
00233    if( edge[nedges].y_max > *ymax )
00234     *ymax = edge[nedges].y_max;
00235    if( edge[nedges].y_min < *ymin )
00236     *ymin = edge[nedges].y_min;
00237    nedges++;
00238   }
00239  }
00240  return( nedges );
00241 }
00242 
00243 /* ========================  Zbf::MountInt  ======================== */
00244 
00245 int Zbf::MountInt( Zbf::Pixel* vtx, Zbf::Edge* edge, int* nedges, int ys )
00246 {
00247  int i, ninters = 0;
00248 
00249  for( i = 0; i < *nedges; i++ )
00250  {
00251   /* delete from edge list */
00252   if( edge[i].y_min > ys )
00253   {
00254    edge[i] = edge[*nedges-1];
00255    *nedges = *nedges-1;
00256   }
00257   /* intersection */
00258   if( (ys >= edge[i].y_min) && (ys < edge[i].y_max) )
00259   {
00260    /* update xs for this scanline */
00261    edge[i].xs -= edge[i].dxs;
00262    vtx[ninters].x = (int)edge[i].xs;
00263 
00264    /* update zs for this scanline */
00265    edge[i].zs -= edge[i].dzs;
00266    vtx[ninters].z = edge[i].zs;
00267 
00268    ninters++;
00269   }
00270  } 
00271  return( ninters );
00272 }
00273 
00274 /* ========================  Zbf::FillPoly  ======================== */
00275 
00276 void Zbf::FillPoly( int npoints, Zbf::NscPnt* poly )
00277 {
00278  static int   old_npts = 0;     /* number of points of last call */
00279  int          ymin, ymax;       /* polygon limits */
00280  int          nedges;           /* number of edges */
00281  int          ys;               /* current y coordinate of scanline */
00282  int          ninters;          /* number of intersections of scanline */
00283  int          i;
00284  
00285 /* Reallocation
00286  */
00287  if (npoints > old_npts)
00288  {
00289   old_npts = 0;
00290   if( scanline_vtx )
00291    free( scanline_vtx );
00292   if( poly_edge )
00293    free( poly_edge );
00294   scanline_vtx = (Pixel*)malloc( (npoints+1)*sizeof(Pixel) );
00295   poly_edge = (Edge*)malloc( (npoints+1)*sizeof(Edge) );
00296   if( !scanline_vtx || !poly_edge )
00297    return;
00298   old_npts = npoints;
00299  }
00300 
00301 /* Mount edge table
00302  */
00303  nedges = MountEdges( poly_edge, &ymin, &ymax, npoints, poly );
00304 
00305 /* Paint scanlines
00306  */
00307  for( ys = ymax; ys >= ymin; ys-- )
00308  {
00309   /* Mount intersection vector for current scanline */
00310   ninters = MountInt( scanline_vtx, poly_edge, &nedges, ys );
00311 
00312   /* Order intersection vector from left to right */
00313   OrderIntersections( scanline_vtx, 0, ninters-1 );
00314 
00315   /* Paint it */
00316   for( i = 0; i < ninters; i += 2 )
00317   {
00318    if( scanline_vtx[i].x < scanline_vtx[i+1].x )
00319    {
00320     ScanLine( &scanline_vtx[i], &scanline_vtx[i+1], ys );
00321    }
00322   }
00323  }
00324 }
00325 
00326 /* =======================  Zbf::Release  ======================= */
00327 
00328 void Zbf::Release( void )
00329 {
00330  if( zbuff )
00331   free( zbuff );
00332  zbuff = NULL;
00333 
00334  if( poly )
00335   free( poly );
00336  poly = NULL;
00337  sizepoly = 0;
00338  npolyverts = 0;
00339 }
00340 
00341 /* =======================  Zbf::Alloc  ========================= */
00342 
00343 int Zbf::Alloc( void  )
00344 {
00345  long int size = (long int)(cv_width*cv_height);
00346 
00347  Release( );
00348 
00349  zbuff = (unsigned int*)calloc( size, sizeof(unsigned int) );
00350  if( zbuff == NULL )
00351   return( 0 );
00352 
00353  sizepoly = 10;
00354  poly = (NscPnt *)calloc( sizepoly, sizeof(NscPnt) );
00355 
00356  return( 1 );
00357 }
00358 
00359 
00360 /*
00361 ** -------------------------------------------------------------------
00362 ** Public class functions:
00363 */
00364 
00365 /* =========================  Zbf::Init  ======================== */
00366 
00367 int Zbf::Init( int w, int h )
00368 {
00369  cv_width = w;
00370  cv_height = h;
00371  if( ! Alloc( ) )
00372   return( 0 );
00373 
00374 /* Clear zbuffer
00375  */
00376  memset( zbuff, 0, cv_width*cv_height*sizeof(unsigned int) );
00377 
00378  return( 1 );
00379 }
00380 
00381 /* ========================  Zbf::Close  ======================== */
00382 
00383 void Zbf::Close( void )
00384 {
00385  Release( );
00386  cv_width = 0;
00387  cv_height = 0;
00388 }
00389 
00390 /* ======================  Zbf::BeginPoly  ====================== */
00391 
00392 void Zbf::BeginPoly( long int color )
00393 {
00394  if( ! zbuff )
00395   return;
00396 
00397  curr_color = color;
00398  cdForeground( curr_color );
00399 
00400  npolyverts = 0;
00401 }
00402 
00403 /* =======================  Zbf::Vertex  ======================== */
00404 
00405 void Zbf::Vertex( double x, double y, double z )
00406 {
00407  if( ! zbuff )
00408   return;
00409 
00410  if( npolyverts == sizepoly )
00411  {
00412   sizepoly *= 2;
00413   poly = (NscPnt *)realloc( poly, sizepoly * sizeof(NscPnt) );
00414  }
00415 
00416  poly[npolyverts].x = x;
00417  poly[npolyverts].y = y;
00418  poly[npolyverts].z = z;
00419  npolyverts++;
00420 }
00421 
00422 /* =======================  Zbf::EndPoly  ======================= */
00423 
00424 void Zbf::EndPoly( void )
00425 {
00426  int  i;
00427 
00428 /* Verify whether one of the polygon vertex is outside 
00429  * the view volume.  If that is the case, reject the polygon.
00430  * This is necessary because the polygons are not being 
00431  * clipped against the view volume.
00432  * The z-buffer algorithm will not work for polygon points
00433  * outside the ranges of -1 to +1 of the normalize screen
00434  * coordinates.
00435  */
00436  for( i = 0; i < npolyverts; i++ )
00437  {
00438   if     ( poly[i].x < -1.0 )
00439    return;
00440   else if( poly[i].x >  1.0 )
00441    return;
00442   if     ( poly[i].y < -1.0 )
00443    return;
00444   else if( poly[i].y >  1.0 )
00445    return;
00446   if     ( poly[i].z < -1.0 )
00447    return;
00448   else if( poly[i].z >  1.0 )
00449    return;
00450  }
00451 
00452  FillPoly( npolyverts, poly );
00453 }
00454 

Generated on Mon Jun 21 12:45:12 2010 for Trab4 by  doxygen 1.4.2-20050421