Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DScorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@

#pragma once

#include <deque>

#include "WWMath/vector3.h"
#include "Common/GameType.h"
#include "Lib/BaseTypeCore.h"

struct VertexFormatXYZDUV1;
class TextureClass;
class DX8IndexBufferClass;
class DX8VertexBufferClass;
Expand Down Expand Up @@ -72,16 +75,18 @@ class W3DScorch : public W3DScorchInterface
SCORCH_PER_ROW = 3
};

Bool isDuplicate(const TScorch& scorch) const;
void updateScorches(WorldHeightMap& map); ///< Update m_vertexScorch and m_indexScorch so all scorches will be drawn.
Bool writeScorchToBuffer(const TScorch& scorch, WorldHeightMap& map, UnsignedInt diffuse,
VertexFormatXYZDUV1* curVb, UnsignedShort* curIb);

DX8VertexBufferClass* m_vertexScorch; ///< Scorch vertex buffer.
DX8IndexBufferClass* m_indexScorch; ///< indices defining a triangles for the scorch drawing.
TextureClass* m_scorchTexture; ///< Scorch mark texture
Int m_curNumScorchVertices; ///< number of vertices used in m_vertexScorch.
Int m_curNumScorchIndices; ///< number of indices used in m_indexScorch.
TScorch m_scorches[MAX_SCORCH_MARKS];
Int m_numScorches;
Int m_scorchesInBuffer; ///< how many are in the buffers. If less than numScorches, we need to update
std::deque<TScorch> m_scorches;
Bool m_needBufferRecompute;
Bool m_deduplicateScorches;
};

Expand Down
251 changes: 120 additions & 131 deletions Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DScorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,19 @@ W3DScorch::W3DScorch(bool deduplicateScorches)
, m_scorchTexture(nullptr)
, m_curNumScorchVertices(0)
, m_curNumScorchIndices(0)
, m_numScorches(0)
, m_scorchesInBuffer(0)
, m_needBufferRecompute(true)
, m_deduplicateScorches(deduplicateScorches)
{}

W3DScorch::~W3DScorch() { freeBuffers(); }

void W3DScorch::allocateBuffers()
{
freeBuffers();
m_vertexScorch = NEW_REF(DX8VertexBufferClass, (DX8_FVF_XYZDUV1, MAX_SCORCH_VERTEX, DX8VertexBufferClass::USAGE_DEFAULT));
m_indexScorch = NEW_REF(DX8IndexBufferClass, (MAX_SCORCH_INDEX));
m_scorchTexture = NEW ScorchTextureClass;
invalidateBuffers();
#ifdef RTS_DEBUG
Vector3 loc(4 * MAP_XY_FACTOR, 4 * MAP_XY_FACTOR, 0);
addScorch(loc, 1 * MAP_XY_FACTOR, SCORCH_1);
loc.Y += 10 * MAP_XY_FACTOR;
loc.X += 5 * MAP_XY_FACTOR;
addScorch(loc, 3 * MAP_XY_FACTOR, SCORCH_1);
#endif
}

void W3DScorch::freeBuffers()
Expand All @@ -63,13 +56,13 @@ void W3DScorch::freeBuffers()

void W3DScorch::clearAllScorches()
{
m_numScorches = 0;
m_scorches.clear();
invalidateBuffers();
}

void W3DScorch::invalidateBuffers()
{
m_scorchesInBuffer = 0;
m_needBufferRecompute = true;
m_curNumScorchVertices = 0;
m_curNumScorchIndices = 0;
}
Expand All @@ -84,36 +77,39 @@ void W3DScorch::invalidateTexture()

