//! draws an indexed triangle list virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) { const S2DVertex *v1, *v2, *v3; u16 color; f32 tmpDiv; // temporary division factor f32 longest; // saves the longest span s32 height; // saves height of triangle u16* targetSurface; // target pointer where to plot pixels s32 spanEnd; // saves end of spans f32 leftdeltaxf; // amount of pixels to increase on left side of triangle f32 rightdeltaxf; // amount of pixels to increase on right side of triangle s32 leftx, rightx; // position where we are f32 leftxf, rightxf; // same as above, but as f32 values s32 span; // current span u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels core::rect<s32> TriangleRect; s32 leftZValue, rightZValue; s32 leftZStep, rightZStep; s32 spanZValue, spanZStep; // ZValues when drawing a span TZBufferType* zTarget, *spanZTarget; // target of ZBuffer; lockedSurface = (u16*)RenderTarget->lock(); lockedZBuffer = ZBuffer->lock(); for (s32 i=0; i<triangleCount; ++i) { v1 = &vertices[*indexList]; ++indexList; v2 = &vertices[*indexList]; ++indexList; v3 = &vertices[*indexList]; ++indexList; // back face culling if (BackFaceCullingEnabled) { s32 z = ((v3->Pos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); if (z < 0) continue; } //near plane clipping if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) continue; // sort for width for inscreen clipping if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); if ((v1->Pos.X - v3->Pos.X) == 0) continue; TriangleRect.UpperLeftCorner.X = v1->Pos.X; TriangleRect.LowerRightCorner.X = v3->Pos.X; // sort for height for faster drawing. if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; TriangleRect.LowerRightCorner.Y = v3->Pos.Y; if (!TriangleRect.isRectCollided(ViewPortRect)) continue; // calculate height of triangle height = v3->Pos.Y - v1->Pos.Y; if (!height) continue; // calculate longest span longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); spanEnd = v2->Pos.Y; span = v1->Pos.Y; leftxf = (f32)v1->Pos.X; rightxf = (f32)v1->Pos.X; leftZValue = v1->ZValue; rightZValue = v1->ZValue; color = v1->Color; targetSurface = lockedSurface + span * SurfaceWidth; zTarget = lockedZBuffer + span * SurfaceWidth; if (longest < 0.0f) { tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); tmpDiv = 1.0f / (f32)height; leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); } else { tmpDiv = 1.0f / (f32)height; rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); } // do it twice, once for the first half of the triangle, // end then for the second half. for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) { if (spanEnd > ViewPortRect.LowerRightCorner.Y) spanEnd = ViewPortRect.LowerRightCorner.Y; // if the span <0, than we can skip these spans, // and proceed to the next spans which are really on the screen. if (span < ViewPortRect.UpperLeftCorner.Y) { // we'll use leftx as temp variable if (spanEnd < ViewPortRect.UpperLeftCorner.Y) { leftx = spanEnd - span; span = spanEnd; } else { leftx = ViewPortRect.UpperLeftCorner.Y - span; span = ViewPortRect.UpperLeftCorner.Y; } leftxf += leftdeltaxf*leftx; rightxf += rightdeltaxf*leftx; targetSurface += SurfaceWidth*leftx; zTarget += SurfaceWidth*leftx; leftZValue += leftZStep*leftx; rightZValue += rightZStep*leftx; } // the main loop. Go through every span and draw it. while (span < spanEnd) { leftx = (s32)(leftxf); rightx = (s32)(rightxf + 0.5f); // perform some clipping // TODO: clipping is not correct when leftx is clipped. if (leftx<ViewPortRect.UpperLeftCorner.X) leftx = ViewPortRect.UpperLeftCorner.X; else if (leftx>ViewPortRect.LowerRightCorner.X) leftx = ViewPortRect.LowerRightCorner.X; if (rightx<ViewPortRect.UpperLeftCorner.X) rightx = ViewPortRect.UpperLeftCorner.X; else if (rightx>ViewPortRect.LowerRightCorner.X) rightx = ViewPortRect.LowerRightCorner.X; // draw the span if (rightx - leftx != 0) { tmpDiv = 1.0f / (rightx - leftx); spanZValue = leftZValue; spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv); hSpanBegin = targetSurface + leftx; spanZTarget = zTarget + leftx; hSpanEnd = targetSurface + rightx; while (hSpanBegin < hSpanEnd) { if (spanZValue > *spanZTarget) { *spanZTarget = spanZValue; *hSpanBegin = color; } spanZValue += spanZStep; ++hSpanBegin; ++spanZTarget; } } leftxf += leftdeltaxf; rightxf += rightdeltaxf; ++span; targetSurface += SurfaceWidth; zTarget += SurfaceWidth; leftZValue += leftZStep; rightZValue += rightZStep; } if (triangleHalf>0) // break, we've gout only two halves break; // setup variables for second half of the triangle. if (longest < 0.0f) { tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; rightxf = (f32)v2->Pos.X; rightZValue = v2->ZValue; rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); } else { tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; leftxf = (f32)v2->Pos.X; leftZValue = v2->ZValue; leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); } spanEnd = v3->Pos.Y; } } RenderTarget->unlock(); ZBuffer->unlock(); }
void CTRTextureDetailMap2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) { sScanConvertData scan; sScanLineData line; // sort on height, y if ( a->Pos.y > b->Pos.y ) swapVertices(&a, &b); if ( a->Pos.y > c->Pos.y ) swapVertices(&a, &c); if ( b->Pos.y > c->Pos.y ) swapVertices(&b, &c); // calculate delta y of the edges scan.invDeltaY[0] = c->Pos.y - a->Pos.y; scan.invDeltaY[1] = b->Pos.y - a->Pos.y; scan.invDeltaY[2] = c->Pos.y - b->Pos.y; scan.invDeltaY[0] = inverse32 ( scan.invDeltaY[0] ); scan.invDeltaY[1] = inverse32 ( scan.invDeltaY[1] ); scan.invDeltaY[2] = inverse32 ( scan.invDeltaY[2] ); if ( (f32) 0.0 == scan.invDeltaY[0] ) return; // find if the major edge is left or right aligned f32 temp[4]; temp[0] = a->Pos.x - c->Pos.x; temp[1] = a->Pos.y - c->Pos.y; temp[2] = b->Pos.x - a->Pos.x; temp[3] = b->Pos.y - a->Pos.y; scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > (f32) 0.0 ? 0 : 1; scan.right = 1 - scan.left; // calculate slopes for the major edge scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; scan.x[0] = a->Pos.x; #ifdef IPOL_Z scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; scan.z[0] = a->Pos.z; #endif #ifdef IPOL_W scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; scan.w[0] = a->Pos.w; #endif #ifdef IPOL_C scan.slopeC[0] = (c->Color - a->Color) * scan.invDeltaY[0]; scan.c[0] = a->Color; #endif #ifdef IPOL_T0 scan.slopeT0[0] = (c->Tex0 - a->Tex0) * scan.invDeltaY[0]; scan.t0[0] = a->Tex0; #endif #ifdef IPOL_T1 scan.slopeT1[0] = (c->Tex1 - a->Tex1) * scan.invDeltaY[0]; scan.t1[0] = a->Tex1; #endif // top left fill convention y run s32 yStart; s32 yEnd; s32 y; #ifdef SUBTEXEL f32 subPixel; #endif lockedSurface = (tVideoSample*)RenderTarget->lock(); #ifdef IPOL_Z lockedZBuffer = ZBuffer->lock(); #endif #ifdef IPOL_T0 IT[0].data = (tVideoSample*)IT[0].Texture->lock(); #endif #ifdef IPOL_T1 IT[1].data = (tVideoSample*)IT[1].Texture->lock(); #endif // rasterize upper sub-triangle if ( (f32) 0.0 != scan.invDeltaY[1] ) { // calculate slopes for top edge scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; scan.x[1] = a->Pos.x; #ifdef IPOL_Z scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; scan.z[1] = a->Pos.z; #endif #ifdef IPOL_W scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; scan.w[1] = a->Pos.w; #endif #ifdef IPOL_C scan.slopeC[1] = (b->Color - a->Color) * scan.invDeltaY[1]; scan.c[1] = a->Color; #endif #ifdef IPOL_T0 scan.slopeT0[1] = (b->Tex0 - a->Tex0) * scan.invDeltaY[1]; scan.t0[1] = a->Tex0; #endif #ifdef IPOL_T1 scan.slopeT1[1] = (b->Tex1 - a->Tex1) * scan.invDeltaY[1]; scan.t1[1] = a->Tex1; #endif // apply top-left fill convention, top part yStart = ceil32( a->Pos.y ); yEnd = ceil32( b->Pos.y ) - 1; #ifdef SUBTEXEL subPixel = ( (f32) yStart ) - a->Pos.y; // correct to pixel center scan.x[0] += scan.slopeX[0] * subPixel; scan.x[1] += scan.slopeX[1] * subPixel; #ifdef IPOL_Z scan.z[0] += scan.slopeZ[0] * subPixel; scan.z[1] += scan.slopeZ[1] * subPixel; #endif #ifdef IPOL_W scan.w[0] += scan.slopeW[0] * subPixel; scan.w[1] += scan.slopeW[1] * subPixel; #endif #ifdef IPOL_C scan.c[0] += scan.slopeC[0] * subPixel; scan.c[1] += scan.slopeC[1] * subPixel; #endif #ifdef IPOL_T0 scan.t0[0] += scan.slopeT0[0] * subPixel; scan.t0[1] += scan.slopeT0[1] * subPixel; #endif #ifdef IPOL_T1 scan.t1[0] += scan.slopeT1[0] * subPixel; scan.t1[1] += scan.slopeT1[1] * subPixel; #endif #endif // rasterize the edge scanlines for( y = yStart; y <= yEnd; ++y) { line.y = y; line.x[scan.left] = scan.x[0]; line.x[scan.right] = scan.x[1]; #ifdef IPOL_Z line.z[scan.left] = scan.z[0]; line.z[scan.right] = scan.z[1]; #endif #ifdef IPOL_W line.w[scan.left] = scan.w[0]; line.w[scan.right] = scan.w[1]; #endif #ifdef IPOL_C line.c[scan.left] = scan.c[0]; line.c[scan.right] = scan.c[1]; #endif #ifdef IPOL_T0 line.t0[scan.left] = scan.t0[0]; line.t0[scan.right] = scan.t0[1]; #endif #ifdef IPOL_T1 line.t1[scan.left] = scan.t1[0]; line.t1[scan.right] = scan.t1[1]; #endif // render a scanline scanline_bilinear ( &line ); scan.x[0] += scan.slopeX[0]; scan.x[1] += scan.slopeX[1]; #ifdef IPOL_Z scan.z[0] += scan.slopeZ[0]; scan.z[1] += scan.slopeZ[1]; #endif #ifdef IPOL_W scan.w[0] += scan.slopeW[0]; scan.w[1] += scan.slopeW[1]; #endif #ifdef IPOL_C scan.c[0] += scan.slopeC[0]; scan.c[1] += scan.slopeC[1]; #endif #ifdef IPOL_T0 scan.t0[0] += scan.slopeT0[0]; scan.t0[1] += scan.slopeT0[1]; #endif #ifdef IPOL_T1 scan.t1[0] += scan.slopeT1[0]; scan.t1[1] += scan.slopeT1[1]; #endif } } // rasterize lower sub-triangle if ( (f32) 0.0 != scan.invDeltaY[2] ) { // advance to middle point if( (f32) 0.0 != scan.invDeltaY[1] ) { temp[0] = b->Pos.y - a->Pos.y; // dy scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; #ifdef IPOL_Z scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; #endif #ifdef IPOL_W scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; #endif #ifdef IPOL_C scan.c[0] = a->Color + scan.slopeC[0] * temp[0]; #endif #ifdef IPOL_T0 scan.t0[0] = a->Tex0 + scan.slopeT0[0] * temp[0]; #endif #ifdef IPOL_T1 scan.t1[0] = a->Tex1 + scan.slopeT1[0] * temp[0]; #endif } // calculate slopes for bottom edge scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; scan.x[1] = b->Pos.x; #ifdef IPOL_Z scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; scan.z[1] = b->Pos.z; #endif #ifdef IPOL_W scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; scan.w[1] = b->Pos.w; #endif #ifdef IPOL_C scan.slopeC[1] = (c->Color - b->Color) * scan.invDeltaY[2]; scan.c[1] = b->Color; #endif #ifdef IPOL_T0 scan.slopeT0[1] = (c->Tex0 - b->Tex0) * scan.invDeltaY[2]; scan.t0[1] = b->Tex0; #endif #ifdef IPOL_T1 scan.slopeT1[1] = (c->Tex1 - b->Tex1) * scan.invDeltaY[2]; scan.t1[1] = b->Tex1; #endif // apply top-left fill convention, top part yStart = ceil32( b->Pos.y ); yEnd = ceil32( c->Pos.y ) - 1; #ifdef SUBTEXEL subPixel = ( (f32) yStart ) - b->Pos.y; // correct to pixel center scan.x[0] += scan.slopeX[0] * subPixel; scan.x[1] += scan.slopeX[1] * subPixel; #ifdef IPOL_Z scan.z[0] += scan.slopeZ[0] * subPixel; scan.z[1] += scan.slopeZ[1] * subPixel; #endif #ifdef IPOL_W scan.w[0] += scan.slopeW[0] * subPixel; scan.w[1] += scan.slopeW[1] * subPixel; #endif #ifdef IPOL_C scan.c[0] += scan.slopeC[0] * subPixel; scan.c[1] += scan.slopeC[1] * subPixel; #endif #ifdef IPOL_T0 scan.t0[0] += scan.slopeT0[0] * subPixel; scan.t0[1] += scan.slopeT0[1] * subPixel; #endif #ifdef IPOL_T1 scan.t1[0] += scan.slopeT1[0] * subPixel; scan.t1[1] += scan.slopeT1[1] * subPixel; #endif #endif // rasterize the edge scanlines for( y = yStart; y <= yEnd; ++y) { line.y = y; line.x[scan.left] = scan.x[0]; line.x[scan.right] = scan.x[1]; #ifdef IPOL_Z line.z[scan.left] = scan.z[0]; line.z[scan.right] = scan.z[1]; #endif #ifdef IPOL_W line.w[scan.left] = scan.w[0]; line.w[scan.right] = scan.w[1]; #endif #ifdef IPOL_C line.c[scan.left] = scan.c[0]; line.c[scan.right] = scan.c[1]; #endif #ifdef IPOL_T0 line.t0[scan.left] = scan.t0[0]; line.t0[scan.right] = scan.t0[1]; #endif #ifdef IPOL_T1 line.t1[scan.left] = scan.t1[0]; line.t1[scan.right] = scan.t1[1]; #endif // render a scanline scanline_bilinear ( &line ); scan.x[0] += scan.slopeX[0]; scan.x[1] += scan.slopeX[1]; #ifdef IPOL_Z scan.z[0] += scan.slopeZ[0]; scan.z[1] += scan.slopeZ[1]; #endif #ifdef IPOL_W scan.w[0] += scan.slopeW[0]; scan.w[1] += scan.slopeW[1]; #endif #ifdef IPOL_C scan.c[0] += scan.slopeC[0]; scan.c[1] += scan.slopeC[1]; #endif #ifdef IPOL_T0 scan.t0[0] += scan.slopeT0[0]; scan.t0[1] += scan.slopeT0[1]; #endif #ifdef IPOL_T1 scan.t1[0] += scan.slopeT1[0]; scan.t1[1] += scan.slopeT1[1]; #endif } } RenderTarget->unlock(); #ifdef IPOL_Z ZBuffer->unlock(); #endif #ifdef IPOL_T0 IT[0].Texture->unlock(); #endif #ifdef IPOL_T1 IT[1].Texture->unlock(); #endif }