JurassicParkTrespasser/jp2_pc/Source/Lib/Renderer/ScreenPolygon.cpp
Michael f40e2e21d7 ScreenRenderPolygon.cpp: use modern STL header names
- std::* treatment
- remove include of TempBuf.cpp which does not exist
2020-04-01 22:04:24 +02:00

784 lines
20 KiB
C++

/***********************************************************************************************
*
* Copyright © DreamWorks Interactive, 1997.
*
* Contents:
* Implementation of ScreenPolygon.hpp.
*
* Bugs:
*
* To do:
*
***********************************************************************************************
*
* $Log:: /JP2_PC/Source/Lib/Renderer/ScreenPolygon.cpp $
*
* 4 6/18/98 6:30p Pkeet
* Added code for printing out debug information.
*
* 3 97/04/25 2:18p Pkeet
* Altered code to use the new implementation of CLine2D.
*
* 2 97/04/24 11:46a Pkeet
* Debugged function and added code for debugging.
*
**********************************************************************************************/
//
// Defines.
//
// Switch for debug text output.
#define bOUTPUT_POLYINTERSECT (0)
#define bVALIDATE_POLYLIST (0)
#define bOUTPUT_POLYLIST (1)
//
// Includes.
//
#include <algorithm>
#include <vector>
#include "Common.hpp"
#include "Lib/W95/Direct3D.hpp"
#include "ScreenRender.hpp"
#include "DepthSortTools.hpp"
#include "Line2D.hpp"
#include "Line.hpp"
#if bOUTPUT_POLYINTERSECT || bOUTPUT_POLYLIST
#include "Lib/Sys/TextOut.hpp"
CConsoleBuffer conPolys(120, 80);
#endif
//
// Module defines.
//
// Maximum number of vertices per polygon.
#define iMAX_POLY_VERTICES (40)
// Definition of a line segment array.
typedef std::vector<CLine2D> TVLines;
bool bDumpPolylist = false;
//
// Module functions.
//
#if bOUTPUT_POLYINTERSECT
//******************************************************************************************
//
void WriteLine(CLine2D& line)
//
//
//
//**********************************
{
conPolys.Print("%1.1f, %1.1f :: %1.1f, %1.1f\n", line.v2From.tX, line.v2From.tY, line.v2To.tX,
line.v2To.tY);
}
#endif // bOUTPUT_POLYINTERSECT
//**********************************************************************************************
//
bool bLineSegCompare
(
const CLine2D& ls_a,
const CLine2D& ls_b
)
//
//
//
//**********************************
{
return ls_a.fMinY() < ls_b.fMinY();
}
//
// Function implementations.
//
//**********************************************************************************************
void AddLineSegment
(
TVLines& rtvl_left,
TVLines& rtvl_right,
const CVector3<>& v3_from,
const CVector3<>& v3_to
)
{
// Build the line segment.
CLine2D line2d(v3_from, v3_to);
// Ignore the line segment if it is horizontal.
if (line2d.bHorizontal())
return;
// Push to appropriate list.
if (line2d.bLeft())
rtvl_left.push_back(line2d);
else
rtvl_right.push_back(line2d);
}
//**********************************************************************************************
void AddLineSegments
(
TVLines& rtvl_left,
TVLines& rtvl_right,
const CRenderPolygon* prpoly
)
{
// Add line segments to the respective left and right lists.
for (int i_vert = 0; i_vert < prpoly->paprvPolyVertices.uLen - 1; i_vert++)
{
AddLineSegment
(
rtvl_left,
rtvl_right,
prpoly->paprvPolyVertices[i_vert]->v3Screen,
prpoly->paprvPolyVertices[i_vert + 1]->v3Screen
);
}
AddLineSegment
(
rtvl_left,
rtvl_right,
prpoly->paprvPolyVertices[prpoly->paprvPolyVertices.uLen - 1]->v3Screen,
prpoly->paprvPolyVertices[0]->v3Screen
);
#if bOUTPUT_POLYINTERSECT
conPolys.Print("\nUnsorted:\n");
for (int i = 0; i < Max(rtvl_left.size(), rtvl_right.size()); i++)
{
if (i < rtvl_left.size())
conPolys.Print("%1.1f, %1.1f :: ", rtvl_left[i].v2From.tY, rtvl_left[i].v2To.tY);
else
conPolys.Print("xxxxxxxxxxxx :: ");
if (i < rtvl_right.size())
conPolys.Print("%1.1f, %1.1f\n", rtvl_right[i].v2From.tY, rtvl_right[i].v2To.tY);
else
conPolys.Print("\n");
}
conPolys.Print("\nSorted:\n");
#endif // bOUTPUT_POLYINTERSECT
// Sort the left and right lists.
stable_sort(rtvl_left.begin(), rtvl_left.end(), bLineSegCompare);
stable_sort(rtvl_right.begin(), rtvl_right.end(), bLineSegCompare);
#if bOUTPUT_POLYINTERSECT
for (i = 0; i < Max(rtvl_left.size(), rtvl_right.size()); i++)
{
if (i < rtvl_left.size())
conPolys.Print("%1.1f, %1.1f :: ", rtvl_left[i].v2From.tY, rtvl_left[i].v2To.tY);
else
conPolys.Print("xxxxxxxxxxxx :: ");
if (i < rtvl_right.size())
conPolys.Print("%1.1f, %1.1f\n", rtvl_right[i].v2From.tY, rtvl_right[i].v2To.tY);
else
conPolys.Print("\n");
}
conPolys.Print("\n");
#endif
}
//**********************************************************************************************
class CDualPolyIt
{
public:
int i_a_left;
int i_a_right;
int i_b_left;
int i_b_right;
TVLines vline_a_left;
TVLines vline_a_right;
TVLines vline_b_left;
TVLines vline_b_right;
float fMinY;
float fMaxY;
float fNextY;
float fStartY;
//******************************************************************************************
CDualPolyIt()
{
i_a_left = 0;
i_a_right = 0;
i_b_left = 0;
i_b_right = 0;
}
//******************************************************************************************
bool bDone()
{
if (i_a_left >= vline_a_left.size() || i_a_right >= vline_a_right.size() ||
i_b_left >= vline_b_left.size() || i_b_right >= vline_b_right.size())
return true;
if (!bOverlap())
return true;
return false;
}
//******************************************************************************************
float fMid()
{
return (fNextY - fStartY) * 0.0001f + fStartY;
}
//******************************************************************************************
void FindMinY()
{
fMinY = Min(fFindMinYa(), fFindMinYb());
}
//******************************************************************************************
void FindMaxY()
{
fMaxY = Max(fFindMaxYa(), fFindMaxYb());
}
//******************************************************************************************
float fFindMinYa()
{
return Min(vline_a_left[i_a_left].fMinY(), vline_a_right[i_a_right].fMinY());
}
//******************************************************************************************
float fFindMinYb()
{
return Min(vline_b_left[i_b_left].fMinY(), vline_b_right[i_b_right].fMinY());
}
//******************************************************************************************
float fFindMaxYa()
{
return Max(vline_a_left[i_a_left].fMaxY(), vline_a_right[i_a_right].fMaxY());
}
//******************************************************************************************
float fFindMaxYb()
{
return Max(vline_b_left[i_b_left].fMaxY(), vline_b_right[i_b_right].fMaxY());
}
//******************************************************************************************
void FindStartY()
{
fStartY = Max(Max(vline_a_left[i_a_left].fMinY(), vline_a_right[i_a_right].fMinY()),
Max(vline_b_left[i_b_left].fMinY(), vline_b_right[i_b_right].fMinY()));
}
//******************************************************************************************
void FindNextY()
{
fNextY = Min(Min(vline_a_left[i_a_left].fMaxY(), vline_a_right[i_a_right].fMaxY()),
Min(vline_b_left[i_b_left].fMaxY(), vline_b_right[i_b_right].fMaxY()));
//
// Look for the smallest Y intersection point in the region bounded by fStartY and
// fNextY.
//
if (vline_a_left[i_a_left].bDoesIntersect(vline_b_left[i_b_left]))
{
float f_y_int = vline_a_left[i_a_left].v2GetIntersection().tY;
if (f_y_int > fStartY)
fNextY = Min(fNextY, f_y_int);
}
if (vline_a_left[i_a_left].bDoesIntersect(vline_b_right[i_b_right]))
{
float f_y_int = vline_a_left[i_a_left].v2GetIntersection().tY;
if (f_y_int > fStartY)
fNextY = Min(fNextY, f_y_int);
}
if (vline_a_right[i_a_right].bDoesIntersect(vline_b_left[i_b_left]))
{
float f_y_int = vline_a_right[i_a_right].v2GetIntersection().tY;
if (f_y_int > fStartY)
fNextY = Min(fNextY, f_y_int);
}
if (vline_a_right[i_a_right].bDoesIntersect(vline_b_right[i_b_right]))
{
float f_y_int = vline_a_right[i_a_right].v2GetIntersection().tY;
if (f_y_int > fStartY)
fNextY = Min(fNextY, f_y_int);
}
}
//******************************************************************************************
bool bOverlap()
{
if (fFindMinYa() >= fFindMaxYb())
return false;
if (fFindMinYb() >= fFindMaxYa())
return false;
return true;
}
//******************************************************************************************
void IncrementPastNextY()
{
while (vline_a_left[i_a_left].fMaxY() <= fNextY && i_a_left < vline_a_left.size())
i_a_left++;
while (vline_a_right[i_a_right].fMaxY() <= fNextY && i_a_right < vline_a_right.size())
i_a_right++;
while (vline_b_left[i_b_left].fMaxY() <= fNextY && i_b_left < vline_b_left.size())
i_b_left++;
while (vline_b_right[i_b_right].fMaxY() <= fNextY && i_b_right < vline_b_right.size())
i_b_right++;
}
//******************************************************************************************
void IncrementToStartY()
{
while (vline_a_left[i_a_left].fMaxY() <= fStartY && i_a_left < vline_a_left.size())
i_a_left++;
while (vline_a_right[i_a_right].fMaxY() <= fStartY && i_a_right < vline_a_right.size())
i_a_right++;
while (vline_b_left[i_b_left].fMaxY() <= fStartY && i_b_left < vline_b_left.size())
i_b_left++;
while (vline_b_right[i_b_right].fMaxY() <= fStartY && i_b_right < vline_b_right.size())
i_b_right++;
}
};
//**********************************************************************************************
float fAreaTrapezoid(CLine2D& line_left, CLine2D& line_right, float f_y_start, float f_y_end)
{
float f_area_sum = 0.0f;
float f_area_tri = 0.0f;
float f_dy = f_y_end - f_y_start;
float f_x_top_left = line_left.fGetIntercept(f_y_start);
float f_x_bot_left = line_left.fGetIntercept(f_y_end);
float f_x_top_right = line_right.fGetIntercept(f_y_start);
float f_x_bot_right = line_right.fGetIntercept(f_y_end);
#if bOUTPUT_POLYINTERSECT
// Write the left and right lines.
conPolys.Print("\nHeight: %1.1f\n", f_dy);
conPolys.Print("Left: %1.1f, %1.1f\n", f_x_top_left, f_x_bot_left);
conPolys.Print("Right: %1.1f, %1.1f\n", f_x_top_right, f_x_bot_right);
#endif
// Add the area of the left side.
f_area_tri += Abs(f_x_top_left - f_x_bot_left) * f_dy * 0.5f;
// Add the area of the right side.
f_area_tri += Abs(f_x_top_right - f_x_bot_right) * f_dy * 0.5f;
// Add the area of the rectangle.
float f_x0 = Min(f_x_top_left, f_x_bot_left);
float f_x1 = Max(f_x_top_right, f_x_bot_right);
f_area_sum = (f_x1 - f_x0) * f_dy - f_area_tri;
#if bOUTPUT_POLYINTERSECT
conPolys.Print("Area: %1.1f\n", f_area_sum);
#endif
// Return the computed area.
return f_area_sum;
}
//**********************************************************************************************
float fAreaIntersection(const CRenderPolygon* prpoly_a, const CRenderPolygon* prpoly_b)
{
Assert(prpoly_a);
Assert(prpoly_b);
CDualPolyIt dpi;
float f_area = 0.0f; // Sum of the sub areas.
//
// Create and sort the arrays of line segments.
//
AddLineSegments(dpi.vline_a_left, dpi.vline_a_right, prpoly_a);
AddLineSegments(dpi.vline_b_left, dpi.vline_b_right, prpoly_b);
//
// The area is zero if one side of either polygon is missing or the polygons no
// longer overlap.
//
if (dpi.bDone())
return f_area;
dpi.FindStartY();
dpi.IncrementToStartY();
dpi.FindNextY();
for (;;)
{
if (dpi.bDone())
return f_area;
#if bOUTPUT_POLYINTERSECT
// Debug output.
conPolys.Print("\n\nY Segment: %1.5f, %1.5f\n", dpi.fStartY, dpi.fNextY);
#endif // bOUTPUT_POLYINTERSECT
//
// Get the area of the seperate and combined trapezoids.
//
float f_area_a = fAreaTrapezoid
(
dpi.vline_a_left[dpi.i_a_left],
dpi.vline_a_right[dpi.i_a_right],
dpi.fStartY,
dpi.fNextY
);
float f_area_b = fAreaTrapezoid
(
dpi.vline_b_left[dpi.i_b_left],
dpi.vline_b_right[dpi.i_b_right],
dpi.fStartY,
dpi.fNextY
);
float f_max_area = Max(f_area_a, f_area_b);
f_max_area = Max(f_max_area, fAreaTrapezoid
(
dpi.vline_a_left[dpi.i_a_left],
dpi.vline_b_right[dpi.i_b_right],
dpi.fStartY,
dpi.fNextY
));
f_max_area = Max(f_max_area, fAreaTrapezoid
(
dpi.vline_b_left[dpi.i_b_left],
dpi.vline_a_right[dpi.i_a_right],
dpi.fStartY,
dpi.fNextY
));
// Get the area of intersection (or negative area of non-intersection).
float f_area_intersection = f_area_a + f_area_b - f_max_area;
#if bOUTPUT_POLYINTERSECT
conPolys.Print("Intersection Area: %1.1f\n", f_area_intersection);
#endif // bOUTPUT_POLYINTERSECT
// If there is an area of intersection, add it to the cumulative value.
if (f_area_intersection > 0.0f)
f_area += f_area_intersection;
dpi.IncrementPastNextY();
dpi.fStartY = dpi.fNextY;
dpi.FindNextY();
}
// Return the area.
return f_area;
}
#if bOUTPUT_POLYINTERSECT
class TestPoly
{
public:
//**************************************************************************************
TestPoly()
{
conPolys.OpenFileSession("TestPoly.txt");
OpenDepthSortDebug();
// Create two dummy polygons.
SRenderVertex* aprv_a[20];
SRenderVertex* aprv_b[20];
SRenderVertex rv_a[20];
SRenderVertex rv_b[20];
CRenderPolygon poly_a;
CRenderPolygon poly_b;
// Build the vertex arrays.
for (int i_vert = 0; i_vert < 20; i_vert++)
{
aprv_a[i_vert] = &rv_a[i_vert];
aprv_b[i_vert] = &rv_b[i_vert];
}
// Add the arrays to the polygon.
poly_a.paprvPolyVertices.atArray = aprv_a;
poly_b.paprvPolyVertices.atArray = aprv_b;
poly_a.paprvPolyVertices.uLen = 3;
poly_b.paprvPolyVertices.uLen = 4;
// Set the values for polygon a.
rv_a[0].v3Screen = CVector3<>(49.44099, 212.22241, 0.0f);
rv_a[1].v3Screen = CVector3<>(20.76502, 197.86124, 0.0f);
rv_a[2].v3Screen = CVector3<>(20.76502, 223.01630, 0.0f);
//rv_a[3].v3Screen = CVector3<>(136.50629, 205.71118, 0.0f);
// Set the values for polygon b.
rv_b[0].v3Screen = CVector3<>(43.07402, 213.65799, 0.0f);
rv_b[1].v3Screen = CVector3<>(0.49998, 223.25742, 0.0f);
rv_b[2].v3Screen = CVector3<>(0.49998, 230.64423, 0.0f);
rv_b[3].v3Screen = CVector3<>(20.76491, 223.01633, 0.0f);
// Output the polygon values.
WritePolygon(&poly_a);
WritePolygon(&poly_b);
// Find the area of intersection.
float f_area_intersection = fAreaIntersection(&poly_a, &poly_b);
conPolys.Print("\n\nThe area of intersection is: %1.20f\n\n", f_area_intersection);
CloseDepthSortDebug();
conPolys.CloseFileSession();
}
};
TestPoly testpoly;
#endif // bOUTPUT_POLYINTERSECT
#if bVALIDATE_POLYLIST
//******************************************************************************************
void ValidatePolylist(CPArray<CRenderPolygon*>& parpoly)
{
if (d3dDriver.bUseD3D())
{
for (uint u = 0; u < parpoly.uLen; ++u)
{
AlwaysAssert(parpoly[u]);
if (parpoly[u]->seterfFace[erfSOURCE_TERRAIN])
AlwaysAssert(parpoly[u]->ehwHardwareFlags == ehwTerrain);
}
}
else
{
for (uint u = 0; u < parpoly.uLen; ++u)
{
AlwaysAssert(parpoly[u]);
AlwaysAssert(parpoly[u]->ehwHardwareFlags == ehwSoftware);
}
}
}
#else // bVALIDATE_POLYLIST
//******************************************************************************************
void ValidatePolylist(CPArray<CRenderPolygon*>& parpoly)
{
}
#endif // bVALIDATE_POLYLIST
#if bOUTPUT_POLYLIST
//******************************************************************************************
void WriteCacheFlags(CSet<ERenderFeature> seterf)
{
if (seterf[erfCOPY])
conPolys.Print("Copy ");
if (seterf[erfLIGHT_SHADE])
conPolys.Print("LS ");
if (seterf[erfTEXTURE])
conPolys.Print("Tex ");
if (seterf[erfTRANSPARENT])
conPolys.Print("Trans ");
if (seterf[erfBUMP])
conPolys.Print("Bump ");
if (seterf[erfDRAW_CLIP])
conPolys.Print("Clip ");
if (seterf[erfALPHA_COLOUR])
conPolys.Print("Alpha Col ");
if (seterf[erfPERSPECTIVE])
conPolys.Print("Persp ");
if (seterf[erfFILTER])
conPolys.Print("Filter ");
if (seterf[erfFILTER_EDGES])
conPolys.Print("Filter Edges ");
if (seterf[erfSUBPIXEL])
conPolys.Print("Sub Pix ");
if (seterf[erfDITHER])
conPolys.Print("Dither ");
if (seterf[erfZ_BUFFER])
conPolys.Print("Z Buffer ");
if (seterf[erfTRAPEZOIDS])
conPolys.Print("Trap ");
if (seterf[erfRASTER_CLIP])
conPolys.Print("RClip ");
if (seterf[erfRASTER_CULL])
conPolys.Print("RCull ");
if (seterf[erfLIGHT])
conPolys.Print("Lt ");
if (seterf[erfFOG])
conPolys.Print("Fog ");
if (seterf[erfFOG_SHADE])
conPolys.Print("Fog Shd ");
if (seterf[erfSPECULAR])
conPolys.Print("Spec ");
if (seterf[erfCOLOURED_LIGHTS])
conPolys.Print("Col Lights ");
if (seterf[erfWIRE])
conPolys.Print("Wire ");
if (seterf[erfSOURCE_TERRAIN])
conPolys.Print("Terr ");
if (seterf[erfSOURCE_WATER])
conPolys.Print("Water ");
if (seterf[erfOCCLUDE])
conPolys.Print("Occlude ");
if (seterf[erfMIPMAP])
conPolys.Print("Mip ");
if (seterf[erfCURVED])
conPolys.Print("Curved ");
if (seterf[erfD3D_CACHE])
conPolys.Print("D3D Cache ");
}
//******************************************************************************************
void DumpPolylist(CPArray<CRenderPolygon*>& parpoly)
{
if (!bDumpPolylist)
return;
conPolys.OpenFileSession("PolyDump.txt");
int i_locks = 0;
int i_locks_sw_cache = 0;
int i_hw = 0;
int i_sw = 0;
bool b_software_mode = parpoly[0]->ehwHardwareFlags == ehwSoftware;
if (d3dDriver.bUseD3D())
{
for (uint u = 0; u < parpoly.uLen; ++u)
{
AlwaysAssert(parpoly[u]);
bool b_sw_cache = false;
switch (parpoly[u]->ehwHardwareFlags)
{
case ehwSoftware:
{
++i_sw;
if (parpoly[u]->seterfFace[erfCOPY])
{
conPolys.Print("SW Cache ");
b_sw_cache = true;
}
else
conPolys.Print("SW ");
}
break;
case ehwTerrain:
++i_hw;
conPolys.Print("HW Terrain ");
break;
case ehwCache:
++i_hw;
conPolys.Print("HW Cache ");
break;
case ehwWater:
++i_hw;
conPolys.Print("HW Water ");
break;
case ehwAlphaCol:
++i_hw;
conPolys.Print("HW Alpha Col ");
break;
case ehwFill:
++i_hw;
conPolys.Print("HW Fill ");
break;
default:
conPolys.Print("************UNKNOWN POLYGON TYPE*************");
}
{
// Texture size:
rptr<CRaster> pras = parpoly[u]->ptexTexture->prasGetTexture();
if (pras)
{
int i_tex_size = pras->iWidth * pras->iHeight;
conPolys.Print("Txls: %ld \t", i_tex_size);
}
else
{
conPolys.Print("No Texture \t");
if (parpoly[u]->ehwHardwareFlags == ehwSoftware)
WriteCacheFlags(parpoly[u]->seterfFace);
}
}
// Count mode switches.
if (b_software_mode)
{
if (parpoly[u]->ehwHardwareFlags != ehwSoftware)
{
b_software_mode = false;
}
}
else
{
if (parpoly[u]->ehwHardwareFlags == ehwSoftware)
{
++i_locks;
b_software_mode = true;
if (b_sw_cache)
{
++i_locks_sw_cache;
conPolys.Print("*** Lock Due To SW Cache ***");
}
else
{
conPolys.Print("*** Lock ***");
}
}
}
conPolys.Print("\n");
}
{
int i_lock_percent = 0;
if (i_locks)
i_lock_percent = (i_locks_sw_cache * 100) / i_locks;
conPolys.Print("\n\n");
conPolys.Print("Total Polygons: %ld\n", parpoly.uLen);
conPolys.Print("Locks Taken: %ld\n", i_locks);
conPolys.Print("Locks Taken due to SW caches: %ld, %ld%%\n", i_locks_sw_cache, i_lock_percent);
}
}
else
{
for (uint u = 0; u < parpoly.uLen; ++u)
{
AlwaysAssert(parpoly[u]);
AlwaysAssert(parpoly[u]->ehwHardwareFlags == ehwSoftware);
conPolys.Print("\n");
}
}
conPolys.CloseFileSession();
bDumpPolylist = false;
}
#else // bOUTPUT_POLYLIST
//******************************************************************************************
void DumpPolylist(CPArray<CRenderPolygon*>& parpoly)
{
}
#endif // bOUTPUT_POLYLIST