00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00035
00036
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
00068 int i;
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;
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
00120
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
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
00275 FACE *theFace = &face;
00276 delete theFace;
00277 }
00278
00279 void
00280 ScanLineConverter::DrawWire(FACE &face)
00281 {
00282 MYPOINT *point;
00283
00284
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
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;
00307
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
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) {
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) {
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;
00339
00340
00341
00342 for (int ScanLine = Ymax; ScanLine >= Ymin; ScanLine--) {
00343
00344
00345
00346 FOR_EACH(Edge, ActiveEdges) {
00347 if (Edge->edge_YBot() > ScanLine)
00348 Edge = ActiveEdges.RemoveCurrent();
00349 else
00350 Edge->INCREMENT();
00351 }
00352
00353
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
00363 ActiveEdges.Resort();
00364
00365
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
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) {
00418
00419 if ((ScanLine == Edge1->edge_YTop()
00420 && ScanLine == Edge2->edge_YTop()) ||
00421 (ScanLine == Edge1->edge_YBot()
00422 && ScanLine == Edge2->edge_YBot()) )
00423
00424
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
00433 cnt += 2;
00434
00435 else
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 }