mirror of
https://github.com/OpenTrespasser/JurassicParkTrespasser.git
synced 2024-12-19 23:21:56 +00:00
2081 lines
64 KiB
C++
2081 lines
64 KiB
C++
/***********************************************************************************************
|
|
*
|
|
* 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<int32> 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 TPIX, class GOUR, class TRANS, class MAP, class INDEX, class CLU>
|
|
class CScanline;
|
|
|
|
//*********************************************************************************************
|
|
template<class LINE> class CDrawPolygon;
|
|
|
|
//*****************************************************************************************
|
|
template<class LINE> void DrawSubtriangle(LINE* pscan, CDrawPolygon<LINE>* pdtriTriangle);
|
|
|
|
|
|
//
|
|
// Global templated helper functions used in CDrawPolygon.
|
|
//
|
|
template <class LINE> void InitializePolygonData(LINE& lineData, CRenderPolygon* rpoly);
|
|
|
|
template <class LINE> void InitializeEdge(CEdge<LINE>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
|
|
template <class LINE> bool bInitTriangleDataEx(CDrawPolygon<LINE>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
|
|
template <class LINE> bool bInitGradientDataPlanarEx(CDrawPolygon<LINE>* poly);
|
|
|
|
template <class LINE> void InitializeForWalkEx(CDrawPolygon<LINE>* poly, CEdge<LINE>* pedge);
|
|
|
|
template <class LINE> void DoneDrawingPolygon(CDrawPolygon<LINE>* 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<class T> 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<class T> 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 LINE> 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<CTexture> ptexTexture; // Pointer to the source texture.
|
|
LINE lineData; // Storage for triangle-wide data based on the
|
|
// scanline type.
|
|
CEdge<LINE>* 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<LINE> 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<LINE> 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<LINE>* 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<LINE>* 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<LINE>* pedge_left, // Base edge.
|
|
const CEdge<LINE>* 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<LINE>* pedge_left,
|
|
CEdge<LINE>* pedge_right0,
|
|
CEdge<LINE>* 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<LINE>* pedge_left0,
|
|
CEdge<LINE>* pedge_left1,
|
|
CEdge<LINE>* 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<TCopyPersp>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TCopyPerspTrans>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TCopyTerrainPersp>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTexturePersp>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTexturePerspTrans>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTexturePerspGour>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTexturePerspTransGour>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TBumpPersp>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TBumpPerspTrans>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TGFogPersp>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
|
|
void InitializeEdge(CEdge<TCopyLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TCopyLinearTrans>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TCopyTerrainLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTextureLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTextureLinearTrans>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTextureLinearGour>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTextureLinearTransGour>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TBumpLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TBumpLinearTrans>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TGFogLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
|
|
void InitializeEdge(CEdge<TTexNoClutLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TTexNoClutLinearTrans>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TShadowTrans8>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TShadowTrans32>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
|
|
#if (BILINEAR_FILTER)
|
|
|
|
void InitializeEdge(CEdge<TCopyPerspFilter>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TCopyLinearFilter>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
|
|
#endif
|
|
|
|
void InitializeEdge(CEdge<TStippleTexPersp>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TStippleTexLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TWaterPersp>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TWaterLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TAlphaTexPersp>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
void InitializeEdge(CEdge<TAlphaTexLinear>& edge, SRenderVertex* prv_from, SRenderVertex* prv_to);
|
|
|
|
|
|
bool bInitTriangleDataEx(CDrawPolygon<TCopyPersp>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TCopyPerspTrans>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TCopyTerrainPersp>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTexturePersp>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTexturePerspTrans>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTexturePerspGour>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTexturePerspTransGour>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TBumpPersp>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TBumpPerspTrans>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TGFogPersp>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
|
|
bool bInitTriangleDataEx(CDrawPolygon<TCopyLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TCopyLinearTrans>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TCopyTerrainLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTextureLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTextureLinearTrans>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTextureLinearGour>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTextureLinearTransGour>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TBumpLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TBumpLinearTrans>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TGFogLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTexNoClutLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TTexNoClutLinearTrans>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TShadowTrans8>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TShadowTrans32>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
|
|
#if (BILINEAR_FILTER)
|
|
|
|
bool bInitTriangleDataEx(CDrawPolygon<TCopyPerspFilter>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TCopyLinearFilter>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
|
|
#endif
|
|
|
|
bool bInitTriangleDataEx(CDrawPolygon<TStippleTexPersp>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TStippleTexLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TWaterPersp>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TWaterLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TAlphaTexPersp>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
bool bInitTriangleDataEx(CDrawPolygon<TAlphaTexLinear>* poly, SRenderVertex* prv_a,
|
|
SRenderVertex* prv_b, SRenderVertex* prv_c, bool b_update);
|
|
|
|
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TCopyPersp>* poly);
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TCopyPerspTrans>* poly);
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TCopyTerrainPersp>* poly);
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TTexturePersp>* poly);
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TTexturePerspTrans>* poly);
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TBumpPersp>* poly);
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TBumpPerspTrans>* poly);
|
|
|
|
#if (BILINEAR_FILTER)
|
|
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TCopyPerspFilter>* poly);
|
|
|
|
#endif
|
|
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TStippleTexPersp>* poly);
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TWaterPersp>* poly);
|
|
bool bInitGradientDataPlanarEx(CDrawPolygon<TAlphaTexPersp>* 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<TCopyPersp>* poly, CEdge<TCopyPersp>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TCopyPerspTrans>* poly, CEdge<TCopyPerspTrans>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TCopyTerrainPersp>* poly, CEdge<TCopyTerrainPersp>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTexturePersp>* poly, CEdge<TTexturePersp>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTexturePerspTrans>* poly, CEdge<TTexturePerspTrans>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTexturePerspGour>* poly, CEdge<TTexturePerspGour>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTexturePerspTransGour>* poly, CEdge<TTexturePerspTransGour>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TBumpPersp>* poly, CEdge<TBumpPersp>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TBumpPerspTrans>* poly, CEdge<TBumpPerspTrans>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TGFogPersp>* poly, CEdge<TGFogPersp>* pedge);
|
|
|
|
void InitializeForWalkEx(CDrawPolygon<TCopyLinear>* poly, CEdge<TCopyLinear>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TCopyLinearTrans>* poly, CEdge<TCopyLinearTrans>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TCopyTerrainLinear>* poly, CEdge<TCopyTerrainLinear>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTextureLinear>* poly, CEdge<TTextureLinear>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTextureLinearTrans>* poly, CEdge<TTextureLinearTrans>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTextureLinearGour>* poly, CEdge<TTextureLinearGour>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTextureLinearTransGour>* poly, CEdge<TTextureLinearTransGour>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TBumpLinear>* poly, CEdge<TBumpLinear>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TBumpLinearTrans>* poly, CEdge<TBumpLinearTrans>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TGFogLinear>* poly, CEdge<TGFogLinear>* pedge);
|
|
|
|
void InitializeForWalkEx(CDrawPolygon<TTexNoClutLinear>* poly, CEdge<TTexNoClutLinear>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TTexNoClutLinearTrans>* poly, CEdge<TTexNoClutLinearTrans>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TShadowTrans8>* poly, CEdge<TShadowTrans8>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TShadowTrans32>* poly, CEdge<TShadowTrans32>* pedge);
|
|
|
|
#if (BILINEAR_FILTER)
|
|
|
|
void InitializeForWalkEx(CDrawPolygon<TCopyPerspFilter>* poly, CEdge<TCopyPerspFilter>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TCopyLinearFilter>* poly, CEdge<TCopyLinearFilter>* pedge);
|
|
|
|
#endif
|
|
|
|
void InitializeForWalkEx(CDrawPolygon<TStippleTexPersp>* poly, CEdge<TStippleTexPersp>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TStippleTexLinear>* poly, CEdge<TStippleTexLinear>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TWaterPersp>* poly, CEdge<TWaterPersp>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TWaterLinear>* poly, CEdge<TWaterLinear>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TAlphaTexPersp>* poly, CEdge<TAlphaTexPersp>* pedge);
|
|
void InitializeForWalkEx(CDrawPolygon<TAlphaTexLinear>* poly, CEdge<TAlphaTexLinear>* pedge);
|
|
|
|
|
|
//
|
|
// This routine is used on the K6_3D to empty the MMX state.
|
|
//
|
|
void DoneDrawingPolygon(CDrawPolygon<TCopyPersp>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TCopyPerspTrans>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TCopyTerrainPersp>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTexturePersp>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTexturePerspTrans>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTexturePerspGour>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTexturePerspTransGour>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TBumpPersp>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TBumpPerspTrans>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TGFogPersp>* poly);
|
|
|
|
void DoneDrawingPolygon(CDrawPolygon<TCopyLinear>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TCopyLinearTrans>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TCopyTerrainLinear>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTextureLinear>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTextureLinearTrans>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTextureLinearGour>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTextureLinearTransGour>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TBumpLinear>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TBumpLinearTrans>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TGFogLinear>* poly);
|
|
|
|
void DoneDrawingPolygon(CDrawPolygon<TTexNoClutLinear>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TTexNoClutLinearTrans>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TShadowTrans8>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TShadowTrans32>* poly);
|
|
|
|
#if (BILINEAR_FILTER)
|
|
|
|
void DoneDrawingPolygon(CDrawPolygon<TCopyPerspFilter>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TCopyLinearFilter>* poly);
|
|
|
|
#endif
|
|
|
|
void DoneDrawingPolygon(CDrawPolygon<TStippleTexPersp>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TStippleTexLinear>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TWaterPersp>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TWaterLinear>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TAlphaTexPersp>* poly);
|
|
void DoneDrawingPolygon(CDrawPolygon<TAlphaTexLinear>* poly);
|
|
|
|
|
|
#endif // if (TARGET_PROCESSOR == PROCESSOR_K6_3D)
|
|
|
|
#endif // if (VER_ASM)
|
|
|
|
|
|
//
|
|
// Generic versions of global templated polygon setup functions.
|
|
//
|
|
template <class LINE> forceinline void InitializePolygonData
|
|
(
|
|
LINE& lineData,
|
|
CRenderPolygon* rpoly
|
|
)
|
|
{
|
|
lineData.InitializePolygonData(rpoly->paprvPolyVertices, rpoly->ptexTexture, rpoly->cvFace,
|
|
rpoly->iMipLevel);
|
|
}
|
|
|
|
template <class LINE> forceinline void InitializeEdge
|
|
(
|
|
CEdge<LINE>& 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 <class LINE> forceinline bool bInitTriangleDataEx
|
|
(
|
|
CDrawPolygon<LINE>* 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 <class LINE> forceinline bool bInitGradientDataPlanarEx
|
|
(
|
|
CDrawPolygon<LINE>* poly
|
|
)
|
|
{
|
|
return poly->bInitGradientDataPlanar();
|
|
}
|
|
|
|
template <class LINE> forceinline void InitializeForWalkEx
|
|
(
|
|
CDrawPolygon<LINE>* poly,
|
|
CEdge<LINE>* 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 <class LINE> forceinline void DoneDrawingPolygon
|
|
(
|
|
CDrawPolygon<LINE>* poly
|
|
)
|
|
{
|
|
// Do nothing.
|
|
return;
|
|
}
|
|
|
|
|
|
#endif // if HEADER_RENDERER_PRIMITIVES_DRAWTRIANGLE_HPP
|