1
/****************************************************************************
2
* PROJECT: Balloon 3D Graphics Subsystem for Squeak
4
* CONTENT: Main rasterizer body
6
* AUTHOR: Andreas Raab (ar)
7
* ADDRESS: Walt Disney Imagineering, Glendale, CA
8
* EMAIL: andreasr@wdi.disney.com
9
* RCSID: $Id: b3dMain.c 2 2001-10-24 23:11:49Z rowledge $
14
*****************************************************************************/
15
#include <stdio.h> /* printf() */
16
#include <stdlib.h> /* exit() */
17
#include <assert.h> /* assert() */
21
#define NULL ((void*)0)
25
unsigned int b3dObjSetupTime;
26
unsigned int b3dMapObjectTime;
27
unsigned int b3dVertexOrderTime;
28
unsigned int b3dSortFaceTime;
32
#define rasterPosX rasterPos[0]
33
#define rasterPosY rasterPos[1]
34
#define rasterPosZ rasterPos[2]
35
#define rasterPosW rasterPos[3]
37
#define windowPosX windowPos[0]
38
#define windowPosY windowPos[1]
40
#define texCoordS texCoord[0]
41
#define texCoordT texCoord[1]
43
#define redValue cc.color[RED_INDEX]
44
#define greenValue cc.color[GREEN_INDEX]
45
#define blueValue cc.color[BLUE_INDEX]
46
#define alphaValue cc.color[ALPHA_INDEX]
49
B3DRasterizerState *currentState;
51
B3DActiveEdgeTable *aet;
52
B3DPrimitiveEdgeList *addedEdges;
54
B3DEdgeAllocList *edgeAlloc;
55
B3DFaceAllocList *faceAlloc;
56
B3DAttrAllocList *attrAlloc;
61
/*************************************************************/
62
/*************************************************************/
63
/*************************************************************/
65
void b3dAbort(char *msg){
70
void b3dValidateEdgeOrder(B3DPrimitiveEdgeList *list)
75
if(list->data[0]->leftFace == list->data[0]->rightFace) {
76
b3dAbort("Left face == right face");
78
for(i=1; i<list->size; i++) {
79
if(list->data[i-1]->xValue > list->data[i]->xValue) {
80
b3dAbort("Edge list is broken");
82
if(list->data[i]->leftFace == list->data[i]->rightFace) {
83
b3dAbort("Left face == right face");
88
void b3dValidateAETOrder(B3DActiveEdgeTable *list)
93
if(list->data[0]->leftFace == list->data[0]->rightFace) {
94
b3dAbort("Left face == right face");
96
for(i=1; i<list->size; i++) {
97
if(list->data[i-1]->xValue > list->data[i]->xValue) {
98
b3dAbort("Edge list is broken");
100
if(list->data[i]->leftFace == list->data[i]->rightFace) {
101
b3dAbort("Left face == right face");
106
/*************************************************************/
107
/*************************************************************/
108
/*************************************************************/
109
/* b3dInitializeFace:
110
Allocate a new primitive face based on the given vertices.
111
Do the necessary initial setup, but don't set up any drawing attributes yet.
112
Return the newly created face.
113
NOTE: May cause allocation of one face!
115
B3DPrimitiveFace *b3dInitializeFace(B3DPrimitiveVertex *v0,
116
B3DPrimitiveVertex *v1,
117
B3DPrimitiveVertex *v2,
121
B3DPrimitiveFace *face;
123
/* Compute major and minor reference edges */
125
float majorDx = v2->rasterPosX - v0->rasterPosX;
126
float majorDy = v2->rasterPosY - v0->rasterPosY;
127
float minorDx = v1->rasterPosX - v0->rasterPosX;
128
float minorDy = v1->rasterPosY - v0->rasterPosY;
129
float area = (majorDx * minorDy) - (minorDx * majorDy);
131
if(area > -0.001 && area < 0.001) return NULL;
132
/* Now that we know the face is valid, do the actual allocation */
133
b3dAllocFace(faceAlloc, face);
136
if(!face) b3dAbort("Face allocation failed");
141
face->leftEdge = NULL;
142
face->rightEdge = NULL;
143
face->attributes = NULL;
144
face->oneOverArea = (float) (1.0 / area);
145
face->majorDx = majorDx;
146
face->majorDy = majorDy;
147
face->minorDx = minorDx;
148
face->minorDy = minorDy;
149
face->texture = texture;
150
face->flags |= attrFlags & (B3D_ATTR_MASK << B3D_ATTR_SHIFT);
152
{ /* Compute dzdx and dzdy */
153
float majorDz = v2->rasterPosZ - v0->rasterPosZ;
154
float minorDz = v1->rasterPosZ - v0->rasterPosZ;
156
face->dzdx = face->oneOverArea * ((majorDz * minorDy) - (minorDz * majorDy));
157
face->dzdy = face->oneOverArea * ((majorDx * minorDz) - (minorDx * majorDz));
161
{/* Compute minZ/maxZ */
162
float z0 = v0->rasterPosZ;
163
float z1 = v1->rasterPosZ;
164
float z2 = v2->rasterPosZ;
169
} else if(z0 <= z2) {
176
} else if(z2 <= z1) {
179
} else if(z0 <= z2) {
186
} /* End of minZ/maxZ */
191
/* b3dInitializePass2:
192
Do a second initialization pass if the face is known to be visible.
194
int b3dInitializePass2(B3DPrimitiveFace *face)
196
double majorDv, minorDv, baseValue;
198
B3DPrimitiveAttribute *attr;
199
B3DPrimitiveVertex *v0 = face->v0;
200
B3DPrimitiveVertex *v1 = face->v1;
201
B3DPrimitiveVertex *v2 = face->v2;
205
b3dAllocAttrib(attrAlloc, face, ok);
206
if(!ok) return 0; /* NOT initalized */
209
attr = face->attributes;
212
if(face->flags & B3D_FACE_RGB) {
213
/* Setup RGB interpolation */
214
majorDv = v2->redValue - v0->redValue;
215
minorDv = v1->redValue - v0->redValue;
216
dvdx = face->oneOverArea * ((majorDv * face->minorDy) - (minorDv * face->majorDy));
217
dvdy = face->oneOverArea * ((minorDv * face->majorDx) - (majorDv * face->minorDx));
218
attr->value = (float) v0->redValue;
219
attr->dvdx = (float) dvdx;
220
attr->dvdy = (float) dvdy;
223
majorDv = v2->greenValue - v0->greenValue;
224
minorDv = v1->greenValue - v0->greenValue;
225
dvdx = face->oneOverArea * ((majorDv * face->minorDy) - (minorDv * face->majorDy));
226
dvdy = face->oneOverArea * ((minorDv * face->majorDx) - (majorDv * face->minorDx));
227
attr->value = (float) v0->greenValue;
228
attr->dvdx = (float) dvdx;
229
attr->dvdy = (float) dvdy;
232
majorDv = v2->blueValue - v0->blueValue;
233
minorDv = v1->blueValue - v0->blueValue;
234
dvdx = face->oneOverArea * ((majorDv * face->minorDy) - (minorDv * face->majorDy));
235
dvdy = face->oneOverArea * ((minorDv * face->majorDx) - (majorDv * face->minorDx));
236
attr->value = (float) v0->blueValue;
237
attr->dvdx = (float) dvdx;
238
attr->dvdy = (float) dvdy;
241
if(face->flags & B3D_FACE_ALPHA) {
242
/* Setup alpha interpolation */
243
majorDv = v2->alphaValue - v0->alphaValue;
244
minorDv = v1->alphaValue - v0->alphaValue;
245
dvdx = face->oneOverArea * ((majorDv * face->minorDy) - (minorDv * face->majorDy));
246
dvdy = face->oneOverArea * ((minorDv * face->majorDx) - (majorDv * face->minorDx));
247
attr->value = (float) v0->alphaValue;
248
attr->dvdx = (float) dvdx;
249
attr->dvdy = (float) dvdy;
252
if(face->flags & B3D_FACE_STW) {
253
/* Setup texture coordinate interpolation */
254
double w0 = v0->rasterPosW;
255
double w1 = v1->rasterPosW;
256
double w2 = v2->rasterPosW;
260
dvdx = face->oneOverArea * ((majorDv * face->minorDy) - (minorDv * face->majorDy));
261
dvdy = face->oneOverArea * ((minorDv * face->majorDx) - (majorDv * face->minorDx));
262
attr->value = (float) w0;
263
attr->dvdx = (float) dvdx;
264
attr->dvdy = (float) dvdy;
267
baseValue = v0->texCoordS * w0;
268
majorDv = (v2->texCoordS * w2) - baseValue;
269
minorDv = (v1->texCoordS * w1) - baseValue;
270
dvdx = face->oneOverArea * ((majorDv * face->minorDy) - (minorDv * face->majorDy));
271
dvdy = face->oneOverArea * ((minorDv * face->majorDx) - (majorDv * face->minorDx));
272
attr->value = (float) baseValue;
273
attr->dvdx = (float) dvdx;
274
attr->dvdy = (float) dvdy;
277
baseValue = v0->texCoordT * w0;
278
majorDv = (v2->texCoordT * w2) - baseValue;
279
minorDv = (v1->texCoordT * w1) - baseValue;
280
dvdx = face->oneOverArea * ((majorDv * face->minorDy) - (minorDv * face->majorDy));
281
dvdy = face->oneOverArea * ((minorDv * face->majorDx) - (majorDv * face->minorDx));
282
attr->value = (float) baseValue;
283
attr->dvdx = (float) dvdx;
284
attr->dvdy = (float) dvdy;
287
face->flags |= B3D_FACE_INITIALIZED;
291
/* b3dInitializeEdge:
292
Initialize the incremental values of the given edge.
294
/* INLINE b3dInitializeEdge(edge) */
295
void b3dInitializeEdge(B3DPrimitiveEdge *edge)
298
assert(edge->nLines);
299
edge->xValue = edge->v0->windowPosX;
300
edge->zValue = edge->v0->rasterPosZ;
301
if(edge->nLines > 1) {
302
edge->xIncrement = (edge->v1->windowPosX - edge->v0->windowPosX) / edge->nLines;
303
edge->zIncrement = (edge->v1->rasterPosZ - edge->v0->rasterPosZ) / (float) edge->nLines;
305
edge->xIncrement = (edge->v1->windowPosX - edge->v0->windowPosX);
306
edge->zIncrement = (edge->v1->rasterPosZ - edge->v0->rasterPosZ);
312
/*************************************************************/
313
/*************************************************************/
314
/*************************************************************/
316
/* b3dFirstIndexForInserting:
317
Return the first possible index for inserting an edge with the given x value.
320
int b3dFirstIndexForInserting(B3DPrimitiveEdgeList *list, int xValue)
322
int low, high, index;
326
index = (low + high) >> 1;
327
if(list->data[index]->xValue <= xValue)
333
while(index > 0 && (list->data[index-1]->xValue) == xValue)
338
/* b3dAddEdgeBeforeIndex:
339
Insert the edge to the list before the given index.
341
/* INLINE b3dAddEdgeBeforeIndex(list, edge, index) */
342
void b3dAddEdgeBeforeIndex(B3DPrimitiveEdgeList *list, B3DPrimitiveEdge *edge, int index)
347
if(list->size == list->max)
348
b3dAbort("No more space for adding edges");
350
assert( (list->size == index) || (list->data[index]->xValue >= edge->xValue));
351
for(i=list->size-1; i >= index; i--)
352
list->data[i+1] = list->data[i];
353
list->data[index] = edge;
358
/* b3d2AddEdgesBeforeIndex:
359
Insert the two edge to the list before the given index.
361
/* INLINE b3dAdd2EdgesBeforeIndex(list, edge1, edge2, index) */
362
void b3dAdd2EdgesBeforeIndex(B3DPrimitiveEdgeList *list,
363
B3DPrimitiveEdge *edge1,
364
B3DPrimitiveEdge *edge2,
370
if(list->size+1 >= list->max)
371
b3dAbort("No more space for adding edges");
373
assert( edge1->xValue == edge2->xValue);
374
assert( (list->size == index) || (list->data[index]->xValue >= edge1->xValue));
376
for(i=list->size-1; i >= index; i--)
377
list->data[i+2] = list->data[i];
378
list->data[index] = edge1;
379
list->data[index+1] = edge2;
384
/* b3dAdjustFaceEdges:
385
Assign left and right edges to the given face.
387
/* INLINE b3dAdjustFaceEdges(face, edge1, edge2) */
388
void b3dAdjustFaceEdges(B3DPrimitiveFace *face, B3DPrimitiveEdge *edge1, B3DPrimitiveEdge *edge2)
393
if(edge1->xValue == edge2->xValue) {
394
if(edge1->xIncrement <= edge2->xIncrement) {
395
face->leftEdge = edge1;
396
face->rightEdge = edge2;
398
face->leftEdge = edge2;
399
face->rightEdge = edge1;
402
if(edge1->xValue <= edge2->xValue) {
403
face->leftEdge = edge1;
404
face->rightEdge = edge2;
406
face->leftEdge = edge2;
407
face->rightEdge = edge1;
413
/* b3dAddLowerEdgeFromFace:
414
Add a new lower edge from the given face.
415
NOTE: oldEdge may be NULL!
416
NOTE: May cause allocation of one edge!
418
B3DPrimitiveEdge *b3dAddLowerEdgeFromFace(B3DPrimitiveFace *face, B3DPrimitiveEdge *oldEdge)
420
B3DPrimitiveVertex *v0 = face->v0;
421
B3DPrimitiveVertex *v1 = face->v1;
422
B3DPrimitiveVertex *v2 = face->v2;
423
int xValue = v1->windowPosX;
426
/* Search the list of added edges to merge the edges from the face */
427
index = b3dFirstIndexForInserting(addedEdges, xValue);
428
for(;index<addedEdges->size; index++) {
429
B3DPrimitiveEdge *edge = addedEdges->data[index];
430
if(edge->xValue != xValue) break;
431
if(edge->rightFace) continue;
432
if((edge->v0 == v1 && edge->v1 == v2) || /* The simple test*/
433
/* The complex test */
434
(edge->v0->windowPosX == v1->windowPosX &&
435
edge->v0->windowPosY == v1->windowPosY &&
436
edge->v0->rasterPosZ == v1->rasterPosZ &&
437
edge->v1->windowPosX == v2->windowPosX &&
438
edge->v1->windowPosY == v2->windowPosY &&
439
edge->v1->rasterPosZ == v2->rasterPosZ)) {
441
if(face->leftEdge == oldEdge)
442
face->leftEdge = edge;
444
face->rightEdge = edge;
445
edge->rightFace = face;
449
/* Need to create a new edge.
450
NOTE: Index already points to the right insertion point.
453
B3DPrimitiveEdge *minorEdge;
454
int nLines = (v2->windowPosY >> B3D_FixedToIntShift) - (v1->windowPosY >> B3D_FixedToIntShift);
455
if(!nLines) return NULL; /* Edge is horizontal */
456
b3dAllocEdge(edgeAlloc, minorEdge);
460
b3dAbort("Edge allocation failed");
464
minorEdge->nLines = nLines;
465
minorEdge->leftFace = face;
466
minorEdge->rightFace = NULL;
467
if(face->leftEdge == oldEdge)
468
face->leftEdge = minorEdge;
470
face->rightEdge = minorEdge;
471
b3dInitializeEdge(minorEdge);
472
b3dAddEdgeBeforeIndex(addedEdges, minorEdge, index);
478
/* b3dAddEdgesFromFace:
479
Add the two new edges from the given primitive face.
480
NOTE: May cause allocation of two edges (but not three)!
482
void b3dAddEdgesFromFace(B3DPrimitiveFace *face, int yValue)
486
B3DPrimitiveEdge *majorEdge = NULL;
487
B3DPrimitiveEdge *minorEdge = NULL;
488
B3DPrimitiveVertex *v0 = face->v0;
489
B3DPrimitiveVertex *v1 = face->v1;
490
B3DPrimitiveVertex *v2 = face->v2;
491
int xValue = v0->windowPosX;
494
/* Search the list of added edges to merge the edges from the face */
495
index = b3dFirstIndexForInserting(addedEdges, xValue);
496
for(;index<addedEdges->size; index++) {
497
B3DPrimitiveEdge *edge = addedEdges->data[index];
498
if(edge->xValue != xValue) break;
499
if(edge->rightFace) continue;
501
(edge->v0->windowPosY != v0->windowPosY ||
502
edge->v0->rasterPosZ != v0->rasterPosZ)) continue;
503
/* If we come to this point the edge might be usable for merging the face */
504
if(needMajor && /* Test only if major edge is needed */
505
(edge->v1 == v2 || /* Simple test */
506
/* A more complex test */
507
(edge->v1->windowPosX == v2->windowPosX &&
508
edge->v1->windowPosY == v2->windowPosY &&
509
edge->v1->rasterPosZ == v2->rasterPosZ))) {
510
/* Yepp. That's the new major */
512
majorEdge->rightFace = face;
513
majorEdge->flags |= B3D_EDGE_RIGHT_MAJOR;
515
if(b3dDoStats) nFaces++;
518
b3dAdjustFaceEdges(face, majorEdge, minorEdge);
522
} else if(needMinor && /* Test only if minor edge is needed */
523
(edge->v1 == v1 || /* Simple test */
524
/* A more complex test */
525
(edge->v1->windowPosX == v1->windowPosX &&
526
edge->v1->windowPosY == v1->windowPosY &&
527
edge->v1->rasterPosZ == v1->rasterPosZ))) {
528
/* Yepp. That's the new minor */
530
minorEdge->rightFace = face;
531
minorEdge->flags |= B3D_EDGE_CONTINUE_RIGHT;
533
b3dAdjustFaceEdges(face, majorEdge, minorEdge);
539
/* Need to create new edges.
540
Note: index already points to the right insertion point in addedEdges
543
int nLines = (v2->windowPosY >> B3D_FixedToIntShift) - (v0->windowPosY >> B3D_FixedToIntShift);
546
/* The major edge is horizontal. */
547
b3dFreeFace(faceAlloc, face);
550
b3dAllocEdge(edgeAlloc, majorEdge);
552
if(!majorEdge) b3dAbort("Edge allocation failed");
555
majorEdge->nLines = nLines;
556
majorEdge->leftFace = face;
557
majorEdge->rightFace = NULL;
558
majorEdge->flags |= B3D_EDGE_LEFT_MAJOR;
559
b3dInitializeEdge(majorEdge);
560
if(b3dDoStats) nFaces++;
564
int nLines = (v1->windowPosY >> B3D_FixedToIntShift) - (v0->windowPosY >> B3D_FixedToIntShift);
567
/* Note: If the (upper) minor edge is horizontal, use the lower one.
568
Note: The lower edge cannot be horizontal if the major edge isn't
571
b3dAddEdgeBeforeIndex(addedEdges, majorEdge, index);
573
minorEdge = b3dAddLowerEdgeFromFace(face,NULL);
576
if(!minorEdge || minorEdge->nLines == 0)
577
b3dAbort("minor edge is horizontal");
579
b3dAdjustFaceEdges(face, majorEdge, minorEdge);
583
b3dAllocEdge(edgeAlloc, minorEdge);
586
if(!minorEdge) b3dAbort("Edge allocation failed");
590
minorEdge->nLines = nLines;
591
minorEdge->leftFace = face;
592
minorEdge->rightFace = NULL;
593
minorEdge->flags |= B3D_EDGE_CONTINUE_LEFT;
594
b3dInitializeEdge(minorEdge);
597
/* Add the newly created edges to addedEdges */
598
if(needMinor && needMajor) {
599
b3dAdd2EdgesBeforeIndex(addedEdges, majorEdge, minorEdge, index);
600
} else if(needMajor) {
601
b3dAddEdgeBeforeIndex(addedEdges, majorEdge, index);
603
b3dAddEdgeBeforeIndex(addedEdges, minorEdge, index);
605
b3dAdjustFaceEdges(face, majorEdge, minorEdge);
610
Remove the given edge from the AET.
611
NOTE: May cause allocation of two edges!
613
/* INLINE b3dRemoveAETEdge(aet, edge, yValue, aetPos) */
614
void b3dRemoveAETEdge(B3DActiveEdgeTable *aet, B3DPrimitiveEdge *edge, int yValue, int aetPos)
616
/* Remove edge and add lower edges if necessary */
618
B3DPrimitiveEdge **aetData = aet->data;
620
assert(aetData[aetPos] == edge);
623
if( (edge->v1->windowPosY >> B3D_FixedToIntShift) != yValue )
624
b3dAbort("Edge exceeds range");
626
/* Remove the edge and adjust the stuff */
627
for(j=aetPos+1; j < aet->size; j++) aetData[j-1] = aetData[j];
629
/* Add new lower edges */
630
if(edge->flags & B3D_EDGE_CONTINUE_LEFT) {
631
b3dAddLowerEdgeFromFace(edge->leftFace, edge);
633
if(edge->flags & B3D_EDGE_CONTINUE_RIGHT) {
634
b3dAddLowerEdgeFromFace(edge->rightFace, edge);
636
if(edge->flags & B3D_EDGE_LEFT_MAJOR) {
638
b3dFreeAttrib(attrAlloc, edge->leftFace);
639
b3dFreeFace(faceAlloc, edge->leftFace);
640
if(b3dDoStats) nFaces--;
642
if(edge->flags & B3D_EDGE_RIGHT_MAJOR) {
643
/* Free right face */
644
b3dFreeAttrib(attrAlloc, edge->rightFace);
645
b3dFreeFace(faceAlloc, edge->rightFace);
646
if(b3dDoStats) nFaces--;
648
/* And free old edge */
649
b3dFreeEdge(edgeAlloc, edge);
653
/* b3dMergeAETEdgesFrom:
654
Merge the edges from the given source into the AET.
656
void b3dMergeAETEdgesFrom(B3DActiveEdgeTable *aet, B3DPrimitiveEdgeList *src)
658
int srcIndex, aetIndex, outIndex, i;
659
B3DPrimitiveEdge *srcEdge, *aetEdge;
664
assert(aet->size + src->size <= aet->max);
667
for(i=0; i<src->size; i++) aet->data[i] = src->data[i];
668
aet->size += src->size;
672
/* Merge the input by stepping backwards through the aet and checking each edge */
673
outIndex = aet->size + src->size - 1;
674
srcIndex = src->size-1;
675
aetIndex = aet->size-1;
676
srcEdge = src->data[srcIndex];
677
aetEdge = aet->data[aetIndex];
678
aet->size += src->size;
680
if(srcEdge->xValue >= aetEdge->xValue) {
682
aet->data[outIndex--] = srcEdge;
683
if(!srcIndex--) return;
684
srcEdge = src->data[srcIndex];
687
aet->data[outIndex--] = aetEdge;
689
for(i=0; i <= srcIndex; i++) aet->data[i] = src->data[i];
692
aetEdge = aet->data[aetIndex];
697
/* INLINE b3dAdvanceAETEdge(edge, aetData, aetStart) */
698
void b3dAdvanceAETEdge(B3DPrimitiveEdge *edge,
699
B3DPrimitiveEdge **aetData,
702
/* Advance to next scan line */
703
edge->zValue += edge->zIncrement;
704
edge->xValue += edge->xIncrement;
705
/* Check if AET sort order is okay */
706
if(aetStart && aetData[aetStart-1]->xValue > edge->xValue) {
707
/* Must resort rightEdge */
708
int xValue = edge->xValue;
710
/* Move the edge left */
711
while(j>0 && aetData[j-1]->xValue > xValue) {
712
aetData[j] = aetData[j-1];
720
/*************************************************************/
721
/*************************************************************/
722
/*************************************************************/
724
double zValueAt(B3DPrimitiveFace *face, double xValue, double yValue)
727
(face->v0->rasterPosZ +
728
(((double)xValue - face->v0->rasterPosX) * face->dzdx) +
729
(((double)yValue - face->v0->rasterPosY) * face->dzdy));
732
#define zValueAt(face, xValue, yValue) \
733
((face)->v0->rasterPosZ + \
734
(((double)(xValue) - (face)->v0->rasterPosX) * (face)->dzdx) +\
735
(((double)(yValue) - (face)->v0->rasterPosY) * (face)->dzdy))
738
/*************************************************************/
739
/*************************************************************/
740
/*************************************************************/
742
int b3dComputeIntersection(B3DPrimitiveFace *frontFace,
743
B3DPrimitiveFace *backFace,
747
double dx1 = frontFace->rightEdge->xValue - frontFace->leftEdge->xValue;
748
double dz1 = frontFace->rightEdge->zValue - frontFace->leftEdge->zValue;
749
double dx2 = backFace->rightEdge->xValue - backFace->leftEdge->xValue;
750
double dz2 = backFace->rightEdge->zValue - backFace->leftEdge->zValue;
751
double px = backFace->leftEdge->xValue - frontFace->leftEdge->xValue;
752
double pz = backFace->leftEdge->zValue - frontFace->leftEdge->zValue;
753
double det = (dx1 * dz2) - (dx2 * dz1);
754
if(det == 0.0) return errorValue;
756
double det2 = ((px * dz2) - (pz * dx2)) / det;
757
return frontFace->leftEdge->xValue + (int)(dx1 * det2);
762
/* b3dCheckIntersectionOfFaces:
763
Compute the possible intersection of frontFace and backFace.
764
Store the result in nextIntersection if it is before any other
765
intersection. Return true if other intersections tests should
766
be performed, false otherwise.
768
int b3dCheckIntersectionOfFaces(B3DPrimitiveFace *frontFace,
769
B3DPrimitiveFace *backFace,
771
B3DPrimitiveEdge *leftEdge,
772
B3DPrimitiveEdge *nextIntersection)
774
double frontZ, backZ;
777
/* Check if the backFace is completely behind the front face */
778
if(backFace->minZ >= frontFace->maxZ) return 0; /* abort */
780
/* Check if front and back face share any edges */
781
if(frontFace->leftEdge == backFace->leftEdge) return 1; /* proceed */
782
if(frontFace->rightEdge == backFace->rightEdge) return 1; /* proceed */
784
/* Check if either front or back face are less than 1 pixel wide */
785
if( (frontFace->leftEdge->xValue >> B3D_FixedToIntShift) ==
786
(frontFace->rightEdge->xValue >> B3D_FixedToIntShift)) return 0; /* abort */
787
if( (backFace->leftEdge->xValue >> B3D_FixedToIntShift) ==
788
(backFace->rightEdge->xValue >> B3D_FixedToIntShift)) return 1; /* proceed */
790
/* Choose the right x value of either front or back face,
791
whichever is less (this is so we sample inside both faces) */
792
if(frontFace->rightEdge->xValue <= backFace->rightEdge->xValue) {
793
rightX = frontFace->rightEdge->xValue;
794
frontZ = frontFace->rightEdge->zValue;
795
backZ = zValueAt(backFace, rightX * B3D_FixedToFloat, yValue);
797
rightX = backFace->rightEdge->xValue;
798
backZ = backFace->rightEdge->zValue;
799
frontZ = zValueAt(frontFace, rightX * B3D_FixedToFloat, yValue);
803
/* possible intersection found */
804
xValue = b3dComputeIntersection(frontFace, backFace, yValue, leftEdge->xValue);
805
if(xValue > rightX) xValue = rightX;
806
/* Ignore intersections at or before the leftEdge's x value. Important. */
807
if((xValue >> B3D_FixedToIntShift) <= (leftEdge->xValue >> B3D_FixedToIntShift))
808
xValue = ((leftEdge->xValue >> B3D_FixedToIntShift) + 1) << B3D_IntToFixedShift;
809
if(xValue < nextIntersection->xValue) {
810
nextIntersection->xValue = xValue;
811
nextIntersection->leftFace = frontFace;
812
nextIntersection->rightFace = backFace;
818
/* b3dAdjustIntersections:
819
Compute the possible intersections of the current front face
820
with all active faces. Store the next intersection if any.
822
/* INLINE b3dAdjustIntersections(fillList, yValue, topEdge, nextIntersection) */
823
void b3dAdjustIntersections(B3DFillList *fillList,
825
B3DPrimitiveEdge *topEdge,
826
B3DPrimitiveEdge *nextIntersection)
828
B3DPrimitiveFace *frontFace = fillList->firstFace;
830
B3DPrimitiveFace *backFace = frontFace->nextFace;
832
while(backFace && proceed) {
833
proceed = b3dCheckIntersectionOfFaces(frontFace, backFace, yValue, topEdge, nextIntersection);
834
backFace = backFace->nextFace;
840
/*************************************************************/
841
/*************************************************************/
842
/*************************************************************/
844
void b3dValidateFillList(B3DFillList *list)
846
B3DPrimitiveFace *firstFace = list->firstFace;
847
B3DPrimitiveFace *lastFace = list->lastFace;
848
B3DPrimitiveFace *face;
850
if(!firstFace && !lastFace) return;
851
if(firstFace->prevFace)
852
b3dAbort("Bad fill list");
853
if(lastFace->nextFace)
854
b3dAbort("Bad fill list");
856
while(face != lastFace)
857
face = face->nextFace;
858
/* Validate sort order */
859
if(firstFace == lastFace)
860
return; /* 0 or 1 element */
861
face = firstFace->nextFace;
862
while(face->nextFace) {
863
if(face->minZ > face->nextFace->minZ)
864
b3dAbort("Fill list sorting problem");
865
face = face->nextFace;
869
/* INLINE b3dAddFirstFill(fillList, aFace) */
870
void b3dAddFirstFill(B3DFillList *fillList, B3DPrimitiveFace *aFace)
872
B3DPrimitiveFace *firstFace = fillList->firstFace;
874
firstFace->prevFace = aFace;
876
fillList->lastFace = aFace;
877
aFace->nextFace = firstFace;
878
aFace->prevFace = NULL;
879
fillList->firstFace = aFace;
880
if(b3dDebug) b3dValidateFillList(fillList);
884
/* INLINE b3dAddLastFill(fillList, aFace) */
885
void b3dAddLastFill(B3DFillList *fillList, B3DPrimitiveFace *aFace)
887
B3DPrimitiveFace *lastFace = fillList->lastFace;
889
lastFace->nextFace = aFace;
891
fillList->firstFace = aFace;
892
aFace->prevFace = lastFace;
893
aFace->nextFace = NULL;
894
fillList->lastFace = aFace;
895
if(b3dDebug) b3dValidateFillList(fillList);
899
/* INLINE b3dRemoveFill(fillList, aFace) */
900
void b3dRemoveFill(B3DFillList *fillList, B3DPrimitiveFace *aFace)
902
if(b3dDebug) b3dValidateFillList(fillList);
904
aFace->prevFace->nextFace = aFace->nextFace;
906
fillList->firstFace = aFace->nextFace;
908
aFace->nextFace->prevFace = aFace->prevFace;
910
fillList->lastFace = aFace->prevFace;
914
/* INLINE b3dInsertBeforeFill(fillList, aFace, otherFace) */
915
void b3dInsertBeforeFill(B3DFillList *fillList, B3DPrimitiveFace *aFace, B3DPrimitiveFace *otherFace)
917
assert(otherFace != fillList->firstFace);
919
aFace->nextFace = otherFace;
920
aFace->prevFace = otherFace->prevFace;
921
aFace->prevFace->nextFace = aFace;
922
otherFace->prevFace = aFace;
923
if(b3dDebug) b3dValidateFillList(fillList);
927
/* INLINE b3dAddFrontFill(fillList, aFace) */
928
void b3dAddFrontFill(B3DFillList *fillList, B3DPrimitiveFace *aFace)
930
B3DPrimitiveFace *firstFace = fillList->firstFace;
931
if(firstFace != fillList->lastFace) {
932
/* Meaning that we must find the new position for the old front face */
933
B3DPrimitiveFace *backFace = firstFace->nextFace;
934
float minZ = firstFace->minZ;
936
while(backFace && backFace->minZ < minZ)
937
backFace = backFace->nextFace;
939
/* Insert firstFace before backFace */
940
if(firstFace->nextFace != backFace) {
941
B3DPrimitiveFace *tempFace = firstFace;
943
b3dRemoveFill(fillList, tempFace);
945
b3dInsertBeforeFill(fillList, tempFace, backFace);
947
b3dAddLastFill(fillList, tempFace);
951
b3dAddFirstFill(fillList, aFace);
952
if(b3dDebug) b3dValidateFillList(fillList);
956
/* INLINE b3dAddBackFill(fillList, aFace) */
957
void b3dAddBackFill(B3DFillList *fillList, B3DPrimitiveFace *aFace)
959
B3DPrimitiveFace *firstFace = fillList->firstFace;
960
B3DPrimitiveFace *lastFace = fillList->lastFace;
961
B3DPrimitiveFace *face;
962
float minZ = aFace->minZ;
966
if(firstFace == lastFace || minZ >= lastFace->minZ) {
967
b3dAddLastFill(fillList, aFace);
969
/* Try an estimation on how to search */
970
if(minZ <= (firstFace->minZ + lastFace->minZ) * 0.5) {
971
/* search front to back */
972
face = firstFace->nextFace;
973
while(face->minZ < minZ) face = face->nextFace;
975
/* search back to front */
976
face = lastFace->prevFace; /* already checked if lastFace->minZ <= minZ */
977
while(face->minZ > minZ) face = face->prevFace;
978
face = face->nextFace;
980
b3dInsertBeforeFill(fillList, aFace, face);
982
if(b3dDebug) b3dValidateFillList(fillList);
986
/* INLINE b3dCleanupFill(fillList) */
987
void b3dCleanupFill(B3DFillList *fillList)
989
B3DPrimitiveFace *firstFace = fillList->firstFace;
992
firstFace->flags ^= B3D_FACE_ACTIVE;
993
firstFace = firstFace->nextFace;
995
fillList->firstFace = fillList->lastFace = NULL;
999
void b3dSearchForNewTopFill(B3DFillList *fillList, int scaledX, int yValue)
1001
B3DPrimitiveFace *topFace = fillList->firstFace;
1003
if(b3dDebug) b3dValidateFillList(fillList);
1004
if(topFace) { /* only if there is any */
1005
B3DPrimitiveFace *face = topFace->nextFace;
1006
double xValue = scaledX * B3D_FixedToFloat;
1007
double topZ = zValueAt(topFace, xValue, yValue);
1009
/* Note: since the list is ordered we need only to search until face->minZ >= topZ */
1010
while(face && face->minZ <= topZ) {
1011
double faceZ = zValueAt(face, xValue, yValue);
1016
face = face->nextFace;
1018
/* and move the guy to front */
1019
b3dRemoveFill(fillList, topFace);
1020
b3dAddFrontFill(fillList, topFace);
1024
/* INLINE b3dToggleTopFills(fillList, edge, yValue) */
1025
void b3dToggleTopFills(B3DFillList *fillList, B3DPrimitiveEdge *edge, int yValue)
1027
B3DPrimitiveFace *leftFace = edge->leftFace;
1028
B3DPrimitiveFace *rightFace = edge->rightFace;
1029
if(b3dDebug) b3dValidateFillList(fillList);
1030
assert(leftFace != rightFace);
1032
int xorMask = leftFace->flags ^ rightFace->flags;
1033
if(xorMask & B3D_FACE_ACTIVE) {
1034
if(leftFace->flags & B3D_FACE_ACTIVE) {
1035
b3dRemoveFill(fillList, leftFace);
1036
b3dAddFrontFill(fillList, rightFace);
1038
b3dRemoveFill(fillList, rightFace);
1039
b3dAddFrontFill(fillList, leftFace);
1042
if(leftFace->flags & B3D_FACE_ACTIVE) {
1043
b3dRemoveFill(fillList, leftFace);
1044
b3dRemoveFill(fillList, rightFace);
1045
b3dSearchForNewTopFill(fillList, edge->xValue, yValue);
1047
if(leftFace->dzdx <= rightFace->dzdx) {
1048
b3dAddFrontFill(fillList, leftFace);
1049
b3dAddBackFill(fillList, rightFace);
1051
b3dAddFrontFill(fillList, rightFace);
1052
b3dAddBackFill(fillList, leftFace);
1056
leftFace->flags ^= B3D_FACE_ACTIVE;
1057
rightFace->flags ^= B3D_FACE_ACTIVE;
1059
if(leftFace->flags & B3D_FACE_ACTIVE) {
1060
b3dRemoveFill(fillList, leftFace);
1061
b3dSearchForNewTopFill(fillList, edge->xValue, yValue);
1063
b3dAddFrontFill(fillList, leftFace);
1065
leftFace->flags ^= B3D_FACE_ACTIVE;
1067
if(b3dDebug) b3dValidateFillList(fillList);
1071
/* INLINE b3dToggleBackFills(fillList, edge, yValue, nextIntersection) */
1072
void b3dToggleBackFills(B3DFillList *fillList,
1073
B3DPrimitiveEdge *edge,
1075
B3DPrimitiveEdge *nextIntersection)
1077
B3DPrimitiveFace *face = edge->leftFace;
1078
if(b3dDebug) b3dValidateFillList(fillList);
1079
if(face->flags & B3D_FACE_ACTIVE) {
1080
b3dRemoveFill(fillList, face);
1082
b3dAddBackFill(fillList, face);
1083
b3dCheckIntersectionOfFaces(fillList->firstFace, face, yValue, edge, nextIntersection);
1085
face->flags ^= B3D_FACE_ACTIVE;
1086
face = edge->rightFace;
1088
if(face->flags & B3D_FACE_ACTIVE) {
1089
b3dRemoveFill(fillList, face);
1091
b3dAddBackFill(fillList, face);
1092
b3dCheckIntersectionOfFaces(fillList->firstFace, face, yValue, edge, nextIntersection);
1094
face->flags ^= B3D_FACE_ACTIVE;
1096
if(b3dDebug) b3dValidateFillList(fillList);
1100
/*************************************************************/
1101
/*************************************************************/
1102
/*************************************************************/
1104
/* INLINE b3dClearSpanBuffer(aet) */
1105
void b3dClearSpanBuffer(B3DActiveEdgeTable *aet)
1107
int i, leftX, rightX;
1108
unsigned int *buffer = currentState->spanBuffer;
1109
if(aet->size && buffer) {
1110
leftX = aet->data[0]->xValue >> B3D_FixedToIntShift;
1111
rightX = aet->data[aet->size-1]->xValue >> B3D_FixedToIntShift;
1112
if(leftX < 0) leftX = 0;
1113
if(rightX >= currentState->spanSize) rightX = currentState->spanSize-1;
1114
for(i=leftX;i<=rightX;i++) buffer[i] = 0;
1119
/* INLINE b3dDrawSpanBuffer(aet, yValue) */
1120
void b3dDrawSpanBuffer(B3DActiveEdgeTable *aet, int yValue)
1123
if(aet->size && currentState->spanDrawer) {
1124
leftX = aet->data[0]->xValue >> B3D_FixedToIntShift;
1125
rightX = aet->data[aet->size-1]->xValue >> B3D_FixedToIntShift;
1126
if(leftX < 0) leftX = 0;
1127
if(rightX > currentState->spanSize) rightX = currentState->spanSize;
1128
currentState->spanDrawer(leftX, rightX, yValue);
1133
/*************************************************************/
1134
/*************************************************************/
1135
/*************************************************************/
1136
/* General failure */
1137
#define FAIL(reason,resume) { aet->yValue = yValue; return reason | resume; }
1138
#define PROCEED { yValue = aet->yValue; }
1140
/* Failure adding objects */
1141
#define FAIL_ADDING(reason) { obj->start = objStart; FAIL(reason, B3D_RESUME_ADDING) }
1142
#define PROCEED_ADDING { objStart = obj->start; PROCEED }
1144
/* Failure merging objects */
1145
#define FAIL_MERGING(reason) { FAIL(reason, B3D_RESUME_MERGING); }
1146
#define PROCEED_MERGING { PROCEED }
1148
/* Failure during paint */
1149
#define FAIL_PAINTING(reason) { aet->start = aetStart; aet->leftEdge = leftEdge; aet->rightEdge = rightEdge; FAIL(reason, B3D_RESUME_PAINTING) }
1150
#define PROCEED_PAINTING(reason) { aetStart = aet->start; leftEdge = aet->leftEdge; rightEdge = aet->rightEdge; PROCEED }
1152
#define FAIL_UPDATING(reason)
1154
int b3dMainLoop(B3DRasterizerState *state, int stopReason)
1156
B3DPrimitiveObject *activeStart, *passiveStart;
1157
int yValue, nextObjY, nextEdgeY;
1158
B3DFillList *fillList;
1159
B3DPrimitiveEdge *lastIntersection, *nextIntersection;
1163
return B3D_GENERIC_ERROR;
1165
if(!state->nObjects)
1166
return B3D_NO_ERROR;
1168
if(b3dValidateAndRemapState(state) != B3D_NO_ERROR)
1169
return B3D_GENERIC_ERROR;
1171
if(stopReason == B3D_NO_ERROR)
1172
if(b3dSetupObjects(state) != B3D_NO_ERROR)
1173
return B3D_GENERIC_ERROR;
1176
/* check the sort order of objects */
1178
for(i=2; i<state->nObjects;i++)
1179
if(!objSortsBefore(state->objects[i-1], state->objects[i]))
1180
b3dAbort("Objects not sorted");
1183
currentState = state;
1184
faceAlloc = state->faceAlloc;
1185
edgeAlloc = state->edgeAlloc;
1186
attrAlloc = state->attrAlloc;
1187
addedEdges = state->addedEdges;
1188
fillList = state->fillList;
1190
nextIntersection = aet->nextIntersection;
1191
lastIntersection = aet->lastIntersection;
1193
if(b3dDoStats) nFaces = 0;
1195
if(stopReason == B3D_NO_ERROR) {
1196
activeStart = passiveStart = state->objects[0];
1197
yValue = nextEdgeY = nextObjY = passiveStart->minY;
1200
resumeCode = stopReason & B3D_RESUME_MASK;
1201
if(resumeCode == B3D_RESUME_ADDING ) goto RESUME_ADDING;
1202
if(resumeCode == B3D_RESUME_MERGING ) goto RESUME_MERGING;
1203
if(resumeCode == B3D_RESUME_PAINTING) goto RESUME_PAINTING;
1204
if(resumeCode == B3D_RESUME_UPDATING) goto RESUME_UPDATING;
1205
return B3D_GENERIC_ERROR;
1208
/**** BEGIN MAINLOOP ****/
1209
while(activeStart || passiveStart || aet->size) {
1213
/* STEP 1: Add new objects if necessary */
1214
if(yValue == nextObjY) {
1215
nextEdgeY = nextObjY;
1216
while(passiveStart && passiveStart->minY == nextObjY) {
1217
passiveStart->flags |= B3D_OBJECT_ACTIVE;
1218
passiveStart = passiveStart->next;
1221
nextObjY = passiveStart->minY;
1224
} /* End of adding objects */
1228
/* STEP 2: Add new edges if necessary */
1229
if(yValue == nextEdgeY) {
1230
B3DPrimitiveObject *obj = activeStart;
1231
int scaledY = (yValue+1) << B3D_IntToFixedShift;
1233
nextEdgeY = nextObjY << B3D_IntToFixedShift;
1234
while(obj != passiveStart) {
1235
B3DInputFace *objFaces = obj->faces;
1236
B3DPrimitiveVertex *objVtx = obj->vertices;
1237
int objStart = obj->start;
1238
int objSize = obj->nFaces;
1241
assert(obj->flags & B3D_OBJECT_ACTIVE);
1243
while(objStart < objSize && ((tempY = objVtx[objFaces[objStart].i0].windowPosY) < scaledY)) {
1244
/* add edges from face at objFaces[objStart] */
1245
B3DInputFace *inputFace = objFaces + objStart;
1246
B3DPrimitiveFace *face;
1248
/* NOTE: If any of the following fails,
1249
we can re-enter the main loop later on. */
1251
if(faceAlloc->nFree == 0)
1252
FAIL_ADDING(B3D_NO_MORE_FACES);
1254
if(edgeAlloc->nFree < 2)
1255
FAIL_ADDING(B3D_NO_MORE_EDGES);
1257
if(addedEdges->size+2 > addedEdges->max)
1258
FAIL_ADDING(B3D_NO_MORE_ADDED);
1260
/* Allocate a new face and do the initial setup */
1261
face = b3dInitializeFace(objVtx + inputFace->i0,
1262
objVtx + inputFace->i1,
1263
objVtx + inputFace->i2,
1267
b3dAddEdgesFromFace(face, yValue);
1272
obj->start = objStart;
1273
if(objStart != objSize) {
1274
if(tempY < nextEdgeY) nextEdgeY = tempY;
1276
/* Unlink obj from activeStart list */
1277
obj->flags |= B3D_OBJECT_DONE;
1278
if(obj == activeStart) {
1279
activeStart = obj->next;
1281
obj->prev->next = obj->next;
1287
nextEdgeY >>= B3D_FixedToIntShift;
1288
} /* End of adding edges */
1291
/* STEP 3: Merge all newly added edges from addedList into the AET */
1292
if(addedEdges->size) {
1295
b3dValidateEdgeOrder(addedEdges);
1296
/* NOTE: If the following fails, we can re-enter the main loop later on. */
1297
if(aet->size + addedEdges->size > aet->max)
1298
FAIL_MERGING(B3D_NO_MORE_AET);
1299
b3dMergeAETEdgesFrom(aet, addedEdges);
1301
b3dValidateAETOrder(aet);
1303
addedEdges->size = 0; /* reset added */
1304
} /* End of merging edges */
1307
/********** THIS IS THE CORE LOOP ********/
1308
/* while(yValue < nextEdgeY && !addedEdges->size && aet->size) { */
1312
if(aet->size > maxEdges) maxEdges = aet->size;
1313
if(nFaces > maxFaces) maxFaces = nFaces;
1316
/* STEP 4: Draw the current span */
1318
/* STEP 4a: Clear the span buffer */
1319
b3dClearSpanBuffer(aet);
1321
/* STEP 4b: Scan out the AET */
1323
B3DPrimitiveEdge *leftEdge;
1324
B3DPrimitiveEdge *rightEdge;
1325
B3DPrimitiveEdge **aetData = aet->data;
1327
int aetSize = aet->size;
1329
/* clean up old fills if any */
1330
b3dCleanupFill(fillList);
1332
nextIntersection->xValue = B3D_MAX_X;
1333
leftEdge = aetData[0];
1334
while(aetStart < aetSize) {
1336
/*-- Toggle the faces of the top edge (the left edge is always on top) --*/
1337
if(leftEdge == lastIntersection) {
1338
/* Special case if this is a intersection edge */
1339
assert(fillList->firstFace == leftEdge->leftFace);
1340
b3dRemoveFill(fillList, leftEdge->rightFace);
1341
b3dAddFrontFill(fillList, leftEdge->rightFace);
1343
b3dToggleTopFills(fillList, leftEdge, yValue);
1345
/*-- end of toggling top edge faces --*/
1347
/* after getting a new top fill we must adjust intersections */
1348
b3dAdjustIntersections(fillList, yValue, leftEdge, nextIntersection);
1350
/*-- search for the next top edge which will be the right edge --*/
1351
assert(aetStart < aetSize);
1352
if(!fillList->firstFace)
1353
rightEdge = aetData[aetStart++]; /* If no current top fill just use the next edge */
1354
else while(aetStart < aetSize) { /* Search for the next top edge in the AET */
1355
rightEdge = aetData[aetStart];
1356
/* If we have an intersection use the intersection edge */
1357
if(nextIntersection->xValue <= rightEdge->xValue) {
1358
rightEdge = nextIntersection;
1362
/* Check if this edge is on top */
1363
assert(fillList->firstFace);
1365
double xValue = rightEdge->xValue * B3D_FixedToFloat;
1366
B3DPrimitiveFace *topFace = fillList->firstFace;
1367
if( rightEdge->leftFace == topFace ||
1368
rightEdge->rightFace == topFace ||
1369
rightEdge->zValue < zValueAt(topFace, xValue, yValue))
1370
break; /* rightEdge is on top */
1372
/* If the edge is not on top toggle its (back) fills */
1373
b3dToggleBackFills(fillList, rightEdge, yValue, nextIntersection);
1376
/*-- end of search for next top edge --*/
1378
/*-- Now do the drawing from leftEdge to rightEdge --*/
1380
if(fillList->firstFace) {
1381
/* Note: We fill *including* leftX and rightX */
1382
int leftX = (leftEdge->xValue >> B3D_FixedToIntShift) + 1;
1383
int rightX = (rightEdge->xValue >> B3D_FixedToIntShift);
1384
B3DPrimitiveFace *topFace = fillList->firstFace;
1386
if(leftX < 0) leftX = 0;
1387
if(rightX >= currentState->spanSize) rightX = currentState->spanSize-1;
1388
if(leftX <= rightX) {
1389
/* Since we know now that some serious filling operation
1390
will happen, initialize the attributes of the face if
1391
this hasn't been done before. */
1393
if( (topFace->flags & B3D_FACE_INITIALIZED) == 0) {
1394
assert(topFace->attributes == NULL);
1395
if(!b3dInitializePass2(topFace))
1396
FAIL_PAINTING(B3D_NO_MORE_ATTRS);
1398
/* And dispatch on the actual pixel drawers */
1399
(*B3D_FILL_FUNCTIONS[(topFace->flags >> B3D_ATTR_SHIFT) & B3D_ATTR_MASK])
1400
(leftX, rightX, yValue, topFace);
1403
/*-- End of drawing -- */
1405
/* prepare for new top edge */
1406
leftEdge = rightEdge;
1407
/* use a new intersection if necessary */
1408
if(leftEdge == nextIntersection) {
1409
nextIntersection = lastIntersection;
1410
lastIntersection = leftEdge;
1412
nextIntersection->xValue = B3D_MAX_X;
1414
/* clean up old fills if any */
1415
b3dCleanupFill(fillList);
1418
/* STEP 4c: Display the pixels from the span buffer */
1419
b3dDrawSpanBuffer(aet, yValue);
1421
/* STEP 5: Go to next y value and update AET entries */
1425
int aetSize = aet->size;
1426
B3DPrimitiveEdge **aetData = aet->data;
1429
while(aetStart < aetSize) {
1430
B3DPrimitiveEdge *edge = aetData[aetStart];
1432
if(--(edge->nLines)) {
1433
/* Advance to next scan line and resort edge */
1434
b3dAdvanceAETEdge(edge, aetData, aetStart);
1437
/* Remove edge and add lower edges if necessary */
1439
if(edgeAlloc->nFree < 2)
1440
FAIL_UPDATING(B3D_NO_MORE_EDGES);
1441
if(addedEdges->size + 2 > addedEdges->max)
1442
FAIL_UPDATING(B3D_NO_MORE_ADDED);
1443
b3dRemoveAETEdge(aet, edge, yValue, aetStart);
1444
aetSize = aet->size;
1445
/* Do NOT advance aetStart here */
1449
/* End of AET update */
1451
b3dValidateAETOrder(aet);
1454
/*}*/ /******** END OF CORE LOOP ********/
1456
} /**** END MAINLOOP ****/
1458
return B3D_NO_ERROR;