diff --git a/Core/GameEngineDevice/CMakeLists.txt b/Core/GameEngineDevice/CMakeLists.txt index cf7e2cae76d..b3a569b032e 100644 --- a/Core/GameEngineDevice/CMakeLists.txt +++ b/Core/GameEngineDevice/CMakeLists.txt @@ -59,6 +59,7 @@ set(GAMEENGINEDEVICE_SRC Include/W3DDevice/GameClient/W3DProfilerFrameCapture.h # Include/W3DDevice/GameClient/W3DProjectedShadow.h Include/W3DDevice/GameClient/W3DPropBuffer.h + Include/W3DDevice/GameClient/W3DScorch.h # Include/W3DDevice/GameClient/W3DRoadBuffer.h # Include/W3DDevice/GameClient/W3DScene.h Include/W3DDevice/GameClient/W3DShaderManager.h @@ -163,6 +164,7 @@ set(GAMEENGINEDEVICE_SRC # Source/W3DDevice/GameClient/W3DPoly.cpp Source/W3DDevice/GameClient/W3DProfilerFrameCapture.cpp Source/W3DDevice/GameClient/W3DPropBuffer.cpp + Source/W3DDevice/GameClient/W3DScorch.cpp # Source/W3DDevice/GameClient/W3DRoadBuffer.cpp # Source/W3DDevice/GameClient/W3DScene.cpp Source/W3DDevice/GameClient/W3DShaderManager.cpp diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h index 6feed84e471..32c87202e6d 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h @@ -46,6 +46,7 @@ class W3DWaypointBuffer; class W3DTerrainLogic; class W3DAssetManager; class SimpleSceneClass; +class W3DScorch; class W3DShroud; class W3DPropDrawModuleData; class W3DPropBuffer; @@ -70,14 +71,6 @@ class W3DDynamicLight; #define DO_ROADS 1 -#ifdef DO_SCORCH -typedef struct { - Vector3 location; - Real radius; - Int scorchType; -} TScorch; -#endif - #define VERTEX_FORMAT VertexFormatXYZDUV2 #define DX8_VERTEX_FORMAT DX8_FVF_XYZDUV2 @@ -195,6 +188,7 @@ class BaseHeightMapRenderObjClass : public RenderObjClass, public DX8_CleanupHoo void updateShorelineTile(Int X, Int Y, Int Border, WorldHeightMap *pMap); ///
. +*/ + +#pragma once + +#include "WWMath/vector3.h" +#include "Common/GameType.h" +#include "Lib/BaseTypeCore.h" + +class TextureClass; +class DX8IndexBufferClass; +class DX8VertexBufferClass; +class WorldHeightMap; + +class W3DScorch +{ +public: + W3DScorch(); + virtual ~W3DScorch(); + + virtual void allocateScorchBuffers(); ///< allocate static buffers for drawing scorch marks. + virtual void freeBuffers(); ///< frees up scorch buffers. + virtual void clearAllScorches(); + virtual void invalidateBuffers(); + virtual void addScorch(Vector3 location, Real radius, Scorches type); + virtual void drawScorches(WorldHeightMap* map); ///< Draws the scorch mark polygons in m_vertexScorch. + +private: + typedef struct + { + Vector3 location; + Real radius; + Int scorchType; + } TScorch; + + enum + { + MAX_SCORCH_VERTEX = 8194, + MAX_SCORCH_INDEX = 6 * 8194, + MAX_SCORCH_MARKS = 500, + SCORCH_MARKS_IN_TEXTURE = 9, + SCORCH_PER_ROW = 3 + }; + + virtual void updateScorches(WorldHeightMap* map); ///< Update m_vertexScorch and m_indexScorch so all scorches will be drawn. + + 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 +}; + +class W3DScorchDummy : public W3DScorch +{ +public: + void allocateScorchBuffers() override {} + void freeBuffers() override {} + void clearAllScorches() override {} + void invalidateBuffers() override {} + void addScorch(Vector3 location, Real radius, Scorches type) override {} + void drawScorches(WorldHeightMap* map) override {} + +private: + void updateScorches(WorldHeightMap* map) override {} +}; diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp index 397d5eee749..0f63d2b2e86 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp @@ -78,6 +78,7 @@ #include "W3DDevice/GameClient/W3DWaypointBuffer.h" #include "W3DDevice/GameClient/W3DCustomEdging.h" #include "W3DDevice/GameClient/WorldHeightMap.h" +#include "W3DDevice/GameClient/W3DScorch.h" #include "W3DDevice/GameClient/W3DShaderManager.h" #include "W3DDevice/GameClient/W3DShadow.h" #include "W3DDevice/GameClient/W3DWater.h" @@ -149,9 +150,8 @@ inline Int IABS(Int x) { if (x>=0) return x; return -x;}; //============================================================================= Int BaseHeightMapRenderObjClass::freeMapResources() { -#ifdef DO_SCORCH - freeScorchBuffers(); -#endif + m_scorches->freeBuffers(); + REF_PTR_RELEASE(m_vertexMaterialClass); REF_PTR_RELEASE(m_stageZeroTexture); REF_PTR_RELEASE(m_stageOneTexture); @@ -163,7 +163,6 @@ Int BaseHeightMapRenderObjClass::freeMapResources() return 0; } -#ifdef DO_SCORCH //============================================================================= // BaseHeightMapRenderObjClass::drawScorches //============================================================================= @@ -171,22 +170,11 @@ Int BaseHeightMapRenderObjClass::freeMapResources() //============================================================================= void BaseHeightMapRenderObjClass::drawScorches() { - - updateScorches(); - if (m_curNumScorchIndices == 0) { - return; - } - DX8Wrapper::Set_Index_Buffer(m_indexScorch,0); - DX8Wrapper::Set_Vertex_Buffer(m_vertexScorch); - DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader); - - DX8Wrapper::Set_Texture(0,m_scorchTexture); - if (Is_Hidden() == 0) { - DX8Wrapper::Draw_Triangles( 0,m_curNumScorchIndices/3, 0, m_curNumScorchVertices); + ShaderClass::Invalidate(); + if (Is_Hidden() == 0 && !ShaderClass::Is_Backface_Culling_Inverted()) { + m_scorches->drawScorches(m_map); } } -#endif - //----------------------------------------------------------------------------- // Public Functions @@ -224,6 +212,9 @@ BaseHeightMapRenderObjClass::~BaseHeightMapRenderObjClass() delete m_shroud; m_shroud = nullptr; + delete m_scorches; + m_scorches = nullptr; + delete [] m_shoreLineTilePositions; m_shoreLineTilePositions = nullptr; @@ -280,12 +271,10 @@ BaseHeightMapRenderObjClass::BaseHeightMapRenderObjClass() #ifdef DO_ROADS m_roadBuffer = nullptr; #endif -#ifdef DO_SCORCH - m_vertexScorch = nullptr; - m_indexScorch = nullptr; - m_scorchTexture = nullptr; - clearAllScorches(); - m_shroud = nullptr; +#if DO_SCORCH + m_scorches = NEW W3DScorch; +#else + m_scorches = NEW W3DScorchDummy; #endif m_bridgeBuffer = NEW W3DBridgeBuffer; @@ -303,6 +292,7 @@ BaseHeightMapRenderObjClass::BaseHeightMapRenderObjClass() #ifdef DO_ROADS m_roadBuffer = NEW W3DRoadBuffer; #endif + m_shroud = nullptr; #if ENABLE_CONFIGURABLE_SHROUD if (TheGlobalData->m_shroudOn) m_shroud = NEW W3DShroud; @@ -1833,9 +1823,8 @@ Int BaseHeightMapRenderObjClass::initHeightData(Int x, Int y, WorldHeightMap *pM Set_Force_Visible(TRUE); //terrain is always visible. scheduleFullUpdate(); - m_scorchesInBuffer = 0; - m_curNumScorchVertices=0; - m_curNumScorchIndices=0; + m_scorches->invalidateBuffers(); + // If the textures aren't allocated (usually because of a hardware reset) need to allocate. Bool needToAllocate = false; if (m_stageTwoTexture == nullptr && m_treeBuffer) { @@ -1850,9 +1839,7 @@ Int BaseHeightMapRenderObjClass::initHeightData(Int x, Int y, WorldHeightMap *pM m_stageThreeTexture=NEW LightMapTerrainTextureClass(m_macroTextureName); m_destAlphaTexture=MSGNEW("TextureClass") TextureClass(256,1,WW3D_FORMAT_A8R8G8B8,MIP_LEVELS_1); initDestAlphaLUT(); -#ifdef DO_SCORCH - allocateScorchBuffers(); -#endif + m_scorches->allocateScorchBuffers(); m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); @@ -1862,168 +1849,6 @@ Int BaseHeightMapRenderObjClass::initHeightData(Int x, Int y, WorldHeightMap *pM return 0; } -#ifdef DO_SCORCH -//============================================================================= -// BaseHeightMapRenderObjClass::freeScorchBuffers -//============================================================================= -/** Frees the vertex buffers for scorches.*/ -//============================================================================= -void BaseHeightMapRenderObjClass::freeScorchBuffers() -{ - REF_PTR_RELEASE(m_vertexScorch); - REF_PTR_RELEASE(m_indexScorch); - REF_PTR_RELEASE(m_scorchTexture); -} - -//============================================================================= -// BaseHeightMapRenderObjClass::allocateScorchBuffers -//============================================================================= -/** Allocates the vertex buffer and texture for scorches.*/ -//============================================================================= -void BaseHeightMapRenderObjClass::allocateScorchBuffers() -{ - 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; - m_scorchesInBuffer = 0; // If we just allocated the buffers, we got no scorches in the buffer. - m_curNumScorchVertices=0; - m_curNumScorchIndices=0; -#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 - -} - -//============================================================================= -// BaseHeightMapRenderObjClass::updateScorches -//============================================================================= -/** Builds the vertex buffer data for drawing the scorches.*/ -//============================================================================= -void BaseHeightMapRenderObjClass::updateScorches() -{ - if (m_scorchesInBuffer > 1) { - return; - } - if (m_numScorches==0) { - return; - } - if (!m_indexScorch || !m_vertexScorch) { - return; - } - 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; - - Int curScorch; - Real shadeR, shadeG, shadeB; - shadeR = TheGlobalData->m_terrainAmbient[0].red; - shadeG = TheGlobalData->m_terrainAmbient[0].green; - shadeB = TheGlobalData->m_terrainAmbient[0].blue; - shadeR += TheGlobalData->m_terrainDiffuse[0].red/2; - shadeG += TheGlobalData->m_terrainDiffuse[0].green/2; - shadeB += TheGlobalData->m_terrainDiffuse[0].blue/2; - shadeR*=255.0f; - shadeG*=255.0f; - shadeB*=255.0f; - Int diffuse=REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16) | ((int)255 << 24); - m_scorchesInBuffer = 0; - for (curScorch=m_numScorches-1; curScorch>=0; curScorch--) { - 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; - - 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<-m_map->getBorderSizeInline()) minX=-m_map->getBorderSizeInline(); - if (minY<-m_map->getBorderSizeInline()) minY=-m_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 > m_map->getXExtent()-m_map->getBorderSizeInline()) { - maxX = m_map->getXExtent()-m_map->getBorderSizeInline(); - } - if (maxY > m_map->getYExtent()-m_map->getBorderSizeInline()) { - maxY = m_map->getYExtent()-m_map->getBorderSizeInline(); - } - Int startVertex = m_curNumScorchVertices; - Int i, j; - for (j=minY; j= MAX_SCORCH_VERTEX) return; - curVb->diffuse = diffuse; - Real theZ; - theZ = amtToFloat+((float)getClipHeight(i+m_map->getBorderSizeInline(),j+m_map->getBorderSizeInline())*MAP_HEIGHT_SCALE); - // 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 yOffset = maxX-minX; - for (j=0; j MAX_SCORCH_INDEX) return; - Int xNdx = i+minX+m_map->getBorderSizeInline(); - Int yNdx = j+minY+m_map->getBorderSizeInline(); - Bool flipForBlend = m_map->getFlipState(xNdx, yNdx); -#if 0 - UnsignedByte alpha[4]; - float UA[4], VA[4]; - m_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; - } - } - } - -} - -#endif - //============================================================================= // BaseHeightMapRenderObjClass::clearAllScorches //============================================================================= @@ -2031,10 +1856,7 @@ void BaseHeightMapRenderObjClass::updateScorches() //============================================================================= void BaseHeightMapRenderObjClass::clearAllScorches() { -#ifdef DO_SCORCH - m_numScorches=0; - m_scorchesInBuffer=0; -#endif + m_scorches->clearAllScorches(); } //============================================================================= @@ -2044,35 +1866,9 @@ void BaseHeightMapRenderObjClass::clearAllScorches() //============================================================================= void BaseHeightMapRenderObjClass::addScorch(Vector3 location, Real radius, Scorches type) { -#ifdef DO_SCORCH - if (m_numScorches >= MAX_SCORCH_MARKS) { - Int i; - for (i=0; iaddScorch(location, radius, type); } - //============================================================================= // BaseHeightMapRenderObjClass::getStaticDiffuse //============================================================================= @@ -2363,9 +2159,8 @@ void BaseHeightMapRenderObjClass::staticLightingChanged() scheduleFullUpdate(); // Cause the scorches to get updated with new lighting. - m_scorchesInBuffer = 0; // If we just allocated the buffers, we got no scorches in the buffer. - m_curNumScorchVertices=0; - m_curNumScorchIndices=0; + m_scorches->invalidateBuffers(); + if (m_roadBuffer) m_roadBuffer->updateLighting(); diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp index c2daacdf927..4309a1fbafa 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp @@ -606,16 +606,12 @@ void FlatHeightMapRenderObjClass::Render(RenderInfoClass & rinfo) } #endif -#ifdef DO_SCORCH DX8Wrapper::Set_Texture(0,nullptr); DX8Wrapper::Set_Texture(1,nullptr); m_stageTwoTexture->restore(); - ShaderClass::Invalidate(); - if (!ShaderClass::Is_Backface_Culling_Inverted()) { - drawScorches(); - } -#endif + drawScorches(); + DX8Wrapper::Set_Texture(0,nullptr); DX8Wrapper::Set_Texture(1,nullptr); m_stageTwoTexture->restore(); diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp index eddcf160ffa..9394e9e9e19 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp @@ -2100,16 +2100,12 @@ void HeightMapRenderObjClass::Render(RenderInfoClass & rinfo) if (m_propBuffer) { m_propBuffer->drawProps(rinfo); } - #ifdef DO_SCORCH DX8Wrapper::Set_Texture(0,nullptr); DX8Wrapper::Set_Texture(1,nullptr); m_stageTwoTexture->restore(); - ShaderClass::Invalidate(); - if (!ShaderClass::Is_Backface_Culling_Inverted()) { - drawScorches(); - } - #endif + drawScorches(); + DX8Wrapper::Set_Texture(0,nullptr); DX8Wrapper::Set_Texture(1,nullptr); m_stageTwoTexture->restore(); diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DScorch.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DScorch.cpp new file mode 100644 index 00000000000..b51e98061e1 --- /dev/null +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DScorch.cpp @@ -0,0 +1,266 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2026 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#include "W3DDevice/GameClient/W3DScorch.h" + +#include "Common/GameMemory.h" +#include "Common/GameType.h" +#include "Common/GlobalData.h" +#include "Common/MapObject.h" +#include "W3DDevice/GameClient/TerrainTex.h" +#include "W3DDevice/GameClient/WorldHeightMap.h" +#include "WW3D2/dx8wrapper.h" + +W3DScorch::W3DScorch() + : m_vertexScorch(nullptr) + , m_indexScorch(nullptr) + , m_scorchTexture(nullptr) + , m_curNumScorchVertices(0) + , m_curNumScorchIndices(0) + , m_numScorches(0) + , m_scorchesInBuffer(0) +{} + +W3DScorch::~W3DScorch() { freeBuffers(); } + +void W3DScorch::allocateScorchBuffers() +{ + 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() +{ + REF_PTR_RELEASE(m_vertexScorch); + REF_PTR_RELEASE(m_indexScorch); + REF_PTR_RELEASE(m_scorchTexture); +} + +void W3DScorch::clearAllScorches() +{ + m_numScorches = 0; + invalidateBuffers(); +} + +void W3DScorch::invalidateBuffers() +{ + m_scorchesInBuffer = 0; + m_curNumScorchVertices = 0; + m_curNumScorchIndices = 0; +} + +void W3DScorch::addScorch(Vector3 location, Real radius, Scorches type) +{ + if (m_numScorches >= MAX_SCORCH_MARKS) + { + Int i; + for (i = 0; i < MAX_SCORCH_MARKS - 1; i++) + { + m_scorches[i] = m_scorches[i + 1]; + } + m_numScorches--; + } + + Int i; + Real limit = radius / 4; + for (i = 0; i < m_numScorches; i++) + { + 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. + } + } + + 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. +} + +void W3DScorch::drawScorches(WorldHeightMap* map) +{ + updateScorches(map); + if (m_curNumScorchIndices == 0) + { + return; + } + DX8Wrapper::Set_Index_Buffer(m_indexScorch, 0); + DX8Wrapper::Set_Vertex_Buffer(m_vertexScorch); + DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader); + + DX8Wrapper::Set_Texture(0, m_scorchTexture); + DX8Wrapper::Draw_Triangles(0, m_curNumScorchIndices / 3, 0, m_curNumScorchVertices); +} + +static Real getMapHeight(WorldHeightMap* map, Int x, Int y) +{ + x += map->getBorderSizeInline(); + y += map->getBorderSizeInline(); + return map->getDataPtr()[x + y * map->getXExtent()] * MAP_HEIGHT_SCALE; +} + +void W3DScorch::updateScorches(WorldHeightMap* map) +{ + if (m_scorchesInBuffer > 1) + { + return; + } + if (m_numScorches == 0) + { + return; + } + if (!m_indexScorch || !m_vertexScorch) + { + return; + } + if (!map) + return; + + 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; + + Int curScorch; + Real shadeR, shadeG, shadeB; + shadeR = TheGlobalData->m_terrainAmbient[0].red; + shadeG = TheGlobalData->m_terrainAmbient[0].green; + shadeB = TheGlobalData->m_terrainAmbient[0].blue; + shadeR += TheGlobalData->m_terrainDiffuse[0].red / 2; + shadeG += TheGlobalData->m_terrainDiffuse[0].green / 2; + shadeB += TheGlobalData->m_terrainDiffuse[0].blue / 2; + shadeR *= 255.0f; + shadeG *= 255.0f; + shadeB *= 255.0f; + Int diffuse = REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16) | ((int)255 << 24); + m_scorchesInBuffer = 0; + for (curScorch = m_numScorches - 1; curScorch >= 0; curScorch--) + { + 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; + + 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++) + { + 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++; + } + } + Int yOffset = maxX - minX; + for (j = 0; j < maxY - minY - 1; j++) + { + for (i = 0; i < maxX - minX - 1; i++) + { + 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]; + m_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; + } + } + } +}