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;
+ }
+ }
+ }
+}