void W3DScorch::addScorch(Vector3 location, Real radius, Scorches type)
{
if (m_numScorches >= MAX_SCORCH_MARKS)
TScorch scorch;
scorch.location = location;
scorch.radius = radius;
scorch.scorchType = type < 0 || (Int)type >= SCORCH_MARKS_IN_TEXTURE ? SCORCH_1 : type;

if (m_deduplicateScorches && isDuplicate(scorch))
{
Int i;
for (i = 0; i < MAX_SCORCH_MARKS - 1; i++)
{
m_scorches[i] = m_scorches[i + 1];
}
m_numScorches--;
return;
}

if ((Int)m_scorches.size() >= MAX_SCORCH_MARKS)
{
m_scorches.pop_front();
}
m_scorches.push_back(scorch);

invalidateBuffers();
}

if (m_deduplicateScorches)
Bool W3DScorch::isDuplicate(const TScorch& scorch) const
{
const Real limit = scorch.radius / 4;
for (std::deque<TScorch>::const_iterator it = m_scorches.begin(); it != m_scorches.end(); ++it)
{
const Real limit = radius / 4;
for (Int i = 0; i < m_numScorches; i++)
if (it->scorchType == scorch.scorchType &&
abs(scorch.location.X - it->location.X) < limit &&
abs(scorch.location.Y - it->location.Y) < limit &&
abs(scorch.radius - it->radius) < limit)
{
if (abs(location.X - m_scorches[i].location.X) < limit &&
abs(location.Y - m_scorches[i].location.Y) < limit &&
abs(radius - m_scorches[i].radius) < limit &&
m_scorches[i].scorchType == type)
{
return; // basically a duplicate.
}
return true;
}
}

m_scorches[m_numScorches].location = location;
m_scorches[m_numScorches].radius = radius;
m_scorches[m_numScorches].scorchType = type;
m_numScorches++;
m_scorchesInBuffer = 0; // force buffer regenerations.
return false;
}

void W3DScorch::drawScorches(WorldHeightMap& map)
Expand All @@ -140,128 +136,121 @@ static Real getMapHeight(WorldHeightMap& map, Int x, Int y)

void W3DScorch::updateScorches(WorldHeightMap& map)
{
if (m_scorchesInBuffer > 1)
{
return;
}
if (m_numScorches == 0)
{
return;
}
if (!m_indexScorch || !m_vertexScorch)
if (!m_needBufferRecompute || m_scorches.empty() || !m_indexScorch || !m_vertexScorch)
{
return;
}

m_needBufferRecompute = false;
m_curNumScorchVertices = 0;
m_curNumScorchIndices = 0;

DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexScorch);
UnsignedShort* ib = lockIdxBuffer.Get_Index_Array();
UnsignedShort* curIb = ib;

DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexScorch);
VertexFormatXYZDUV1* vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array();
VertexFormatXYZDUV1* curVb = vb;

Real shadeR = (TheGlobalData->m_terrainAmbient[0].red + TheGlobalData->m_terrainDiffuse[0].red) / 2.0f;
Real shadeG = (TheGlobalData->m_terrainAmbient[0].green + TheGlobalData->m_terrainDiffuse[0].green) / 2.0f;
Real shadeB = (TheGlobalData->m_terrainAmbient[0].blue + TheGlobalData->m_terrainDiffuse[0].blue) / 2.0f;
UnsignedInt diffuse = DX8Wrapper::Convert_Color_Clamp(Vector4(shadeR, shadeG, shadeB, 1.0f));

m_scorchesInBuffer = 0;
for (Int curScorch = m_numScorches - 1; curScorch >= 0; curScorch--)
// TheSuperHackers @info Scorches are written in reverse order to ensure that the last added scorches fit in the buffers.
for (std::deque<TScorch>::reverse_iterator it = m_scorches.rbegin(); it != m_scorches.rend(); ++it)
{
m_scorchesInBuffer++;
Real radius = m_scorches[curScorch].radius;
Vector3 loc = m_scorches[curScorch].location;
Int type = m_scorches[curScorch].scorchType;
if (type < 0)
{
type = 0;
}
if (type >= SCORCH_MARKS_IN_TEXTURE)
{
type = 0;
}
Real amtToFloat = 0;
amtToFloat = MAP_HEIGHT_SCALE / 10;
if (!writeScorchToBuffer(*it, map, diffuse,
vb + m_curNumScorchVertices, ib + m_curNumScorchIndices))
return;
}
}

