Skip to content

Commit 4d1e1e1

Browse files
committed
implement height based terrain lighting for water
1 parent 1f456cf commit 4d1e1e1

3 files changed

Lines changed: 131 additions & 1 deletion

File tree

Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
/*
22
** Command & Conquer Generals Zero Hour(tm)
33
** Copyright 2025 Electronic Arts Inc.
44
**
@@ -492,6 +492,13 @@ void BaseHeightMapRenderObjClass::ReAcquireResources(void)
492492
}
493493
}
494494

495+
// --------
496+
static float invLerp(float a, float b, float v)
497+
{
498+
if (a == b) return 0.0f; // avoid divide by zero
499+
return (v - a) / (b - a);
500+
}
501+
495502
//=============================================================================
496503
// BaseHeightMapRenderObjClass::doTheLight
497504
//=============================================================================
@@ -591,6 +598,99 @@ void BaseHeightMapRenderObjClass::doTheLight(VERTEX_FORMAT *vb, Vector3*light, V
591598
if (shadeB > 1.0) shadeB = 1.0;
592599
if(shadeB < 0.0f) shadeB = 0.0f;
593600

601+
// ---------------------------------------------
602+
// Height based ambient light factor (for water)
603+
// ---------------------------------------------
604+
if (TheGlobalData &&
605+
TheGlobalData->m_terrainHeightAmbientLightHeightStart > 0 &&
606+
(TheGlobalData->m_terrainHeightAmbientLightHeight1 >= 0 || TheGlobalData->m_terrainHeightAmbientLightHeight2 >= 0) &&
607+
vb->z <= TheGlobalData->m_terrainHeightAmbientLightHeightStart
608+
) {
609+
Real col1R, col1G, col1B, col2R, col2G, col2B;
610+
//Real factor1 = 0.0;
611+
//Real factor2 = 0.0;
612+
Real height1 = -1;
613+
Real height2 = -1;
614+
615+
Real colR;
616+
Real colG;
617+
Real colB;
618+
619+
// case 1: only one color
620+
if (TheGlobalData->m_terrainHeightAmbientLightHeight1 <= 0)
621+
{
622+
col1R = TheGlobalData->m_terrainHeightAmbientLightColor2.red;
623+
col1G = TheGlobalData->m_terrainHeightAmbientLightColor2.green;
624+
col1B = TheGlobalData->m_terrainHeightAmbientLightColor2.blue;
625+
height1 = TheGlobalData->m_terrainHeightAmbientLightHeight2;
626+
}
627+
else if (TheGlobalData->m_terrainHeightAmbientLightHeight2 <= 0) {
628+
col1R = TheGlobalData->m_terrainHeightAmbientLightColor1.red;
629+
col1G = TheGlobalData->m_terrainHeightAmbientLightColor1.green;
630+
col1B = TheGlobalData->m_terrainHeightAmbientLightColor1.blue;
631+
height1 = TheGlobalData->m_terrainHeightAmbientLightHeight1;
632+
}
633+
else
634+
{ // case 2: both colors
635+
636+
col1R = TheGlobalData->m_terrainHeightAmbientLightColor1.red;
637+
col1G = TheGlobalData->m_terrainHeightAmbientLightColor1.green;
638+
col1B = TheGlobalData->m_terrainHeightAmbientLightColor1.blue;
639+
col2R = TheGlobalData->m_terrainHeightAmbientLightColor2.red;
640+
col2G = TheGlobalData->m_terrainHeightAmbientLightColor2.green;
641+
col2B = TheGlobalData->m_terrainHeightAmbientLightColor2.blue;
642+
height1 = TheGlobalData->m_terrainHeightAmbientLightHeight1;
643+
height2 = TheGlobalData->m_terrainHeightAmbientLightHeight2;
644+
}
645+
646+
bool multiply = !TheGlobalData->m_terrainHeightAmbientLightAdditive;
647+
Real base;
648+
if (multiply)
649+
base = 1.0;
650+
else
651+
base = 0.0;
652+
653+
if (vb->z > height1) {
654+
Real t = WWMath::Clamp(invLerp(TheGlobalData->m_terrainHeightAmbientLightHeightStart, height1, vb->z));
655+
colR = col1R * t + (1.0 - t) * base;
656+
colG = col1G * t + (1.0 - t) * base;
657+
colB = col1B * t + (1.0 - t) * base;
658+
}
659+
660+
// Between height1 and height2
661+
else if (height2 > -1 && vb->z > height2)
662+
{
663+
Real t = WWMath::Clamp(invLerp(height1, height2, vb->z));
664+
Real factor1 = 1.0f - t; // 1 → 0
665+
Real factor2 = t; // 0 → 1
666+
667+
colR = col1R * factor1 + col2R * factor2;
668+
colG = col1G * factor1 + col2G * factor2;
669+
colB = col1B * factor1 + col2B * factor2;
670+
}
671+
// below
672+
else {
673+
colR = col2R;
674+
colG = col2G;
675+
colB = col2B;
676+
}
677+
678+
if (multiply) {
679+
shadeR *= colR;
680+
shadeG *= colG;
681+
shadeB *= colB;
682+
}
683+
else {
684+
shadeR = WWMath::Clamp(shadeR + colR);
685+
shadeG = WWMath::Clamp(shadeG + colG);
686+
shadeB = WWMath::Clamp(shadeB + colB);
687+
}
688+
}
689+
// ---------------------------------------------
690+
691+
692+
693+
// Old, inactive code
594694
if (m_useDepthFade && vb->z <= TheGlobalData->m_waterPositionZ)
595695
{ //height is below water level
596696
//reduce lighting values based on light fall off as it travels through water.

GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,14 @@ class GlobalData : public SubsystemInterface
590590
Bool m_heightAboveTerrainIncludesWater;
591591
Bool m_hideScorchmarksAboveGround;
592592

593+
// Water depth lighting
594+
RGBColor m_terrainHeightAmbientLightColor1;
595+
RGBColor m_terrainHeightAmbientLightColor2;
596+
Real m_terrainHeightAmbientLightHeightStart;
597+
Real m_terrainHeightAmbientLightHeight1;
598+
Real m_terrainHeightAmbientLightHeight2;
599+
Bool m_terrainHeightAmbientLightAdditive;
600+
593601
// the trailing '\' is included!
594602
const AsciiString &getPath_UserData() const { return m_userDataDir; }
595603

GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,14 @@ GlobalData* GlobalData::m_theOriginal = NULL;
575575
{"DefaultExcludedDeathTypes", INI::parseDeathTypeFlagsList, NULL, offsetof(GlobalData, m_defaultExcludedDeathTypes) },
576576
{"HeightAboveTerrainIncludesWater", INI::parseBool, NULL, offsetof(GlobalData, m_heightAboveTerrainIncludesWater) },
577577
{"HideScorchmarksAboveGround", INI::parseBool, NULL, offsetof(GlobalData, m_hideScorchmarksAboveGround) },
578+
579+
580+
{ "TerrainHeightAmbientLightColor1", INI::parseRGBColor, NULL, offsetof(GlobalData, m_terrainHeightAmbientLightColor1) },
581+
{ "TerrainHeightAmbientLightColor2", INI::parseRGBColor, NULL, offsetof(GlobalData, m_terrainHeightAmbientLightColor2) },
582+
{ "TerrainHeightAmbientLightStart", INI::parseReal, NULL, offsetof(GlobalData, m_terrainHeightAmbientLightHeightStart) },
583+
{ "TerrainHeightAmbientLightHeight1", INI::parseReal, NULL, offsetof(GlobalData, m_terrainHeightAmbientLightHeight1) },
584+
{ "TerrainHeightAmbientLightHeight2", INI::parseReal, NULL, offsetof(GlobalData, m_terrainHeightAmbientLightHeight2) },
585+
{ "TerrainHeightAmbientLightAdditive", INI::parseBool, NULL, offsetof(GlobalData, m_terrainHeightAmbientLightAdditive) },
578586
{ NULL, NULL, NULL, 0 } // keep this last
579587

580588
};
@@ -1163,6 +1171,20 @@ GlobalData::GlobalData()
11631171

11641172
m_heightAboveTerrainIncludesWater = false;
11651173

1174+
m_terrainHeightAmbientLightColor1.red = 0;
1175+
m_terrainHeightAmbientLightColor1.green = 0;
1176+
m_terrainHeightAmbientLightColor1.blue = 0;
1177+
1178+
m_terrainHeightAmbientLightColor2.red = 0;
1179+
m_terrainHeightAmbientLightColor2.green = 0;
1180+
m_terrainHeightAmbientLightColor2.blue = 0;
1181+
1182+
m_terrainHeightAmbientLightHeightStart = -1;
1183+
m_terrainHeightAmbientLightHeight1 = -1;
1184+
m_terrainHeightAmbientLightHeight2 = -1;
1185+
1186+
m_terrainHeightAmbientLightAdditive = false;
1187+
11661188
} // end GlobalData
11671189

11681190

0 commit comments

Comments
 (0)