diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DScorch.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DScorch.h index 927ff86c965..02423a0e867 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DScorch.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DScorch.h @@ -18,10 +18,13 @@ #pragma once +#include + #include "WWMath/vector3.h" #include "Common/GameType.h" #include "Lib/BaseTypeCore.h" +struct VertexFormatXYZDUV1; class TextureClass; class DX8IndexBufferClass; class DX8VertexBufferClass; @@ -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 m_scorches; + Bool m_needBufferRecompute; Bool m_deduplicateScorches; }; diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DScorch.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DScorch.cpp index 38b869c5738..ecc6d294b38 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DScorch.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DScorch.cpp @@ -32,8 +32,7 @@ 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) {} @@ -41,17 +40,11 @@ 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() @@ -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; } @@ -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::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) @@ -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::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; }