Int minX = REAL_TO_INT_FLOOR((loc.X - radius) / MAP_XY_FACTOR);
Int minY = REAL_TO_INT_FLOOR((loc.Y - radius) / MAP_XY_FACTOR);
if (minX < -map.getBorderSizeInline())
minX = -map.getBorderSizeInline();
if (minY < -map.getBorderSizeInline())
minY = -map.getBorderSizeInline();
Int maxX = REAL_TO_INT_CEIL((loc.X + radius) / MAP_XY_FACTOR);
Int maxY = REAL_TO_INT_CEIL((loc.Y + radius) / MAP_XY_FACTOR);
maxX++;
maxY++;
if (maxX > map.getXExtent() - map.getBorderSizeInline())
{
maxX = map.getXExtent() - map.getBorderSizeInline();
}
if (maxY > map.getYExtent() - map.getBorderSizeInline())
Bool W3DScorch::writeScorchToBuffer(const TScorch& scorch, WorldHeightMap& map, UnsignedInt diffuse,
VertexFormatXYZDUV1* curVb, UnsignedShort* curIb)
{
Real radius = scorch.radius;
Vector3 loc = scorch.location;
Int type = scorch.scorchType;
Real amtToFloat = MAP_HEIGHT_SCALE / 10;

Int minX = REAL_TO_INT_FLOOR((loc.X - radius) / MAP_XY_FACTOR);
Int minY = REAL_TO_INT_FLOOR((loc.Y - radius) / MAP_XY_FACTOR);
if (minX < -map.getBorderSizeInline())
minX = -map.getBorderSizeInline();
if (minY < -map.getBorderSizeInline())
minY = -map.getBorderSizeInline();
Int maxX = REAL_TO_INT_CEIL((loc.X + radius) / MAP_XY_FACTOR);
Int maxY = REAL_TO_INT_CEIL((loc.Y + radius) / MAP_XY_FACTOR);
maxX++;
maxY++;
if (maxX > map.getXExtent() - map.getBorderSizeInline())
{
maxX = map.getXExtent() - map.getBorderSizeInline();
}
if (maxY > map.getYExtent() - map.getBorderSizeInline())
{
maxY = map.getYExtent() - map.getBorderSizeInline();
}
Int startVertex = m_curNumScorchVertices;
Int i, j;
for (j = minY; j < maxY; j++)
{
for (i = minX; i < maxX; i++)
{
maxY = map.getYExtent() - map.getBorderSizeInline();
if (m_curNumScorchVertices >= MAX_SCORCH_VERTEX)
return false;
curVb->diffuse = diffuse;
Real theZ = amtToFloat + getMapHeight(map, i, j);
// The scorchmarks are spaced out by 1.5 in the texture.
Real uOffset = (type % SCORCH_PER_ROW) * 1.5f;
Real vOffset = (type / SCORCH_PER_ROW) * 1.5f;
Real X = i * MAP_XY_FACTOR;
Real Y = j * MAP_XY_FACTOR;
curVb->u1 = (uOffset + 0.5f + (X - loc.X) / (2 * radius)) / (SCORCH_PER_ROW + 1);
curVb->v1 = (vOffset + 0.5f + (Y - loc.Y) / (2 * radius)) / (SCORCH_PER_ROW + 1);
curVb->x = X;
curVb->y = Y;
curVb->z = theZ;
curVb++;
m_curNumScorchVertices++;
}
Int startVertex = m_curNumScorchVertices;
Int i, j;
for (j = minY; j < maxY; j++)
}
Int yOffset = maxX - minX;
for (j = 0; j < maxY - minY - 1; j++)
{
for (i = 0; i < maxX - minX - 1; i++)
{
for (i = minX; i < maxX; i++)
if (m_curNumScorchIndices + 6 > MAX_SCORCH_INDEX)
return false;
Int xNdx = i + minX + map.getBorderSizeInline();
Int yNdx = j + minY + map.getBorderSizeInline();
Bool flipForBlend = map.getFlipState(xNdx, yNdx);
#if 0
UnsignedByte alpha[4];
float UA[4], VA[4];
map.getAlphaUVData(xNdx, yNdx, UA, VA, alpha, &flipForBlend);
#endif
if (flipForBlend)
{
if (m_curNumScorchVertices >= MAX_SCORCH_VERTEX)
return;
curVb->diffuse = diffuse;
Real theZ = amtToFloat + getMapHeight(map, i, j);
// The scorchmarks are spaced out by 1.5 in the texture.
Real uOffset = (type % SCORCH_PER_ROW) * 1.5f;
Real vOffset = (type / SCORCH_PER_ROW) * 1.5f;
Real X = i * MAP_XY_FACTOR;
Real Y = j * MAP_XY_FACTOR;
curVb->u1 = (uOffset + 0.5f + (X - loc.X) / (2 * radius)) / (SCORCH_PER_ROW + 1);
curVb->v1 = (vOffset + 0.5f + (Y - loc.Y) / (2 * radius)) / (SCORCH_PER_ROW + 1);
curVb->x = X;
curVb->y = Y;
curVb->z = theZ;
curVb++;
m_curNumScorchVertices++;
*curIb++ = startVertex + j * yOffset + i + 1;
*curIb++ = startVertex + j * yOffset + i + yOffset;
*curIb++ = startVertex + j * yOffset + i;
*curIb++ = startVertex + j * yOffset + i + 1;
*curIb++ = startVertex + j * yOffset + i + 1 + yOffset;
*curIb++ = startVertex + j * yOffset + i + yOffset;
}
}
Int yOffset = maxX - minX;
for (j = 0; j < maxY - minY - 1; j++)
{
for (i = 0; i < maxX - minX - 1; i++)
else
{
if (m_curNumScorchIndices + 6 > MAX_SCORCH_INDEX)
return;
Int xNdx = i + minX + map.getBorderSizeInline();
Int yNdx = j + minY + map.getBorderSizeInline();
Bool flipForBlend = map.getFlipState(xNdx, yNdx);
#if 0
UnsignedByte alpha[4];
float UA[4], VA[4];
map.getAlphaUVData(xNdx, yNdx, UA, VA, alpha, &flipForBlend);
#endif
if (flipForBlend)
{
*curIb++ = startVertex + j * yOffset + i + 1;
*curIb++ = startVertex + j * yOffset + i + yOffset;
*curIb++ = startVertex + j * yOffset + i;
*curIb++ = startVertex + j * yOffset + i + 1;
*curIb++ = startVertex + j * yOffset + i + 1 + yOffset;
*curIb++ = startVertex + j * yOffset + i + yOffset;
}
else
{
*curIb++ = startVertex + j * yOffset + i;
*curIb++ = startVertex + j * yOffset + i + 1 + yOffset;
*curIb++ = startVertex + j * yOffset + i + yOffset;
*curIb++ = startVertex + j * yOffset + i;
*curIb++ = startVertex + j * yOffset + i + 1;
*curIb++ = startVertex + j * yOffset + i + 1 + yOffset;
}
m_curNumScorchIndices += 6;
*curIb++ = startVertex + j * yOffset + i;
*curIb++ = startVertex + j * yOffset + i + 1 + yOffset;
*curIb++ = startVertex + j * yOffset + i + yOffset;
*curIb++ = startVertex + j * yOffset + i;
*curIb++ = startVertex + j * yOffset + i + 1;
*curIb++ = startVertex + j * yOffset + i + 1 + yOffset;
}
m_curNumScorchIndices += 6;
}
}

return true;
}
Loading