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

Generated on Mon Jun 20 18:09:52 2011 for Trab8 by  doxygen 1.4.2-20050421