Scan.cpp

Go to the documentation of this file.
00001 /* ****************************************************************** **
00002 **    OpenSees - Open System for Earthquake Engineering Simulation    **
00003 **          Pacific Earthquake Engineering Research Center            **
00004 **                                                                    **
00005 **                                                                    **
00006 ** (C) Copyright 1999, The Regents of the University of California    **
00007 ** All Rights Reserved.                                               **
00008 **                                                                    **
00009 ** Commercial use of this program without express permission of the   **
00010 ** University of California, Berkeley, is strictly prohibited.  See   **
00011 ** file 'COPYRIGHT'  in main directory for information on usage and   **
00012 ** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
00013 **                                                                    **
00014 ** Developed by:                                                      **
00015 **   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
00016 **   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
00017 **   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
00018 **                                                                    **
00019 ** ****************************************************************** */
00020                                                                         
00021 // $Revision: 1.2 $
00022 // $Date: 2003/02/14 23:01:58 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/renderer/Scan.cpp,v $
00024                                                                         
00025                                                                         
00026 #include <math.h>
00027 #include <limits.h>
00028 #include <stdlib.h>
00029 
00030 #include "Scan.h"
00031 #include "Device.h"
00032 #include "Projection.h"
00033 
00034 // #define DEBUG_SCAN
00035 
00036 /*** NOTE:: device.ENDIMAGE(); *****/
00037 
00038 ScanLineConverter::ScanLineConverter()
00039 :zBuffer(0), sizeBuffer(0)
00040 {
00041   scanMode = WINDING;
00042   fillMode = 1;
00043 }
00044 
00045 ScanLineConverter::~ScanLineConverter()
00046 {
00047   if (zBuffer != 0)
00048       delete [] zBuffer;
00049 }
00050 
00051 void 
00052 ScanLineConverter::setScanMode(int mode)
00053  {
00054   scanMode = mode;
00055 }
00056 
00057 void 
00058 ScanLineConverter::setFillMode(int mode)
00059 {
00060   fillMode = mode;
00061 }
00062 
00063 
00064 int
00065 ScanLineConverter::update(void)
00066 {
00067      // first set the zbuffer
00068      int i;// j;
00069      
00070      length = theDevice->GetHeight(); 
00071      width = theDevice->GetWidth();
00072 
00073      int size = length*width;
00074      if (size != sizeBuffer) {
00075          if (zBuffer != 0)
00076              delete [] zBuffer;
00077          zBuffer = new float[size];
00078        if (zBuffer == 0) {
00079          opserr << "ScanLineConverter::update() - out of memory\n";
00080          return -1;
00081        }
00082        sizeBuffer = size;
00083      }
00084 
00085      for (i=0; i<length*width; i++)
00086        zBuffer[i] = -2; // we have clipped out all from 0 -2
00087 
00088     return 0;
00089 }
00090 
00091 
00092 void
00093 ScanLineConverter::scanLine(FACE &face)
00094 {
00095 #ifdef _UNIX
00096     MYPOINT *point1 = face.pointList.GetHead();
00097     if (point1 != 0) {
00098         if (fillMode == 1) {
00099             DrawWire(face);
00100         } else {
00101             MYPOINT *point1 = face.pointList.SetToHead();       
00102         MYPOINT *point2 = face.pointList.Forward();     
00103 
00104             if (point2 != 0) {
00105                 int x1 = (int)point1->X();
00106                 int y1 = (int)point1->Y();    
00107                 float zCur = point1->Z();           
00108                 float rCur = point1->r;
00109                 float gCur = point1->g;
00110                 float bCur = point1->b;
00111 
00112                 int x2 = (int)point2->X();
00113                 int y2 = (int)point2->Y();      
00114                 float z2 = point2->Z();                     
00115                 float r2 = point2->r;
00116                 float g2 = point2->g;
00117                 float b2 = point2->b;       
00118                 /*
00119                 rCur = 1.0; gCur = 0; bCur = 0;
00120                 r2 = 0; g2 = 0; b2 = 1;
00121                 */
00122                 int dx = x2 - x1;
00123                 int dy = y2 - y1;
00124                 float dz = z2 - zCur;
00125                 float dr = r2 -rCur;
00126                 float dg = g2 -gCur;
00127                 float db = b2 -bCur;
00128                 
00129                 if (dx == 0 && dy == 0) {
00130                     ;
00131                 } else if (dx == 0) {
00132                     int L = dy;
00133                     if (L < 0) L = -L;
00134                     dz = dz/L; dr = dr/L; dg = dg/L; db = db/L;
00135                     if (y1 < y2) { 
00136                         for (int y=y1; y<=y2; y++) {
00137                             if (zBuffer[x1+width*y] < zCur) {
00138                                 theDevice->C3F(rCur, gCur, bCur);
00139                                 zBuffer[x1+width*y] = zCur;
00140                                 theDevice->V2F(x1,y);
00141                             }
00142                             zCur += dz;
00143                             rCur += dr;
00144                             gCur += dg;
00145                             bCur += db;
00146                         }
00147                     } else {
00148                         for (int y=y1; y>=y2; y--) {
00149                             if (zBuffer[x1+width*y] < zCur) {
00150                                 theDevice->C3F(rCur, gCur, bCur);
00151                                 zBuffer[x1+width*y] = zCur;
00152                                 theDevice->V2F(x1,y);
00153                             }
00154                             zCur += dz;
00155                             rCur += dr;
00156                             gCur += dg;
00157                             bCur += db;
00158                         }
00159                     }
00160                         
00161                 } else if (dy == 0) {
00162                     int L = dx;
00163                     if (L < 0) L = -L;
00164                     dz = dz/L; dr = dr/L; dg = dg/L; db = db/L;
00165                     if (x1 < x2) {
00166                         for (int x=x1; x<=x2; x++) {
00167                             if (zBuffer[x+width*y1] < zCur) {
00168                                 theDevice->C3F(rCur, gCur, bCur);
00169                                 zBuffer[x+width*y1] = zCur;
00170                                 theDevice->V2F(x,y1);
00171                             }
00172                             zCur += dz;
00173                             rCur += dr;
00174                             gCur += dg;
00175                             bCur += db;
00176                         } 
00177                     } else {
00178                         for (int x=x1; x>=x2; x--) {
00179                             if (zBuffer[x+width*y1] < zCur) {
00180                                 theDevice->C3F(rCur, gCur, bCur);
00181                                 zBuffer[x+width*y1] = zCur;
00182                                 theDevice->V2F(x,y1);
00183                             }
00184                             zCur += dz;
00185                             rCur += dr;
00186                             gCur += dg;
00187                             bCur += db;
00188                         } 
00189                     }                   
00190                 } else {
00191                     float yCur = point1->Y();
00192                     float xCur = point1->X(); 
00193                     float dx = (point2->X() -xCur);
00194                     float dy = (point2->Y() -yCur);
00195                     float length = sqrt(dx*dx + dy*dy);
00196                     dx /= length;
00197                     dy /= length;
00198                     int L = (int)length;
00199                     dz = dz/length; dr = dr/length; dg = dg/length; db = db/length;
00200                     for (int l=0; l<L; l++) {
00201                         int x = (int)xCur;
00202                         int y = (int)yCur;                          
00203                         if (zBuffer[x+width*y] < zCur) {
00204                             theDevice->C3F(rCur, gCur, bCur);
00205                             zBuffer[x+width*y] = zCur;
00206                             theDevice->V2F(x,y);
00207                         }
00208                         xCur += dx;
00209                         yCur += dy;                         
00210                         zCur += dz;
00211                         rCur += dr;
00212                         gCur += dg;
00213                         bCur += db;
00214                     }
00215                 }
00216             }
00217         }
00218     }
00219 #else
00220  MYPOINT *point1 = face.pointList.GetHead();
00221     if (point1 != 0) {
00222         if (fillMode == 1) {
00223             DrawWire(face);
00224         } else {
00225             MYPOINT *point1 = face.pointList.SetToHead();       
00226         MYPOINT *point2 = face.pointList.Forward();     
00227 
00228             if (point2 != 0) {
00229                 int x1 = (int)point1->X();
00230                 int y1 = (int)point1->Y();    
00231                 float zCur = point1->Z();           
00232                 float rCur = point1->r;
00233                 float gCur = point1->g;
00234                 float bCur = point1->b;
00235 
00236                 int x2 = (int)point2->X();
00237                 int y2 = (int)point2->Y();      
00238                 float z2 = point2->Z();                     
00239                 float r2 = point2->r;
00240                 float g2 = point2->g;
00241                 float b2 = point2->b;
00242                                 
00243  
00244   
00245   theDevice->BGNCLOSEDLINE();
00246   theDevice->C3F(rCur,gCur,bCur);
00247   theDevice->V2F(x1,y1);
00248   theDevice->C3F(r2,g2,b2);
00249   theDevice->V2F(x2,y2);
00250   theDevice->ENDCLOSEDLINE();
00251                 }
00252         }
00253         }
00254   
00255 
00256 #endif
00257 
00258     // now we delete the face
00259     FACE *theFace = &face;
00260     delete theFace;
00261 }
00262 
00263 void
00264 ScanLineConverter::scanPolygon(FACE &face)
00265 {
00266   MYPOINT *point = face.pointList.GetHead();
00267   if (point != 0) {
00268     if (fillMode == 1) {
00269       DrawWire(face);
00270     } else 
00271       DrawFill(face);
00272   }    
00273   
00274   // now we delete the face
00275   FACE *theFace = &face;
00276   delete theFace;
00277 }
00278 
00279 void
00280 ScanLineConverter::DrawWire(FACE &face)
00281 {
00282   MYPOINT *point;
00283 
00284   // set the color of wire to rgb of first point
00285   point = face.pointList.GetHead();
00286   theDevice->C3F(point->r, point->g, point->b);
00287 
00288   theDevice->BGNCLOSEDLINE();
00289   FOR_EACH(point, face.pointList)
00290     {
00291       theDevice->V2F(point->X(), point->Y());
00292     }
00293   theDevice->ENDCLOSEDLINE();
00294 }
00295   
00296 
00297 LIST<EDGE> FaceEdges(ORDER_DECREASING);
00298 LIST<EDGE> ActiveEdges(ORDER_INCREASING);
00299   
00300 void
00301 ScanLineConverter::DrawFill(FACE &face)
00302 {
00303 //  MYPOINT *point;
00304   int y1, y2, cnt, slope;
00305   int Ymax, Ymin, Pixel, xleft, xright, dX;
00306   float Rcur, Gcur, Bcur, Zcur, dR_dX, dG_dX, dB_dX, dZ_dX;// Zfar;
00307 //  float R,G,B,r1,g1,b1,r2,g2,b2,ka,kd,r,g,b,Iar,Iag,Iab,DotLN,N;
00308   MYPOINT *Point1, *Point2;
00309   EDGE *Edge, *Edge1, *Edge2;
00310 
00311   Ymax = 0;
00312   Ymin = 1000000; 
00313 
00314   FaceEdges.Clear();
00315   ActiveEdges.Clear();
00316 
00317   // for each pair of vertices create an edge and add to list of face edges
00318   FOR_EACH_PAIR(Point1,Point2,face.pointList,{
00319      y1 = (int)Point1->Y();
00320      y2 = (int)Point2->Y();
00321      if (y1 > y2) {
00322         if ((y1-1) >= y2) {  // only add if it will be drawn
00323            Edge = new EDGE(Point1, Point2, 1);
00324            FaceEdges.AddSorted(*Edge, &Edge->Y_Top);
00325            if (y1 > Ymax) Ymax = y1;
00326            if (y2 < Ymin) Ymin = y2;
00327         }
00328      }
00329      else 
00330         if ((y2-1) >= y1) {   // only add if it will be drawn
00331            Edge = new EDGE(Point2, Point1, -1);
00332            FaceEdges.AddSorted(*Edge, &Edge->Y_Top);
00333            if (y2 > Ymax) Ymax = y2;
00334            if (y1 < Ymin) Ymin = y1;
00335           }
00336    });
00337 
00338    Ymax = Ymax - 1; // we start 1 scan line down          
00339 
00340    // now for each scanline determine which pixels should be off and 
00341    // which should be on
00342    for (int ScanLine = Ymax; ScanLine >= Ymin; ScanLine--) {
00343 
00344      // for each edge on active list increment the attributes & check 
00345      // if it should still be there
00346      FOR_EACH(Edge, ActiveEdges) {  
00347        if (Edge->edge_YBot() > ScanLine)  
00348          Edge = ActiveEdges.RemoveCurrent();
00349        else
00350          Edge->INCREMENT(); 
00351      }  
00352 
00353      // remove edges from faceedge list if it should be in active edges
00354      FOR_EACH(Edge, FaceEdges) {
00355        if (Edge->edge_YTop() > ScanLine) {
00356          Edge = FaceEdges.RemoveCurrent();
00357          
00358          ActiveEdges.AddSorted(*Edge, &Edge->X_Cur);
00359        }
00360      }
00361 
00362      // resort the edges on the active list
00363      ActiveEdges.Resort();
00364 
00365      // if WINDING we must ensure if at bottom edges sorted also by slope
00366      if (scanMode == WINDING) {
00367        FOR_EACH_PAIR(Edge1, Edge2, ActiveEdges, {
00368          if ((ScanLine == Edge1->edge_YBot())
00369               && (ScanLine == Edge2->edge_YBot())
00370               && (Edge1->edge_Xcur() == Edge2->edge_Xcur()))
00371              
00372              if (Edge1->edge_Slope() == 1) {
00373                Edge1->edge_SlopeSet(-1);
00374                Edge2->edge_SlopeSet(1);
00375              }
00376        });
00377      }
00378 
00379      // now go across
00380      cnt = 0; slope = 0;
00381      FOR_EACH_PAIR(Edge1, Edge2, ActiveEdges, {
00382        xleft = Edge1->edge_Xcur();
00383        xright = Edge2->edge_Xcur();
00384        slope = slope + Edge1->edge_Slope() + Edge2->edge_Slope();
00385 
00386        if (xleft < xright) {
00387 
00388          cnt++;
00389          if (((cnt%2) == 1) || (scanMode == WINDING && slope != 0)) {
00390 
00391            Zcur = Edge1->edge_Zcur();
00392            Rcur = Edge1->edge_Rcur();
00393            Gcur = Edge1->edge_Gcur();
00394            Bcur = Edge1->edge_Bcur();
00395            dX = xleft - xright;
00396            dZ_dX = (Zcur - Edge2->edge_Zcur()) / dX;
00397            dR_dX = (Rcur - Edge2->edge_Rcur()) / dX;
00398            dB_dX = (Bcur - Edge2->edge_Bcur()) / dX;
00399            dG_dX = (Gcur - Edge2->edge_Gcur()) / dX;
00400 
00401            theDevice->BGNPOINT();
00402            for (Pixel = xleft; Pixel < xright; Pixel++) {
00403              if (zBuffer[Pixel+width*ScanLine] < Zcur) {
00404                theDevice->C3F(Rcur, Gcur, Bcur);
00405                zBuffer[Pixel+width*ScanLine] = Zcur;
00406                theDevice->V2F(Pixel,ScanLine);
00407              }
00408              Zcur += dZ_dX;
00409              Rcur += dR_dX;
00410              Gcur += dG_dX;
00411              Bcur += dB_dX;
00412            }
00413            theDevice->ENDPOINT();
00414          }
00415        }           
00416 
00417        else if (xleft == xright) {  // crossing edges or a vertex
00418 
00419          if ((ScanLine == Edge1->edge_YTop() 
00420               && ScanLine == Edge2->edge_YTop()) || 
00421              (ScanLine == Edge1->edge_YBot() 
00422               && ScanLine == Edge2->edge_YBot())  )
00423 
00424            // meeting vertices top or bottom -- for even odd count as 2
00425            cnt += 1;
00426 
00427          else if ((ScanLine == Edge1->edge_YTop() 
00428                    && ScanLine == Edge2->edge_YBot()) || 
00429                   (ScanLine == Edge1->edge_YBot() 
00430                    && ScanLine == Edge2->edge_YTop())   )
00431 
00432            // meeting vertices, one top one bottom -- for even odd count as 1
00433            cnt += 2;
00434 
00435          else   // crossing edges
00436            cnt += 1;
00437        }
00438      });
00439    }
00440 }
00441 
00442   
00443 void
00444 ScanLineConverter::setDevice(Device &device)
00445 {
00446     theDevice = &device;
00447 }
00448 
00449   
00450 void
00451 ScanLineConverter::setProjection(Projection &projection)
00452 {
00453     theProjection = &projection;
00454 }

Generated on Mon Oct 23 15:05:27 2006 for OpenSees by doxygen 1.5.0