Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

863 lines
23 KiB
C++

#include "MLRHeaders.hpp"
#if !defined(MLR_MLRCLIPTRICK_HPP)
#include <MLR\MLRClipTrick.hpp>
#endif
extern DWORD gShowClippedPolys;
//#############################################################################
//######################### MLRCardCloud ################################
//#############################################################################
DynamicArrayOf<MLRClippingState>
*MLRCardCloud::clipPerVertex;
DynamicArrayOf<Vector4D>
*MLRCardCloud::clipExtraCoords;
DynamicArrayOf<RGBAColor>
*MLRCardCloud::clipExtraColors;
DynamicArrayOf<Vector2DScalar>
*MLRCardCloud::clipExtraTexCoords;
DynamicArrayOf<int>
*MLRCardCloud::clipExtraLength;
MLRCardCloud::ClassData*
MLRCardCloud::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRCardCloud::InitializeClass()
{
Verify(!DefaultData);
Verify(gos_GetCurrentHeap() == StaticHeap);
DefaultData =
new ClassData(
MLRCardCloudClassID,
"MidLevelRenderer::MLRCardCloud",
MLREffect::DefaultData
);
Register_Object(DefaultData);
clipPerVertex = new DynamicArrayOf<MLRClippingState> (Limits::Max_Number_Vertices_Per_Effect);
Register_Object(clipPerVertex);
clipExtraCoords = new DynamicArrayOf<Vector4D> (Limits::Max_Number_Vertices_Per_Effect);
Register_Object(clipExtraCoords);
clipExtraColors = new DynamicArrayOf<RGBAColor> (Limits::Max_Number_Vertices_Per_Effect);
Register_Object(clipExtraColors);
clipExtraTexCoords = new DynamicArrayOf<Vector2DScalar> (Limits::Max_Number_Vertices_Per_Effect);
Register_Object(clipExtraTexCoords);
clipExtraLength = new DynamicArrayOf<int> (Limits::Max_Number_Primitives_Per_Frame);
Register_Object(clipExtraLength);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRCardCloud::TerminateClass()
{
Unregister_Object(clipPerVertex);
delete clipPerVertex;
Unregister_Object(clipExtraCoords);
delete clipExtraCoords;
Unregister_Object(clipExtraColors);
delete clipExtraColors;
Unregister_Object(clipExtraTexCoords);
delete clipExtraTexCoords;
Unregister_Object(clipExtraLength);
delete clipExtraLength;
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRCardCloud::MLRCardCloud(int nr) :
MLREffect(nr, DefaultData)
{
Verify(gos_GetCurrentHeap() == EffectHeap);
usedNrOfCards = NULL;
Check_Pointer(this);
drawMode = SortData::TriList;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRCardCloud::~MLRCardCloud()
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRCardCloud::SetData
(
const int *count,
const Stuff::Point3D *point_data,
const Stuff::RGBAColor *color_data
)
{
Check_Pointer(this);
usedNrOfCards = count;
Verify(*usedNrOfCards <= maxNrOf);
points = point_data;
colors = color_data;
Verify(texCoords != NULL);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRCardCloud::SetData
(
const int *count,
const Stuff::Point3D *point_data,
const Stuff::RGBAColor *color_data,
const Vector2DScalar *uv_data
)
{
Check_Pointer(this);
usedNrOfCards = count;
Verify(*usedNrOfCards <= maxNrOf);
texCoords = uv_data;
SetData(count, point_data, color_data);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRCardCloud::Draw (DrawEffectInformation *dInfo, GOSVertexPool *allVerticesToDraw, MLRSorter *sorter)
{
Check_Object(this);
#ifdef LAB_ONLY
if(Limits::Max_Number_Vertices_Per_Frame < allVerticesToDraw->GetLast() + *usedNrOfCards * 4)
{
SPEWALWAYS((0, "Not drawing MLRCardCloud. Too many vertices! Raid a bug to Art!"));
return;
}
#endif
worldToEffect.Invert(*dInfo->effectToWorld);
Transform(*usedNrOfCards, 4);
if( Clip(dInfo->clippingFlags, allVerticesToDraw, false) )
{
sorter->AddEffect(this, dInfo->state);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
MLRCardCloud::Draw (ToBeDrawnPrimitive *tbdp, MLRSorter *sorter)
{
Check_Object(this);
effectToClipMatrix = tbdp->shapeToClipMatrix;
Transform(*usedNrOfCards, 4);
int index = -1;
if( Clip(tbdp->clippingFlags, tbdp->allVerticesToDraw, true) )
{
sorter->AddEffect(this, tbdp->state, index);
}
return index;
}
static MLRClippingState theAnd, theOr, theTest;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
MLRCardCloud::Clip(MLRClippingState clippingFlags, GOSVertexPool *vt, bool db)
{
Check_Object(this);
int i, j, k, l;
int end, len = *usedNrOfCards;
int mask, k1, ct=0, ret = 0;
Scalar a=0.0f, bc0, bc1;
Check_Object(vt);
gos_vertices = vt->GetActualVertexPool(db);
Check_Pointer(gos_vertices);
numGOSVertices = 0;
//
//--------------------------------------
// See if we don't have to draw anything
//--------------------------------------
//
if(clippingFlags.GetClippingState() == 0 || len <= 0)
{
if(len <= 0)
{
visible = 0;
}
else
{
//
//-------------------------------
// Handle the non-indexed version
//-------------------------------
//
for(i=0,j=0;i<len;i++,j+=4)
{
if(IsOn(i) == false)
{
continue;
}
GOSCopyTriangleData(
&gos_vertices[numGOSVertices],
transformedCoords->GetData(),
texCoords,
j, j+1, j+2
#if FOG_HACK
, true
#endif
);
DWORD tmpColor = GOSCopyColor(&colors[i]);
for(k=numGOSVertices;k<numGOSVertices+3;k++)
{
gos_vertices[k].argb = tmpColor;
}
gos_vertices[numGOSVertices + 3] = gos_vertices[numGOSVertices];
gos_vertices[numGOSVertices + 4] = gos_vertices[numGOSVertices + 2];
GOSCopyData(
&gos_vertices[numGOSVertices + 5],
transformedCoords->GetData(),
texCoords,
j+3
#if FOG_HACK
, true
#endif
);
gos_vertices[numGOSVertices + 5].argb = tmpColor;
numGOSVertices += 6;
}
if(db==false)
{
Check_Object(vt);
vt->Increase(numGOSVertices);
}
visible = numGOSVertices ? 1 : 0;
}
return visible;
}
int myNumberUsedClipVertex, myNumberUsedClipIndex, myNumberUsedClipLength;
myNumberUsedClipVertex = 0;
myNumberUsedClipIndex = 0;
myNumberUsedClipLength = 0;
//
//-------------------------------
// Handle the non-indexed version
//-------------------------------
//
//
//-----------------------------------------------------------------
// Step through each polygon, making sure that we don't try to clip
// backfaced polygons
//-----------------------------------------------------------------
//
for(i=0,j=0;i<len;i++,j+=4)
{
if(IsOn(i) == false)
{
continue;
}
TurnVisible(i);
//
//---------------------------------------------------------------
// Test each vertex of the polygon against the allowed clipping
// planes, and accumulate status for which planes always clip and
// which planes clipped at least once
//---------------------------------------------------------------
//
theAnd.SetClippingState(0x3f);
theOr.SetClippingState(0);
end = j+4;
Stuff::Vector4D *v4d = transformedCoords->GetData() + j;
MLRClippingState *cs = clipPerVertex->GetData() + j;
for(k=j;k<end;k++,v4d++,cs++)
{
cs->Clip4dVertex(v4d);;
theAnd &= (*clipPerVertex)[k];
theOr |= (*clipPerVertex)[k];
#ifdef LAB_ONLY
if(*cs==0)
{
Set_Statistic(NonClippedVertices, NonClippedVertices+1);
}
else
{
Set_Statistic(ClippedVertices, ClippedVertices+1);
}
#endif
}
//
//-------------------------------------------------------------------
// If any bit is set for all vertices, then the polygon is completely
// outside the viewing space and we don't have to draw it. On the
// other hand, if no bits at all were ever set, we can do a trivial
// accept of the polygon
//-------------------------------------------------------------------
//
if (theAnd != 0)
{
TurnInVisible(i);
}
else if (theOr == 0)
{
TurnVisible(i);
GOSCopyTriangleData(
&gos_vertices[numGOSVertices],
transformedCoords->GetData(),
texCoords,
j, j+1, j+2
#if FOG_HACK
, true
#endif
);
DWORD tmpColor = GOSCopyColor(&colors[i]);
gos_vertices[numGOSVertices].argb = tmpColor;
gos_vertices[numGOSVertices + 1].argb = tmpColor;
gos_vertices[numGOSVertices + 2].argb = tmpColor;
gos_vertices[numGOSVertices + 3] = gos_vertices[numGOSVertices];
gos_vertices[numGOSVertices + 4] = gos_vertices[numGOSVertices + 2];
GOSCopyData(
&gos_vertices[numGOSVertices + 5],
transformedCoords->GetData(),
texCoords,
j+3
#if FOG_HACK
, true
#endif
);
gos_vertices[numGOSVertices + 5].argb = tmpColor;
#ifdef LAB_ONLY
if(gShowClippedPolys)
{
for(l=0;l<6;l++)
{
gos_vertices[numGOSVertices+l].argb = 0xff0000ff;
gos_vertices[numGOSVertices+l].u = 0.0f;
gos_vertices[numGOSVertices+l].v = 0.0f;
}
}
#endif
numGOSVertices += 6;
ret++;
}
//
//-----------------------------------------------------------------
// It is not a trivial case, so we must now do real clipping on the
// polygon
//-----------------------------------------------------------------
//
else
{
// ultra small triangles clipped at farclip cause problems
if(theOr.IsFarClipped() == true)
{
continue;
}
int numberVerticesPerPolygon = 0;
//
//---------------------------------------------------------------
// Handle the case of a single clipping plane by stepping through
// the vertices and finding the edge it originates
//---------------------------------------------------------------
//
if (theOr.GetNumberOfSetBits() == 1)
{
for(k=j;k<end;k++)
{
k1 = (k+1 < end) ? k + 1 : j;
//
//----------------------------------------------------
// If this vertex is inside the viewing space, copy it
// directly to the clipping buffer
//----------------------------------------------------
//
int clipped_index =
myNumberUsedClipVertex + numberVerticesPerPolygon;
theTest = (*clipPerVertex)[k];
if(theTest == 0)
{
(*clipExtraCoords)[clipped_index] = (*transformedCoords)[k];
(*clipExtraTexCoords)[clipped_index] = texCoords[k];
(*clipExtraColors)[clipped_index] = colors[i];
numberVerticesPerPolygon++;
clipped_index++;
//
//-------------------------------------------------------
// We don't need to clip this edge if the next vertex is
// also in the viewing space, so just move on to the next
// vertex
//-------------------------------------------------------
//
if((*clipPerVertex)[k1] == 0)
{
continue;
}
}
//
//---------------------------------------------------------
// This vertex is outside the viewing space, so if the next
// vertex is also outside the viewing space, no clipping is
// needed and we throw this vertex away. Since only one
// clipping plane is involved, it must be in the same space
// as the first vertex
//---------------------------------------------------------
//
else if((*clipPerVertex)[k1] != 0)
{
Verify((*clipPerVertex)[k1] == (*clipPerVertex)[k]);
continue;
}
//
//--------------------------------------------------
// We now find the distance along the edge where the
// clipping plane will intersect
//--------------------------------------------------
//
mask = 1;
theTest |= (*clipPerVertex)[k1];
//
//-----------------------------------------------------
// Find the boundary conditions that match our clipping
// plane
//-----------------------------------------------------
//
for (l=0; l<MLRClippingState::NextBit; l++)
{
if(theTest.IsClipped(mask))
{
//
//-------------------------------------------
// Find the clipping interval from bc0 to bc1
//-------------------------------------------
//
a = GetLerpFactor(l, (*transformedCoords)[k], (*transformedCoords)[k1]);
Verify(a >= 0.0f && a <= 1.0f);
ct = l;
break;
}
mask <<= 1;
}
//
//------------------------------
// Lerp the homogeneous position
//------------------------------
//
(*clipExtraCoords)[clipped_index].Lerp(
(*transformedCoords)[k],
(*transformedCoords)[k1],
a
);
DoClipTrick((*clipExtraCoords)[clipped_index], ct);
//
//----------------------------------------------------------
// If there are colors, lerp them in screen space for now as
// most cards do that anyway
//----------------------------------------------------------
//
(*clipExtraTexCoords)[clipped_index].Lerp(
texCoords[k],
texCoords[k1],
a
);
(*clipExtraColors)[clipped_index] = colors[i];
//
//--------------------------------
// Bump the polygon's vertex count
//--------------------------------
//
numberVerticesPerPolygon++;
}
}
//
//---------------------------------------------------------------
// We have to handle multiple planes. We do this by creating two
// buffers and we switch between them as we clip plane by plane
//---------------------------------------------------------------
//
else
{
EffectClipData srcPolygon, dstPolygon;
int dstBuffer = 0;
//
//-----------------------------------------------------
// Point the source polygon buffer at our original data
//-----------------------------------------------------
//
srcPolygon.coords = &((*transformedCoords)[j]);
srcPolygon.clipPerVertex = &((*clipPerVertex)[j]);
srcPolygon.flags = 0;
// srcPolygon.colors = const_cast<RGBAColor*>(&colors[j]);
srcPolygon.flags |= 2;
srcPolygon.texCoords = const_cast<Vector2DScalar*>(&texCoords[j]);
srcPolygon.length = 4;
//
//--------------------------------
// Point to the destination buffer
//--------------------------------
//
dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData();
// dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData();
dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData();
dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData();
dstPolygon.flags = srcPolygon.flags;
dstPolygon.length = 0;
//
//-----------------------------------------------------------
// Spin through each plane that clipped the primitive and use
// it to actually clip the primitive
//-----------------------------------------------------------
//
mask = 1;
MLRClippingState theNewOr(0);
int loop = 4;
do
{
for(l=0; l<MLRClippingState::NextBit; l++)
{
if(theOr.IsClipped(mask))
{
//
//-----------------------------------
// Clip each vertex against the plane
//-----------------------------------
//
for(k=0;k<srcPolygon.length;k++)
{
k1 = (k+1 < srcPolygon.length) ? k+1 : 0;
theTest = srcPolygon.clipPerVertex[k];
//
//----------------------------------------------------
// If this vertex is inside the viewing space, copy it
// directly to the clipping buffer
//----------------------------------------------------
//
if(theTest.IsClipped(mask) == 0)
{
dstPolygon.coords[dstPolygon.length] =
srcPolygon.coords[k];
dstPolygon.clipPerVertex[dstPolygon.length] =
srcPolygon.clipPerVertex[k];
dstPolygon.texCoords[dstPolygon.length] =
srcPolygon.texCoords[k];
dstPolygon.length++;
//
//-------------------------------------------------------
// We don't need to clip this edge if the next vertex is
// also in the viewing space, so just move on to the next
// vertex
//-------------------------------------------------------
//
if(srcPolygon.clipPerVertex[k1].IsClipped(mask) == 0)
{
continue;
}
}
//
//---------------------------------------------------------
// This vertex is outside the viewing space, so if the next
// vertex is also outside the viewing space, no clipping is
// needed and we throw this vertex away. Since only one
// clipping plane is involved, it must be in the same space
// as the first vertex
//---------------------------------------------------------
//
else if(srcPolygon.clipPerVertex[k1].IsClipped(mask) != 0)
{
Verify(
srcPolygon.clipPerVertex[k1].IsClipped(mask)
== srcPolygon.clipPerVertex[k].IsClipped(mask)
);
continue;
}
//
//-------------------------------------------
// Find the clipping interval from bc0 to bc1
//-------------------------------------------
//
bc0 = GetBC(l, srcPolygon.coords[k]);
bc1 = GetBC(l, srcPolygon.coords[k1]);
Verify(!Close_Enough(bc0, bc1));
a = bc0 / (bc0 - bc1);
Verify(a >= 0.0f && a <= 1.0f);
//
//------------------------------
// Lerp the homogeneous position
//------------------------------
//
dstPolygon.coords[dstPolygon.length].Lerp(
srcPolygon.coords[k],
srcPolygon.coords[k1],
a
);
DoCleanClipTrick(dstPolygon.coords[dstPolygon.length], l);
//
//-----------------------------------------------------
// If there are texture uv's, we need to lerp them in a
// perspective correct manner
//-----------------------------------------------------
//
dstPolygon.texCoords[dstPolygon.length].Lerp
(
srcPolygon.texCoords[k],
srcPolygon.texCoords[k1],
a
);
//
//-------------------------------------
// We have to generate a new clip state
//-------------------------------------
//
dstPolygon.clipPerVertex[dstPolygon.length].Clip4dVertex(&dstPolygon.coords[dstPolygon.length]);
//
//----------------------------------
// Bump the new polygon vertex count
//----------------------------------
//
dstPolygon.length++;
}
//
//-----------------------------------------------
// Swap source and destination buffer pointers in
// preparation for the next plane test
//-----------------------------------------------
//
srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData();
// srcPolygon.colors = clipBuffer[dstBuffer].colors.GetData();
srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData();
srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData();
srcPolygon.length = dstPolygon.length;
dstBuffer = !dstBuffer;
dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData();
// dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData();
dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData();
dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData();
dstPolygon.length = 0;
}
mask = mask << 1;
}
theNewOr = 0;
for(k=0;k<srcPolygon.length;k++)
{
theNewOr |= srcPolygon.clipPerVertex[k];
}
theOr == theNewOr;
} while (theNewOr != 0 && loop--);
//
//--------------------------------------------------
// could not clip this rare case, just ignore it
//--------------------------------------------------
//
if(theNewOr != 0)
{
testList[i] = 0;
continue;
}
//
//--------------------------------------------------
// Move the most recent polygon into the clip buffer
//--------------------------------------------------
//
for(k=0;k<srcPolygon.length;k++)
{
int clipped_index = myNumberUsedClipVertex + k;
if(srcPolygon.coords[k].z == srcPolygon.coords[k].w)
{
srcPolygon.coords[k].z -= SMALL;
}
(*clipExtraCoords)[clipped_index] = srcPolygon.coords[k];
(*clipExtraTexCoords)[clipped_index] = srcPolygon.texCoords[k];
(*clipExtraColors)[clipped_index] = colors[i];
}
numberVerticesPerPolygon = srcPolygon.length;
}
(*clipExtraLength)[myNumberUsedClipLength] = numberVerticesPerPolygon;
myNumberUsedClipVertex += numberVerticesPerPolygon;
myNumberUsedClipLength++;
ret++;
// clip
// dont draw the original
TurnInVisible(i);
}
}
if(myNumberUsedClipLength > 0)
{
for(i=0,j=0;i<myNumberUsedClipLength;i++)
{
int stride = (*clipExtraLength)[i];
for(k=1;k<stride-1;k++)
{
if(db==false)
{
Verify((vt->GetLast() + 3 + numGOSVertices) < vt->GetLength());
}
GOSCopyTriangleData(
&gos_vertices[numGOSVertices],
clipExtraCoords->GetData(),
clipExtraColors->GetData(),
clipExtraTexCoords->GetData(),
j, j+k+1, j+k
#if FOG_HACK
, true
#endif
);
#ifdef LAB_ONLY
if(gShowClippedPolys)
{
gos_vertices[numGOSVertices].argb = 0xffff0000;
gos_vertices[numGOSVertices].u = 0.0f;
gos_vertices[numGOSVertices].v = 0.0f;
gos_vertices[numGOSVertices+1].argb = 0xffff0000;
gos_vertices[numGOSVertices+1].u = 0.0f;
gos_vertices[numGOSVertices+1].v = 0.0f;
gos_vertices[numGOSVertices+2].argb = 0xffff0000;
gos_vertices[numGOSVertices+2].u = 0.0f;
gos_vertices[numGOSVertices+2].v = 0.0f;
}
#endif
numGOSVertices += 3;
}
j += stride;
}
}
if(db==false)
{
vt->Increase(numGOSVertices);
}
visible = numGOSVertices ? 1 : 0;
return visible;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRCardCloud::TestInstance() const
{
if (usedNrOfCards)
{
Check_Pointer(usedNrOfCards);
Verify(*usedNrOfCards >= 0);
Verify(*usedNrOfCards <= maxNrOf);
}
}