/*********************************************************************************************** * * Copyright © DreamWorks Interactive. 1996 * * Contents: * Triangle drawing function. The function is a template based on a scanline type. * * Bugs: * * To do: * Add an 'Assert' function to ensure anti-clockwise triangle coordinates are received. * Experiment with tables instead of the compound 'if' statements in the constructor. * If shared edges are rejected, pass only the array of edges to 'RenderFromLeft' and * 'RenderFromRight,' and lump functions only called by the constructor into the * constructor. If shared edges are used, create a new constructor. * * Change the vertex parameter interpolation to work with half-open ranges. For example, * when interpolating from a lighting value of 16.0 to 32.0, it should make the last pixel * end up just below 32.0. Then we won't have to scale the parameter by numbers like * LASTRANGE - 0.01. * * Notes: * The base edge of the triangle is the edge along which the triangle scanline routine * starts. For a triangle with one left edge and two right edges, it is quicker to * calculate increments for, and scan along, the left edge -- the left edge is therefore * the base edge. * * The algorithmic basis for the code implemented here and in reference modules can be * found in "Graphics Gems Vol. III" under "Accurate Polygon Scan Conversion Using * Half-Open Invervals" on page 362. The code is very dissimilar from the example code * in that it uses a faster technique for edge-walking the triangles, and that it is * objected-oriented and templated to work with various scanline types (e.g., flat, * gouraud or linear texture-mapped). * *********************************************************************************************** * * $Log:: /JP2_PC/Source/Lib/Renderer/Primitives/DrawTriangle.hpp $ * * 113 98.09.19 12:39a Mmouni * Added "forceinline" to many small inline functions. * Inlined some functions for speed. * * 112 98.09.10 4:05p Mmouni * Changed fMAX_NEG_AREA (-2*area where sub-triangle are dropped) to * -0.2. * * 111 8/27/98 2:23p Rvande * Changed to constants to floats. * * 110 8/25/98 3:07p Rvande * qualified fixed as being in the global scope * * 109 98.08.19 7:40p Mmouni * Now any polygon that has degenerate sub-triangles will be rendered by * triangulation instead of using the trapezoid renderer. * * 108 98.07.17 6:36p Mmouni * Added new alpha texture primitive. * * 107 98.06.28 4:53p Mmouni * Moved pixel coverage stat calculation to before * InitializePolygonsData to avoid MMX/FPU switching. * * 106 98.06.17 6:46p Mmouni * Not counts pixels base on pre-calculated area. * * 105 98.06.12 3:36p Mmouni * Added optimized versions of planar polygon gradient routines. * * 104 98.06.04 8:13p Mmouni * Changed method used to compute the texture gradients across polygons * with planar values to prevent weird shifting. * * 103 98.05.21 11:32p Mmouni * Added check for valid texture co-ordinates to polygon drawing * routine. * * 102 98.03.24 8:17p Mmouni * Made changes to support alternate perspective correction settings. * * 101 3/05/98 3:38p Pkeet * Added the 'bCAT_PIXEL_STAT' macro switch. Removed unused stats. * * 100 2/26/98 2:54p Mmouni * Added call to done drawing polygon routine for use by the 3dx version * of DrawTriangle. * * 99 98.01.22 3:14p Mmouni * Removed bump-map depth conditional compilation. * * 98 1/19/98 7:34p Pkeet * Added support for 16 bit bumpmaps. * * 97 1/15/98 7:03p Pkeet * Added the polygon lock stat. * * 96 98.01.14 9:08p Mmouni * Made changes for K6 3D polygon setup optimizations. * * 95 1/13/98 1:51p Pkeet * Replaced the auxilary renderer switch with a screen lock. * * 94 1/12/98 11:45a Pkeet * Added in the software lock request for the auxilary renderer. * * 93 97.11.25 7:02p Mmouni * Finished Pentium/Pentium Pro triangle setup optimization. * * 92 97.11.14 11:58p Mmouni * Removed mis-use of erfFILTER flag. * Added specialized versions of InitializePolygonData for terrain * texture. * * 91 97.11.11 9:50p Mmouni * Added iBits to SGlobalRas structure. * * 90 97/11/08 3:41p Pkeet * Removed Z template parameters and code. * * 89 97/10/30 7:05p Pkeet * Added a threshold for using a triangle slope for the trapezoids. * * 88 97/10/28 13:23 Speter * Restored previous SetMinAbs() code, which is needed for proper linear * mapping with traps. * * 87 97.10.27 1:26p Mmouni * Changed to make the pixel coverage stat work correctly. * * 86 97.10.15 7:39p Mmouni * Added support for inline assembly for parts of CDrawPolygon. * * 85 97/10/12 20:34 Speter * Removed fClutRampScale, as cvIntensity is now pre-scaled. * * 84 10/10/97 1:43p Mmouni * All rendering is now left to right. * * 83 8/19/97 5:21p Bbell * Increased the 'iMAX_RASTER_VERTICES' const. * * 82 97/08/07 11:35a Pkeet * Added interface support for mipmapping. * * 81 97/08/05 11:33 Speter * Added psDrawPolygonBegin stat. * * 80 97/07/28 11:16a Pkeet * Uses the 'erfDRAW_CLIP' to set the constant colour to 0 after polygon * data has been set. * * 79 97/07/23 18:00 Speter * Added psDrawPolygonSolid stat. * * 78 97/07/18 3:29p Pkeet * Removed use of the 'b_right' parameter from DrawSubTriangle. * * 77 97/07/16 15:59 Speter * Fixed some bugs in trapezoid renderer, and now use trapezoids for * non-planar polygons as well. Added InitGradientData() to calculate * gradients for trapezoids. InitializeTriangleData now takes two * params to use as coefficients in derivative calculation rather than * f_invdx; also takes b_update parameter to use for multiple-triangle * gradient calculations. Added AssertXRange function to test the * validity of a single scanline. Added iNumRasterVertices global. * Added additional DrawPolygon sub-stats. Removed unneeded fInvDX * member variable. * * 76 97/07/07 14:02 Speter * Now copy vertices for current polygon locally to arvRasterVertices, * which is used rather than rpoly.paprvPolyVertices for most * DrawPolygon code. Renamed iY to iYScr, as it's now a union with * v3Cam, and set in InitializePolygonData. * * 75 97/06/27 15:22 Speter * Now renders trapezoids when able to. Added DrawTrapezoids, * InitTriangleData, InitializeTopVertex. Re-ordered code to allow for * multiple base-edges per polygon. Call new * LINE::InitializePolygonData function. Moved calls to * SetNumIntensities() and fClutRampScale to Gouraud templates. Updated * primitive stats (disabled) for trapezoids. Removed * CalculateTrapStats(). * * 74 97/06/25 1:14p Pkeet * Includes code for displaying depth sort clipping. * * 73 97/06/24 4:22p Pkeet * Made array of edges static to eliminate unnecessary constructor * calls. * * 72 6/19/97 2:53p Mlange * Moved Profile.hpp to Lib/Sys. * * 71 97/06/17 2:03p Pkeet * Removed the reference counting pointer from prasScreen. * * 70 97/06/15 17:27 Speter * Put trapezoid stat code inside bPRIM_STATS compile flag. * * 69 97/06/14 6:46p Pkeet * Fixed compile bug. * * 68 6/15/97 1:43a Bbell * Fixed final mode build problem. * * 67 6/15/97 1:31a Bbell * Removed unnecessary include. * * 66 97/06/13 7:31p Pkeet * Added CDrawPolygonBase and a global raster structure. * * 65 97/06/12 15:29 Speter * CalculateTrapStats is now iffed out. * * 64 97/06/10 15:39 Speter * Removed iY calculation from CDrawPolygon. Now done in pipeline. * * 63 97/06/06 17:15 Speter * Fixes for Final mode (timing stats). * * 62 97/06/05 17:02 Speter * Updated for stats. * * 61 97/06/04 6:45p Pkeet * Moved the profile stats here. * * 60 97/06/03 18:50 Speter * Added #include FixedP.hpp. Moved polygon stats here from * Profile.cpp, added perspective stats. * * 59 97/06/02 13:52 Speter * Added primitive element stats for both triangles and trapezoids. * * 58 97/05/26 2:19p Pkeet * Optimal calculation of the integer Y position. * * 57 97/05/25 18:04 Speter * Changed CDrawTriangle to CDrawPolygon, which calls member * DrawTriangle. Added faster triangulisation. * * 56 97/05/23 17:52 Speter * Added CDrawPolygon<> template, which should be used by all rather * than CDrawTriangle<>. For now CDrawPolygon<> invokes * CDrawTriangle<>. The latter now takes vertex and texture arguments * directly, rather than via SRenderTriangle. Removed * CRenderPolygon::fScreenArea param, now calculate fInvDx directly. * * 55 5/06/97 5:07p Cwalla * Stoped fixed point overloading. * * 54 97-03-31 22:19 Speter * Adjust fInvDx calculation for actual screen area. * Now use CEdge<> line variables rather than slower pointers. * Moved timing calls to DrawSubtriangle.hpp. * * 53 97/02/20 7:19p Pkeet * Removed the vertical scanline loop from the 'RenderFromLeft' and * 'RenderFromRight' member functions in favour of a function call to a * DrawSubtriangle function. Added the necessary includes and changes to * use the new DrawSubtriangle function. Removed the '++' member * function as the code has been moved to the DrawSubtriangle function. * * 52 97/02/19 11:08 Speter * Corrected sign of pixel stat. * * 51 97/02/07 7:44p Pkeet * Removed the 'bValidateHandedness' and 'bSetParialDerivativeRelX' functions in favour of using * the pre-calculated area of the triangle. * * 50 97/01/26 19:54 Speter * Changed valid handedness test to not assert. * Moved scanline timing calls from outside scanline call to outside of sub-triangle loop. * * 49 97/01/16 11:54 Speter * Updated for CProfile changes. * * 48 1/15/97 1:03p Pkeet * Removed fog template parameters. * * 47 1/08/97 7:42p Pkeet * Added an include for CEdge. Removed extraneous scope information from the CDrawTriangle * constructor. * * 46 97/01/07 12:04 Speter * Updated for rptr_const. * * 45 96/12/31 16:58 Speter * Updated for rptr. * * 44 96/12/17 19:23 Speter * Removed psDrawTriangle stat (subsumed in psDrawTriangles). * * 43 96/12/17 13:19 Speter * Moved extern fClutRampScale declaration here from DrawTriangle.hpp. * Moved includes to bottom of file for now, since they contain code. * * * 42 96/12/09 16:18 Speter * Updated for new CProfile members. * * 41 96/12/06 17:58 Speter * Changed profile to use new CCycleTimer class and Add() function. * * 40 12/06/96 5:14p Pkeet * Commented out seperate left and right drawing routines. * * 39 12/06/96 3:51p Pkeet * Added the bModified global flag. * * 38 96/12/05 16:48 Speter * Removed #ifdef on profile calls. * * 37 12/05/96 1:17p Pkeet * Added profiling from the Profile.hpp module. * * 36 11/12/96 2:46p Pkeet * Added support for initializing self-modifying code on a per-triangle basis. * * 35 10/11/96 10:31a Pkeet * Added 'pvClutConversion' as a global variable instead of a member of 'CDrawTriangle.' No clut * pointer is therefore passed to the 'DrawLoop' functions. * * 34 10/10/96 8:20p Pkeet * Moved extern out of this module. * * 33 10/10/96 7:58p Pkeet * Made statically declared variables externally declared variables. * * 32 10/09/96 7:44p Pkeet * Changed the 'LineFlatZ.hpp' include to the 'Scanline.hpp' include. Changed references from * 'CLineFlatZ' to 'CScanline.' Removed the 'pixPixel' and 'ptexTexture' global variables. Moved * the 'iDefaultFog' global to the fog template module. Removed the 'fSCALE_ADJUST' const. Added * the 'pdpixClut' and 'ptexTexture' member variables. * * 31 96/10/08 19:26 Speter * Added stats for scanline timing and number of pixels drawn. * * 30 96/10/04 18:39 Speter * Added necessary include. * * 29 96/10/04 18:02 Speter * Removed defunct ObjDef2D.hpp include. Added RenderDefs.hpp. * * 28 10/04/96 3:51p Pkeet * Added the CZBuffer class as a template parameter to CLineFlatZ. * * 27 10/03/96 6:17p Pkeet * Removed pvClutTable in favour of a member variable of the triangle. * * 26 10/03/96 3:14p Pkeet * Removed constants and global variables associated with Gouraud shading. Removed extraneous * includes. Added includes removed from 'ScreenRenderDWI.cpp.' * * 25 9/27/96 4:32p Pkeet * Removed the 'LineGouraudZ' template class. * * 24 9/24/96 2:53p Pkeet * Calculates a 'fClutRampScale' value from the number of ramp values in a clut only when a clut * is present, otherwise uses the default value. The test for a valid Z-buffer present was moved * from this primitive to the 'ScreenRenderDWI' module. * * 23 8/21/96 4:44p Pkeet * Moved 'pixPixel.' * * 22 8/20/96 4:47p Pkeet * Added the 'iDefaultFog' variable. * * 21 96/08/09 11:05 Speter * Changed zbuffer from CRasterMemT to simple CRaster, because with D3D, z buffer might * be different depth. * * 20 7/31/96 12:38p Pkeet * Added 'fGouraudTolerance' constant. * * 19 7/29/96 2:15p Pkeet * Made the 'SRenderCoord' struct non-const. * * 18 96/07/26 18:22 Speter * Changed scaling of vertex parameters again. Now all increments are scaled by parameter size, * actual values are scaled by parameter size minus one, and 0.5 is added. * * 17 96/07/26 10:53 Speter * Added fSCALE_ADJUST parameter for vertex parameter scaling adjustment. A value of 1.0 for * this prevents crashes, but we must still determine the reallly correct way of scaling. * * 16 96/07/24 14:54 Speter * Added fClutRampScale global variable, and some comments. * * 15 96/07/22 15:24 Speter * Moved pixSolid global variable to LineFlatZ.hpp. * * 14 7/18/96 5:43p Pkeet * Changed iY asserts to match height range. * * 13 96/07/18 17:18 Speter * Changes affecting zillions of files: * Changed SRenderCoord to SRenderVertex. * Added SRenderTriangle type, changed drawing primitives to accept it. * * 12 7/17/96 12:06p Pkeet * Moved the drawing primitives up by 1 so that they clip correctly. * * 11 96/07/16 13:14 Speter * Changed iPixelSolid to pixSolid. * * 10 96/07/15 18:58 Speter * Changed u4_data param to CTexture*. * Added static globals: ptexTexture, pvClutTable, pixPixel. * * 9 7/09/96 3:22p Pkeet * Moved 'i4DInvZ' to LineFlatZ.hpp. * * 8 7/08/96 3:28p Pkeet * Moved 'i4DInvZ.' * * 7 6/25/96 2:31p Pkeet * Made 'u4Data' a global variable instead of a member variable of 'CDrawTriangle.' * * 6 6/17/96 6:42p Pkeet * Added 'iFastPosFloatToInt' use. * * 5 6/13/96 8:31p Pkeet * Eliminated fast float to int conversions for now. * * 4 6/13/96 3:23p Pkeet * Added comments. * * 3 6/13/96 3:08p Pkeet * Changed 'CDrawTriangle' prefix. Added to the 'to do' list. Added asserts. Added references to * texts. * * 2 6/06/96 7:57p Pkeet * Changed calls to 'DrawFromLeft' and 'DrawFromRight' to reflect their new status as template * functions as opposed to member functions. * * 1 6/06/96 5:38p Pkeet * Initial implementation. 'CDrawTriangle' now combines aspects of the old 'CPoly' object with * the draw functions added as member functions. * **********************************************************************************************/ #ifndef HEADER_RENDERER_PRIMITIVES_DRAWTRIANGLE_HPP #define HEADER_RENDERER_PRIMITIVES_DRAWTRIANGLE_HPP // // Necessary includes for triangle drawing. // #include "Lib/Sys/Profile.hpp" #include "Lib/Renderer/ScreenRender.hpp" #include "Lib/View/Raster.hpp" #include "Lib/Types/FixedP.hpp" #include "Edge.hpp" #define bPRIM_STATS (0) #define bPOLY_STATS (0) #define bPIXEL_COVERAGE_STAT (1) #define bCAT_PIXEL_STAT (0) #define bLOCK_STAT (1) // // Global constants & variables. // const int iMAX_RASTER_VERTICES = 64; const float fMAX_NEG_AREA = -0.2; extern SRenderVertex arvRasterVertices[iMAX_RASTER_VERTICES]; extern int iNumRasterVertices; extern bool bModified; extern int iDefaultFog; // Stats, relative to proProfile.psDrawPolygon. extern CProfileStat psDrawPolygonInit; extern CProfileStat psDrawPolygonBump; #if bLOCK_STAT extern CProfileStat psDrawPolygonLock; #endif #if bPOLY_STATS extern CProfileStat psDrawPolygonBegin; extern CProfileStat psDrawPolygonData; extern CProfileStat psDrawPolygonEdges; extern CProfileStat psDrawPolygonWalk; #endif extern CProfileStatParent psPixels; #if bCAT_PIXEL_STAT extern CProfileStat psPixelsPerspective; extern CProfileStat psPixelsC; #endif #if bPRIM_STATS extern CProfileStat psSubpolygons; extern CProfileStat psTrapezoids; extern CProfileStat psBaseEdges; extern CProfileStat psEdges; extern CProfileStat psLines; #endif // // Forward declarations of classes and functions. // //********************************************************************************************* template class CScanline; //********************************************************************************************* template class CDrawPolygon; //***************************************************************************************** template void DrawSubtriangle(LINE* pscan, CDrawPolygon* pdtriTriangle); // // Global templated helper functions used in CDrawPolygon. // template void InitializePolygonData(LINE& lineData, CRenderPolygon* rpoly); template void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); template bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); template bool bInitGradientDataPlanarEx(CDrawPolygon* poly); template void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); template void DoneDrawingPolygon(CDrawPolygon* poly); // // Global functions. // //********************************************************************************************* inline int iPrev ( int i ) { return i > 0 ? i-1 : iNumRasterVertices - 1; } //********************************************************************************************* inline int iNext ( int i ) { i++; return i < iNumRasterVertices ? i : 0; } //********************************************************************************************* // template inline void SetMinAbs ( T& t_a, // Variable to set. T t_b // Value to compare with. ) // // Set t_a to t_b if the absolute value of t_b is less than t_a. // //************************************** { // if (Abs(t_b) < Abs(t_a)) // t_a = t_b; if (t_a >= 0) { if (t_b < 0) t_a = 0; else SetMin(t_a, t_b); } else { if (t_b > 0) t_a = 0; else SetMax(t_a, t_b); } } //********************************************************************************************* // template inline void SetMaxAbs ( T& t_a, // Variable to set. T t_b // Value to compare with. ) // // Set t_a to t_b if the absolute value of t_b is greater than t_a. // //************************************** { if (Abs(t_b) > Abs(t_a)) t_a = t_b; } // // Structure Definitions. // //********************************************************************************************* // struct SGlobalRas // // A global raster description for use by subtriangle asm blocks. // // Prefix: gs // //************************************** { void* pvScreen; // Screen buffer. uint32 u4LinePixels; // Screen buffer stride. int iBits; // Bits per pixel (15 or 16). }; // Global structure. extern SGlobalRas gsGlobals; // // Class definitions. // //********************************************************************************************* // class CDrawPolygonBase // // Describes a polygon rasterizing structure that is independant of template types. // // Prefix: polybase // //************************************** { public: // Force default constructor inline so it is not called. forceinline CDrawPolygonBase() { } int iY; // Current scanline being rasterized. int iYTo; // Last scanline to be rasterized along the current // pair of left and right edges. int iLineStartIndex; // Index to the first pixel in the current horizontal line. ::fixed fxLineLength; // Length of the current scanline. ::fixed fxDeltaLineLength; // Increment of the length of the scanline for the current // pair of left and right edges. }; //********************************************************************************************* // template class CDrawPolygon : public CDrawPolygonBase // // Describes triangle rasterizing data based on a scanline type. Sets up the basic information // of the plane, and performs plane data lineIncrements per scanline. // // Prefix: tri // //************************************** { public: CRaster* prasScreen; // Pointer to the main screen raster. ptr_const ptexTexture; // Pointer to the source texture. LINE lineData; // Storage for triangle-wide data based on the // scanline type. CEdge* pedgeBase; // Base edge. CRenderPolygon* prpolyPoly; // Render polygon. public: //***************************************************************************************** // // CDrawPolygon constructors. // //***************************************************************************************** // CDrawPolygon ( CRaster* pras_screen, // Address of the screen buffer. CRenderPolygon& rpoly // Info on polygon to render. ) // // Draws a polygon by splitting into triangles and calling DrawTriangle. // // Notes: // This class assumes that: // // * The polygon coordinates are provided in an anti-clockwise direction. // // * 0.5 has been added to the x and y values of the screen coordinates to cause // pixels to be lit according to their centres as opposed to their top left // corners. // //************************************** { CCycleTimer ctmr; #if (VER_DEBUG) rpoly.Validate(); #endif // // Copy data to CDrawPolygon member variables. // bModified = false; prpolyPoly = &rpoly; Assert(pras_screen); prasScreen = pras_screen; ptexTexture = rpoly.ptexTexture; #if bPIXEL_COVERAGE_STAT // Add timing information. Area = -0.5 * dx. int iArea = iRound(rpoly.fArea); psPixels.Add(0, iArea); #if bCAT_PIXEL_STAT if (LINE::TIndex::bIsPerspective()) psPixelsPerspective.Add(0, iArea); #endif #endif InitializePolygonData(lineData, &rpoly); // // Test to see if the polygon is supposed to render black only. If it is, changed // the flat colour to black. // if (rpoly.seterfFace[erfDRAW_CLIP]) { u4ConstColour = 0; } iNumRasterVertices = rpoly.paprvPolyVertices.uLen; #if bPOLY_STATS psDrawPolygonBegin.Add(ctmr(), 1); #endif if (iNumRasterVertices <= 3) { // Render the triangle. DrawTriangle ( &arvRasterVertices[0], &arvRasterVertices[1], &arvRasterVertices[2] ); } else { // // Subdivide the polygon. // // Check menu setting before enabling trapezoidalisation. if (rpoly.seterfFace[erfTRAPEZOIDS]) { DrawTrapezoids(); } else { DrawTriangulated(); } } DoneDrawingPolygon(this); } //***************************************************************************************** // bool bInitTriangleData ( SRenderVertex* prv_a, // 3 vertices making up this triangle. SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update = false ) // // Sets up triangle-wide rasterising info. // // Returns: // Whether the triangle is large enough to render. // //************************************** { Assert(prv_a); Assert(prv_b); Assert(prv_c); // // Calculate fInvDx, the partial derivative of x over the triangle, using the following // formula: // // 1 1 // fInvDx = ---- = --------------------------------------- // dx (x2 - x1)(y3 - y1) - (x3 - x1)(y2 - y1) // // dx also happens to be -2 times the area of the triangle, so we can check for correct // orientation here as well. // float f_yab = (prv_b->v3Screen.tY - prv_a->v3Screen.tY); float f_yac = (prv_c->v3Screen.tY - prv_a->v3Screen.tY); float f_dx = (prv_b->v3Screen.tX - prv_a->v3Screen.tX) * f_yac - (prv_c->v3Screen.tX - prv_a->v3Screen.tX) * f_yab; if (f_dx >= fMAX_NEG_AREA) return false; // Calculate coefficients to pass to template InitializeTriangleData functions. float f_invdx = 1.0f / f_dx; float f_yab_invdx = f_yab * f_invdx; float f_yac_invdx = f_yac * f_invdx; // Calculate triangle data for the line type. lineData.InitializeTriangleData(prv_a, prv_b, prv_c, f_yab_invdx, f_yac_invdx, ptexTexture, b_update, prpolyPoly->seterfFace[erfSOURCE_TERRAIN]); return true; } //***************************************************************************************** // bool bInitGradientDataPlanar ( ) // // Sets up polygon-wide rasterising info. // // Returns: // Whether the polygon is large enough to render. // //************************************** { SRenderVertex *prv_a = &arvRasterVertices[iNumRasterVertices-2]; SRenderVertex *prv_b = &arvRasterVertices[iNumRasterVertices-1]; SRenderVertex *prv_c = &arvRasterVertices[0]; SRenderVertex *prv_a_min = prv_a; SRenderVertex *prv_b_min = prv_b; SRenderVertex *prv_c_min = prv_c; // // Find the first edge pair with an area greater than 25 pixels, or if no // edge pair has an area greater than 25 pixels find the maximum. // float f_yab_min = (prv_b->v3Screen.tY - prv_a->v3Screen.tY); float f_yac_min = (prv_c->v3Screen.tY - prv_a->v3Screen.tY); float f_dx_min = (prv_b->v3Screen.tX - prv_a->v3Screen.tX) * f_yac_min - (prv_c->v3Screen.tX - prv_a->v3Screen.tX) * f_yab_min; for (int i = 1; i < iNumRasterVertices && f_dx_min > -50.0f; i++) { prv_a = prv_b; prv_b = prv_c; prv_c = &arvRasterVertices[i]; float f_yab = (prv_b->v3Screen.tY - prv_a->v3Screen.tY); float f_yac = (prv_c->v3Screen.tY - prv_a->v3Screen.tY); float f_dx = (prv_b->v3Screen.tX - prv_a->v3Screen.tX) * f_yac - (prv_c->v3Screen.tX - prv_a->v3Screen.tX) * f_yab; if (f_dx < f_dx_min) { f_yab_min = f_yab; f_yac_min = f_yac; f_dx_min = f_dx; prv_a_min = prv_a; prv_b_min = prv_b; prv_c_min = prv_c; } } // Is the polygon too small to draw? if (f_dx_min >= fMAX_NEG_AREA) return false; #if bPIXEL_COVERAGE_STAT // Add timing information. Area = -0.5 * dx. psPixels.Add(0, iRound(f_dx_min * -0.5f)); #if bCAT_PIXEL_STAT if (LINE::TIndex::bIsPerspective()) psPixelsPerspective.Add(0, iRound(f_dx_min * -0.5f)); #endif #endif // Calculate coefficients to pass to template InitializeTriangleData functions. float f_invdx = 1.0f / f_dx_min; float f_yab_invdx = f_yab_min * f_invdx; float f_yac_invdx = f_yac_min * f_invdx; // Calculate triangle data for the line type. lineData.InitializeTriangleData(prv_a, prv_b, prv_c, f_yab_invdx, f_yac_invdx, ptexTexture, 0, prpolyPoly->seterfFace[erfSOURCE_TERRAIN]); return true; } protected: //***************************************************************************************** // // CDrawPolygon member functions. // //***************************************************************************************** // void DrawTriangle ( SRenderVertex* prv_a, // 3 vertices making up this triangle. SRenderVertex* prv_b, SRenderVertex* prv_c ) // // Draws a triangle by building edges and scanning through those edges either left-to-right // or right-to-left. The direction of the scanning depends on which way the triangle points // along the horizontal screen axis. // //************************************** { CCycleTimer ctmr; int dir; #if bPRIM_STATS psSubpolygons.Add(0, 1); #endif // // Determine where to start walking the edges of the triangle, and the base edge of the // triangle. There are only six basic patterns for walking the edges of an // anti-clockwise triangle. Where 'a', 'b' and 'c' represent the vertices of a triangle, // 'ab', 'bc' and 'ca' represent the edges of a triangle and where 'L' stands for left // and 'R' stands for right, the decision tree for walking the triangle this is: // // ab is // /\ // L / \ R // / \ // ---------------- ---------------- // | | // bc is bc is // /\ /\ // L / \ R L / \ R // / \ / \ // ------- --- --- ------- // | L | R | | | | L | R | // | ab| ca| ca is ca is | ca| bc| // | bc| | /\ /\ | | ab| // ------- L / \ R L / \ R ------- // / \ / \ // ------- ------- ------- ------- // | L | R | | L | R | | L | R | | L | R | // | ca| bc| | ab| ca| | bc| ab| | bc| ab| // | ab| | | | bc| | ca| | | | ca| // ------- ------- ------- ------- // // The order of edge walking will be set to this tree, and the i4ScanlineDirection // variable will be set to 1 if the triangle is rasterized from the left to right, // otherwise it will be set to -1. If an edge doesn't cross a horizontal scanline, // it is assumed to be a right edge. // CEdge pedge[3]; // Edge list. // If ab is left: if (prv_a->iYScr < prv_b->iYScr) { // If bc is left: if (prv_b->iYScr < prv_c->iYScr) { dir = -1; InitializeEdge(pedge[0], prv_a, prv_b); InitializeEdge(pedge[1], prv_b, prv_c); InitializeEdge(pedge[2], prv_a, prv_c); } else { // If ca is left: if (prv_c->iYScr < prv_a->iYScr) { dir = -1; InitializeEdge(pedge[0], prv_c, prv_a); InitializeEdge(pedge[1], prv_a, prv_b); InitializeEdge(pedge[2], prv_c, prv_b); } else { dir = 1; InitializeEdge(pedge[0], prv_a, prv_b); InitializeEdge(pedge[1], prv_a, prv_c); InitializeEdge(pedge[2], prv_c, prv_b); } } } else { // If bc is left: if (prv_b->iYScr < prv_c->iYScr) { // If ca is left: if (prv_c->iYScr < prv_a->iYScr) { dir = -1; InitializeEdge(pedge[0], prv_b, prv_c); InitializeEdge(pedge[1], prv_c, prv_a); InitializeEdge(pedge[2], prv_b, prv_a); } else { dir = 1; InitializeEdge(pedge[0], prv_b, prv_c); InitializeEdge(pedge[1], prv_b, prv_a); InitializeEdge(pedge[2], prv_a, prv_c); } } else { // bc is right. dir = 1; InitializeEdge(pedge[0], prv_c, prv_a); InitializeEdge(pedge[1], prv_c, prv_b); InitializeEdge(pedge[2], prv_b, prv_a); } } // Always render left-to-right. i4ScanlineDirection = 1; #if bPOLY_STATS psDrawPolygonEdges.Add(ctmr(), 1); #endif if (!bInitTriangleDataEx(this, prv_a, prv_b, prv_c, false)) return; #if bPOLY_STATS psDrawPolygonData.Add(ctmr(), 1); #endif #if bPRIM_STATS psEdges.Add(0, 3); #endif // // Walk along left or right edges depending on which is faster. // if (dir > 0) { RenderFromLeft(&pedge[0], &pedge[1], &pedge[2]); } else { RenderFromRight(&pedge[0], &pedge[1], &pedge[2]); } } //***************************************************************************************** // void DrawTriangulated() // // Draws a polygon by subdividing into triangles and then dividing the triangles into // sub-trapezoids. // //************************************** { // Find top point. int i_ymin = iTopIndex(); // Render the top triangle. int i_a = iPrev(i_ymin); int i_b = i_ymin; int i_c = iNext(i_ymin); // // From here, proceed to triangulate downwards. // int i_aa = iPrev(i_a); int i_cc = iNext(i_c); for (;;) { DrawTriangle ( &arvRasterVertices[i_a], &arvRasterVertices[i_b], &arvRasterVertices[i_c] ); if (i_aa == i_cc) { // Bottom triangle. DrawTriangle ( &arvRasterVertices[i_a], &arvRasterVertices[i_c], &arvRasterVertices[i_cc] ); break; } // Advance to next lowest vertex. if (arvRasterVertices[i_aa].iYScr < arvRasterVertices[i_cc].iYScr) { i_b = i_a; i_a = i_aa; i_aa = iPrev(i_a); } else { i_b = i_c; i_c = i_cc; i_cc = iNext(i_c); } } } //***************************************************************************************** // bool bInitGradientData ( int i_left1, // Top vertices of polygon. int i_right1, bool& b_bad_subtriangles // Set to true if any sub-triangles are too small to render. ) // //************************************** { // // Iteratate all the trapezoids, finding optimal gradients. // bool b_update; bool b_good; // Find next coordinates. int i_left2 = iNext(i_left1); int i_right2 = iPrev(i_right1); // Initialise gradients based on top trapezoid. b_good = bInitTriangleDataEx ( this, &arvRasterVertices[i_left1], &arvRasterVertices[i_left2], &arvRasterVertices[i_right2], false ); b_update = b_good; b_bad_subtriangles = !b_good; if (i_left1 != i_right1 && i_left2 != i_right2) { // The top is a trapezoid; update from bottom right triangle. b_good = bInitTriangleDataEx ( this, &arvRasterVertices[i_left1], &arvRasterVertices[i_right2], &arvRasterVertices[i_right1], b_update ); b_update |= b_good; b_bad_subtriangles |= !b_good; } // Iterate through remaining trapezoids. for (;;) { if (i_left2 == i_right2) // We just did bottom triangle. break; int i_diff = arvRasterVertices[i_left2].iYScr - arvRasterVertices[i_right2].iYScr; if (i_diff <= 0) { // New left vertex and edge. i_left1 = i_left2; i_left2 = iNext(i_left2); if (i_diff == 0 && i_left2 == i_right2) // We just hit bottom trap. break; // Update for new left. if (i_left2 != i_right2) { b_good = bInitTriangleDataEx ( this, &arvRasterVertices[i_left2], &arvRasterVertices[i_right2], &arvRasterVertices[i_left1], b_update ); b_update |= b_good; b_bad_subtriangles |= !b_good; } } if (i_diff >= 0) { // New right vertex and edge. i_right1 = i_right2; i_right2 = iPrev(i_right2); // Update for new right. if (i_left2 != i_right2) { b_good = bInitTriangleDataEx ( this, &arvRasterVertices[i_left2], &arvRasterVertices[i_right2], &arvRasterVertices[i_right1], b_update ); b_update |= b_good; b_bad_subtriangles |= !b_good; } } } return b_update; } //***************************************************************************************** // void DrawTrapezoids() // // Draws a polygon by subdividing into trapezoids, and building edges as necessary. // Each trapezoid is always rendered left-to-right. // //************************************** { CCycleTimer ctmr; #if bPRIM_STATS psSubpolygons.Add(0, 1); #endif // Find top trapezoid. int i_right1 = iTopIndex(); // May not be unique top point; check adjacent points for same scanline. int i_left1 = iNext(i_right1); if (arvRasterVertices[i_left1].iYScr > arvRasterVertices[i_right1].iYScr) { i_left1 = i_right1; // Try previous vertex. i_right1 = iPrev(i_left1); if (arvRasterVertices[i_right1].iYScr > arvRasterVertices[i_left1].iYScr) // Pointy top. i_right1 = i_left1; } if (LINE::bIsPlanar()) { // Find gradients. if (!bInitGradientDataPlanarEx(this)) return; } else { // Find gradients. bool b_bad_subtriangles = false; if (!bInitGradientData(i_left1, i_right1, b_bad_subtriangles)) return; // If one or more sub-triangles were bad, don't use the trapezoid renderer. if (b_bad_subtriangles) { DrawTriangulated(); return; } } #if bPOLY_STATS psDrawPolygonData.Add(ctmr(), 1); #endif // Always render left-to-right. i4ScanlineDirection = 1; // The two edge structures re-used throughout this polygon. CEdge edge_left, edge_right; int i_left2 = iNext(i_left1); int i_right2 = iPrev(i_right1); // Initialise the first two edges. InitializeEdge(edge_left, &arvRasterVertices[i_left1], &arvRasterVertices[i_left2]); InitializeEdge(edge_right, &arvRasterVertices[i_right1], &arvRasterVertices[i_right2]); #if bPRIM_STATS psEdges.Add(0, 2); #endif fxLineLength = edge_right.lineStart.fxX - edge_left.lineStart.fxX; InitializeTopVertex(edge_left.prvFrom); InitializeForWalkEx(this, &edge_left); #if bPOLY_STATS psDrawPolygonEdges.Add(ctmr(), 1); #endif #if bLOCK_STAT { CCycleTimer ctmr_lock; prasScreen->Lock(); psDrawPolygonLock.Add(ctmr_lock(), 1); } #else // Lock the surface for renderering. prasScreen->Lock(); #endif // Render this and subsequent trapezoids. for (;;) { // // Render the current trapezoid. // // Find the bottom of the current trapezoid. iYTo = Min(edge_left.prvTo->iYScr, edge_right.prvTo->iYScr); if (iY < iYTo) { #if bPRIM_STATS psTrapezoids.Add(0, 1); #endif fxDeltaLineLength = edge_right.lineIncrement.fxX - edge_left.lineIncrement.fxX; edge_left.lineStart.AssertXRange(fxLineLength); #if bPOLY_STATS psDrawPolygonWalk.Add(ctmr(), 1); #endif DrawSubtriangle(&edge_left.lineStart, this); psPixels.Add(ctmr()); } if (i_left2 == i_right2) // We just did bottom triangle. break; int i_diff = edge_left.prvTo->iYScr - edge_right.prvTo->iYScr; if (i_diff <= 0) { // New left vertex and edge. i_left1 = i_left2; i_left2 = iNext(i_left2); if (i_diff == 0 && i_left2 == i_right2) // We just hit bottom trap. break; // Update line length for more accuracy, adjusting by the difference between the // accumulated X of the left edge, and the exact X of the new left vertex. fxLineLength += edge_left.lineStart.fxX; InitializeEdge(edge_left, &arvRasterVertices[i_left1], &arvRasterVertices[i_left2]); #if bPRIM_STATS psEdges.Add(0, 1); #endif InitializeForWalkEx(this, &edge_left); fxLineLength -= edge_left.lineStart.fxX; } if (i_diff >= 0) { // New right vertex and edge. i_right1 = i_right2; i_right2 = iPrev(i_right2); InitializeEdge(edge_right, &arvRasterVertices[i_right1], &arvRasterVertices[i_right2]); #if bPRIM_STATS psEdges.Add(0, 1); #endif // Update line length for more accuracy, using exact X of new right vertex, // and accumulated X of left edge. fxLineLength = edge_right.lineStart.fxX - edge_left.lineStart.fxX; } } #if bPOLY_STATS psDrawPolygonWalk.Add(ctmr(), 1); #endif } //***************************************************************************************** // forceinline int iTopIndex() // // Returns: // The index of the topmost (lowest Y) vertex. // //********************************** { // Find top point. int i_ymin = 0; for (int i = 1; i < iNumRasterVertices; i++) { if (arvRasterVertices[i].iYScr < arvRasterVertices[i_ymin].iYScr) i_ymin = i; } return i_ymin; } //***************************************************************************************** // forceinline void InitializeTopVertex ( SRenderVertex* prv_top ) // // Sets the line walking variables for the top of any sub-polygon. // //************************************** { iY = prv_top->iYScr; iLineStartIndex = iY * prasScreen->iLinePixels; } //***************************************************************************************** // forceinline void InitializeForWalk ( CEdge* pedge // Base edge. ) // // Prepares triangle for edge walking given a base edge. // //************************************** { Assert(pedge); #if bPRIM_STATS psBaseEdges.Add(0, 1); psLines.Add(0, pedge->prvTo->iYScr - pedge->prvFrom->iYScr); #endif // Initialize edge chosen to be the base edge. pedge->lineStart.InitializeAsBase(pedge, this); } //***************************************************************************************** // forceinline bool bBeginValidEdge ( const CEdge* pedge_opposite // Edge opposite the base edge. ) // // Prepares triangle for edge walking based on a left and right edge. // // Returns: // Returns 'true' if the edge is visible, otherwise returns 'false.' // //************************************** { Assert(pedge_opposite); Assert(pedge_opposite->prvTo); iYTo = pedge_opposite->prvTo->iYScr; return iY < iYTo; } //***************************************************************************************** // forceinline void InitializeForEdge ( const CEdge* pedge_left, // Base edge. const CEdge* pedge_right // Edge opposite the base edge. ) // // Updates triangle information for rasterizing a new edge. // //************************************** { Assert(pedge_left); Assert(pedge_right); #if bPRIM_STATS psTrapezoids.Add(0, 1); #endif fxLineLength = (pedge_right->lineStart.fxX - pedge_left->lineStart.fxX); fxDeltaLineLength = (pedge_right->lineIncrement.fxX - pedge_left->lineIncrement.fxX); } //***************************************************************************************** // forceinline void RenderFromLeft ( CEdge* pedge_left, CEdge* pedge_right0, CEdge* pedge_right1 ) // // Scans through triangle edges using the single left edge as the base edge. // // Notes: // The triangle is subdivided and scanned as follows: // // |\ // | \ // | \ right edge 0: // left edge | \ (top triangle subdivision) // (base edge) | \ // | \ // |------- // | / // | / // | / // | / right edge 1: // | / (bottom triangle subdivision) // | / // |/ // //************************************** { CCycleTimer ctmr; Assert(pedge_left); Assert(pedge_right0); Assert(pedge_right1); InitializeTopVertex(pedge_left->prvFrom); // Initialize triangle-wide data based on the single left edge. InitializeForWalkEx(this, pedge_left); #if bPOLY_STATS psDrawPolygonWalk.Add(ctmr(), 1); #endif #if bLOCK_STAT { CCycleTimer ctmr_lock; prasScreen->Lock(); psDrawPolygonLock.Add(ctmr_lock(), 1); } #else // Lock the surface for renderering. prasScreen->Lock(); #endif // Scan top sub-triangle of the triangle. if (bBeginValidEdge(pedge_right0)) { InitializeForEdge(pedge_left, pedge_right0); { pedge_left->lineStart.AssertXRange(fxLineLength); #if bPOLY_STATS psDrawPolygonWalk.Add(ctmr(), 1); #endif DrawSubtriangle(&pedge_left->lineStart, this); psPixels.Add(ctmr()); } } // Scan the bottom sub-triangle of the triangle. if (bBeginValidEdge(pedge_right1)) { InitializeForEdge(pedge_left, pedge_right1); { pedge_left->lineStart.AssertXRange(fxLineLength); #if bPOLY_STATS psDrawPolygonWalk.Add(ctmr(), 1); #endif DrawSubtriangle(&pedge_left->lineStart, this); psPixels.Add(ctmr()); } } } //***************************************************************************************** // forceinline void RenderFromRight ( CEdge* pedge_left0, CEdge* pedge_left1, CEdge* pedge_right ) // // Scans through triangle edges using the two left edges as base edges. // // Notes: // The triangle is subdivided and scanned as follows: // // /| // / | // left edge 0: / | // (top triangle / | right edge // subdivision) / | // / | // -------| // \ | // \ | // left edge 1: \ | // (bottom triangle \ | // subdivision) \ | // \ | // \| // //************************************** { CCycleTimer ctmr; Assert(pedge_left0); Assert(pedge_left1); Assert(pedge_right); InitializeTopVertex(pedge_left0->prvFrom); InitializeForWalkEx(this, pedge_left0); fxLineLength = (pedge_right->lineStart.fxX - pedge_left0->lineStart.fxX); #if bPOLY_STATS psDrawPolygonWalk.Add(ctmr(), 1); #endif #if bLOCK_STAT { CCycleTimer ctmr_lock; prasScreen->Lock(); psDrawPolygonLock.Add(ctmr_lock(), 1); } #else // Lock the surface for renderering. prasScreen->Lock(); #endif // Scan top sub-triangle of the triangle. iYTo = pedge_left0->prvTo->iYScr; if (iY < iYTo) { fxDeltaLineLength = (pedge_right->lineIncrement.fxX - pedge_left0->lineIncrement.fxX); pedge_left0->lineStart.AssertXRange(fxLineLength); #if bPOLY_STATS psDrawPolygonWalk.Add(ctmr(), 1); #endif DrawSubtriangle(&pedge_left0->lineStart, this); psPixels.Add(ctmr()); } // Scan the bottom sub-triangle of the triangle. iYTo = pedge_left1->prvTo->iYScr; if (iY < iYTo) { InitializeForWalkEx(this, pedge_left1); // Update line length for more accuracy, adjusting by the difference between the // accumulated X of the left edge, and the exact X of the new left vertex. fxLineLength += pedge_left0->lineStart.fxX; fxLineLength -= pedge_left1->lineStart.fxX; fxDeltaLineLength = (pedge_right->lineIncrement.fxX - pedge_left1->lineIncrement.fxX); pedge_left1->lineStart.AssertXRange(fxLineLength); #if bPOLY_STATS psDrawPolygonWalk.Add(ctmr(), 1); #endif DrawSubtriangle(&pedge_left1->lineStart, this); psPixels.Add(ctmr()); } } }; // // Template parameter includes. // #include "GouraudT.hpp" #include "TransparencyT.hpp" #include "MapT.hpp" #include "IndexT.hpp" #include "ColLookupT.hpp" #include "Edge.hpp" #include "Scanline.hpp" #include "DrawSubTriangle.hpp" #if (VER_ASM) // // Custom optimized versions of selected global templated polygon setup functions. // void InitializePolygonData(TCopyPersp& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TCopyPerspTrans& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TCopyTerrainPersp& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTexturePersp& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTexturePerspTrans& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTexturePerspGour& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTexturePerspTransGour& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TBumpPersp& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TBumpPerspTrans& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TGFogPersp& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TCopyLinear& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TCopyLinearTrans& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TCopyTerrainLinear& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTextureLinear& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTextureLinearTrans& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTextureLinearGour& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTextureLinearTransGour& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TBumpLinear& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TBumpLinearTrans& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TGFogLinear& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTexNoClutLinear& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TTexNoClutLinearTrans& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TShadowTrans8& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TShadowTrans32& lineData, CRenderPolygon* rpoly); #if (BILINEAR_FILTER) void InitializePolygonData(TCopyPerspFilter& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TCopyLinearFilter& lineData, CRenderPolygon* rpoly); #endif void InitializePolygonData(TStippleTexPersp& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TStippleTexLinear& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TWaterPersp& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TWaterLinear& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TAlphaTexPersp& lineData, CRenderPolygon* rpoly); void InitializePolygonData(TAlphaTexLinear& lineData, CRenderPolygon* rpoly); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); #if (BILINEAR_FILTER) void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); #endif void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); void InitializeEdge(CEdge& edge, SRenderVertex* prv_from, SRenderVertex* prv_to); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); #if (BILINEAR_FILTER) bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); #endif bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitTriangleDataEx(CDrawPolygon* poly, SRenderVertex* prv_a, SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); #if (BILINEAR_FILTER) bool bInitGradientDataPlanarEx(CDrawPolygon* poly); #endif bool bInitGradientDataPlanarEx(CDrawPolygon* poly); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); bool bInitGradientDataPlanarEx(CDrawPolygon* poly); #if (TARGET_PROCESSOR == PROCESSOR_K6_3D) // // We can't beat the compiled code on the Pentium for this routine so // only K6_3D version exist. // void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); #if (BILINEAR_FILTER) void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); #endif void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); void InitializeForWalkEx(CDrawPolygon* poly, CEdge* pedge); // // This routine is used on the K6_3D to empty the MMX state. // void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); #if (BILINEAR_FILTER) void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); #endif void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); void DoneDrawingPolygon(CDrawPolygon* poly); #endif // if (TARGET_PROCESSOR == PROCESSOR_K6_3D) #endif // if (VER_ASM) // // Generic versions of global templated polygon setup functions. // template forceinline void InitializePolygonData ( LINE& lineData, CRenderPolygon* rpoly ) { lineData.InitializePolygonData(rpoly->paprvPolyVertices, rpoly->ptexTexture, rpoly->cvFace, rpoly->iMipLevel); } template forceinline void InitializeEdge ( CEdge& edge, // The edge to initialize. SRenderVertex* prv_from, // Starting coordinate of edge. SRenderVertex* prv_to // End coordinate of edge. ) { edge.InitializeEdge(prv_from, prv_to); } template forceinline bool bInitTriangleDataEx ( CDrawPolygon* poly, SRenderVertex* prv_a, // 3 vertices making up this triangle. SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update ) { return poly->bInitTriangleData(prv_a, prv_b, prv_c, b_update); } template forceinline bool bInitGradientDataPlanarEx ( CDrawPolygon* poly ) { return poly->bInitGradientDataPlanar(); } template forceinline void InitializeForWalkEx ( CDrawPolygon* poly, CEdge* pedge ) { Assert(pedge); #if bPRIM_STATS psBaseEdges.Add(0, 1); psLines.Add(0, pedge->prvTo->iYScr - pedge->prvFrom->iYScr); #endif // Set base edge. poly->pedgeBase = pedge; // Initialize edge chosen to be the base edge. pedge->lineStart.InitializeAsBase(pedge, poly); } template forceinline void DoneDrawingPolygon ( CDrawPolygon* poly ) { // Do nothing. return; } #endif // if HEADER_RENDERER_PRIMITIVES_DRAWTRIANGLE_HPP