Skip to content
Merged
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
24 changes: 16 additions & 8 deletions Core/GameEngine/Source/GameClient/FXList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,11 +481,8 @@ class DecalFXNugget : public FXNugget

DecalFXNugget()
{
m_templateName.set("GenericDecal"); // TODO
//m_templateName = AsciiString::TheEmptyString;
//m_textureName = AsciiString::TheEmptyString;
//m_opacity = 1.0; ///< value between 0 and 1
//m_color = 0; ///< color in ARGB format. (Alpha is ignored).
// m_templateNames left empty; doFXPos falls back to "GenericDecal" if none listed.
m_scale.setRange(1.0f, 1.0f, GameClientRandomVariable::CONSTANT); // default = no scale variance
m_lifetime = 0;
/* m_fadeOutTime = 0;
m_fadeInTime = 0;
Expand Down Expand Up @@ -514,7 +511,12 @@ class DecalFXNugget : public FXNugget
}
}

Drawable* drawable = TheThingFactory->newDrawable(TheThingFactory->findTemplate(m_templateName));
// pick one of the listed decal templates at random (fall back to GenericDecal if none listed)
AsciiString tmplName = m_templateNames.empty()
? AsciiString("GenericDecal")
: m_templateNames[GameClientRandomValue(0, (Int)m_templateNames.size() - 1)];

Drawable* drawable = TheThingFactory->newDrawable(TheThingFactory->findTemplate(tmplName));
if (!drawable)
return;

Expand All @@ -531,6 +533,10 @@ class DecalFXNugget : public FXNugget
if (m_randomAngle)
drawable->setOrientation(GameClientRandomValueReal(0, PI * 2));

// apply per-spawn random uniform scale variance (default range 1..1 = no change);
// W3DDecalDraw multiplies its decal size by the drawable's instance scale.
drawable->setInstanceScale(drawable->getInstanceScale() * m_scale.getValue());

drawable->setExpirationDate(TheGameLogic->getFrame() + m_lifetime);
}
else
Expand All @@ -555,7 +561,8 @@ class DecalFXNugget : public FXNugget
{
static const FieldParse myFieldParse[] =
{
{ "DecalName", INI::parseAsciiString, nullptr, offsetof(DecalFXNugget, m_templateName) },
{ "DecalName", INI::parseAsciiStringVectorAppend, nullptr, offsetof(DecalFXNugget, m_templateNames) },
{ "Scale", INI::parseGameClientRandomVariable, nullptr, offsetof(DecalFXNugget, m_scale) },
{ "Lifetime", INI::parseDurationUnsignedInt, nullptr, offsetof(DecalFXNugget, m_lifetime) },
{ "Offset", INI::parseCoord3D, nullptr, offsetof(DecalFXNugget, m_offset) },
{ "Angle", INI::parseReal, nullptr, offsetof(DecalFXNugget, m_angle) },
Expand All @@ -571,7 +578,8 @@ class DecalFXNugget : public FXNugget
}

private:
AsciiString m_templateName;
std::vector<AsciiString> m_templateNames; ///< one is picked at random per spawn ("DecalName", repeatable)
GameClientRandomVariable m_scale; ///< random uniform size factor per spawn ("Scale = low high")
UnsignedInt m_lifetime;
Coord3D m_offset;
Real m_angle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class W3DDecalDrawModuleData : public ModuleData
ShadowType m_type; /// type of projection
Real m_decalSizeX; /// 1/(world space extent of texture in x direction)
Real m_decalSizeY; /// 1/(world space extent of texture in y direction)
Bool m_renderAboveWater; /// if true, this decal draws above water (else below, shadow-like)

W3DDecalDrawModuleData();
~W3DDecalDrawModuleData();
Expand Down
49 changes: 25 additions & 24 deletions Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include <d3dx8core.h>

#include "Common/GlobalData.h"
#include "Common/MapData.h"
#include "Common/PerfTimer.h"
#include "Common/Xfer.h"

Expand Down Expand Up @@ -602,10 +603,10 @@ void BaseHeightMapRenderObjClass::doTheLight(VERTEX_FORMAT *vb, Vector3*light, V
// ---------------------------------------------
// Height based ambient light factor (for water)
// ---------------------------------------------
if (TheGlobalData &&
TheGlobalData->m_terrainHeightAmbientLightHeightStart > 0 &&
(TheGlobalData->m_terrainHeightAmbientLightHeight1 >= 0 || TheGlobalData->m_terrainHeightAmbientLightHeight2 >= 0) &&
vb->z <= TheGlobalData->m_terrainHeightAmbientLightHeightStart
if (TheMapData &&
TheMapData->m_terrainHeightAmbientLightHeightStart > 0 &&
(TheMapData->m_terrainHeightAmbientLightHeight1 >= 0 || TheMapData->m_terrainHeightAmbientLightHeight2 >= 0) &&
vb->z <= TheMapData->m_terrainHeightAmbientLightHeightStart
) {
Real col1R, col1G, col1B, col2R, col2G, col2B;
//Real factor1 = 0.0;
Expand All @@ -618,41 +619,41 @@ void BaseHeightMapRenderObjClass::doTheLight(VERTEX_FORMAT *vb, Vector3*light, V
Real colB;

// case 1: only one color
if (TheGlobalData->m_terrainHeightAmbientLightHeight1 <= 0)
if (TheMapData->m_terrainHeightAmbientLightHeight1 <= 0)
{
col1R = TheGlobalData->m_terrainHeightAmbientLightColor2.red;
col1G = TheGlobalData->m_terrainHeightAmbientLightColor2.green;
col1B = TheGlobalData->m_terrainHeightAmbientLightColor2.blue;
height1 = TheGlobalData->m_terrainHeightAmbientLightHeight2;
col1R = TheMapData->m_terrainHeightAmbientLightColor2.red;
col1G = TheMapData->m_terrainHeightAmbientLightColor2.green;
col1B = TheMapData->m_terrainHeightAmbientLightColor2.blue;
height1 = TheMapData->m_terrainHeightAmbientLightHeight2;
}
else if (TheGlobalData->m_terrainHeightAmbientLightHeight2 <= 0) {
col1R = TheGlobalData->m_terrainHeightAmbientLightColor1.red;
col1G = TheGlobalData->m_terrainHeightAmbientLightColor1.green;
col1B = TheGlobalData->m_terrainHeightAmbientLightColor1.blue;
height1 = TheGlobalData->m_terrainHeightAmbientLightHeight1;
else if (TheMapData->m_terrainHeightAmbientLightHeight2 <= 0) {
col1R = TheMapData->m_terrainHeightAmbientLightColor1.red;
col1G = TheMapData->m_terrainHeightAmbientLightColor1.green;
col1B = TheMapData->m_terrainHeightAmbientLightColor1.blue;
height1 = TheMapData->m_terrainHeightAmbientLightHeight1;
}
else
{ // case 2: both colors

col1R = TheGlobalData->m_terrainHeightAmbientLightColor1.red;
col1G = TheGlobalData->m_terrainHeightAmbientLightColor1.green;
col1B = TheGlobalData->m_terrainHeightAmbientLightColor1.blue;
col2R = TheGlobalData->m_terrainHeightAmbientLightColor2.red;
col2G = TheGlobalData->m_terrainHeightAmbientLightColor2.green;
col2B = TheGlobalData->m_terrainHeightAmbientLightColor2.blue;
height1 = TheGlobalData->m_terrainHeightAmbientLightHeight1;
height2 = TheGlobalData->m_terrainHeightAmbientLightHeight2;
col1R = TheMapData->m_terrainHeightAmbientLightColor1.red;
col1G = TheMapData->m_terrainHeightAmbientLightColor1.green;
col1B = TheMapData->m_terrainHeightAmbientLightColor1.blue;
col2R = TheMapData->m_terrainHeightAmbientLightColor2.red;
col2G = TheMapData->m_terrainHeightAmbientLightColor2.green;
col2B = TheMapData->m_terrainHeightAmbientLightColor2.blue;
height1 = TheMapData->m_terrainHeightAmbientLightHeight1;
height2 = TheMapData->m_terrainHeightAmbientLightHeight2;
}

bool multiply = !TheGlobalData->m_terrainHeightAmbientLightAdditive;
bool multiply = !TheMapData->m_terrainHeightAmbientLightAdditive;
Real base;
if (multiply)
base = 1.0;
else
base = 0.0;

if (vb->z > height1) {
Real t = WWMath::Clamp(invLerp(TheGlobalData->m_terrainHeightAmbientLightHeightStart, height1, vb->z));
Real t = WWMath::Clamp(invLerp(TheMapData->m_terrainHeightAmbientLightHeightStart, height1, vb->z));
colR = col1R * t + (1.0 - t) * base;
colG = col1G * t + (1.0 - t) * base;
colB = col1B * t + (1.0 - t) * base;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
//-------------------------------------------------------------------------------------------------
W3DDecalDrawModuleData::W3DDecalDrawModuleData()
{
m_renderAboveWater = FALSE; // default: below water (shadow-like)
}

//-------------------------------------------------------------------------------------------------
Expand All @@ -69,6 +70,7 @@ void W3DDecalDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
{ "FadeInTime", INI::parseDurationUnsignedInt, nullptr, offsetof(W3DDecalDrawModuleData, m_fadeInTime) },
{ "SizeX", INI::parseReal, nullptr, offsetof(W3DDecalDrawModuleData, m_decalSizeX) },
{ "SizeY", INI::parseReal, nullptr, offsetof(W3DDecalDrawModuleData, m_decalSizeY) },
{ "RenderAboveWater", INI::parseBool, nullptr, offsetof(W3DDecalDrawModuleData, m_renderAboveWater) },
{ nullptr, nullptr, nullptr, 0 }
};
p.add(dataFieldParse);
Expand Down Expand Up @@ -123,11 +125,31 @@ void W3DDecalDraw::init_shadow()
strlcpy(shadowInfo.m_ShadowName, data->m_textureName.str(), ARRAY_SIZE(shadowInfo.m_ShadowName));
shadowInfo.allowUpdates = FALSE; //shadow image will never update
shadowInfo.allowWorldAlign = TRUE; //shadow image will wrap around world objects
shadowInfo.m_type = data->m_type;
shadowInfo.m_sizeX = data->m_decalSizeX;
shadowInfo.m_sizeY = data->m_decalSizeY;

// W3DDecalDraw is a standalone FX decal, not a real object shadow. Only the decal-use blend types
// are valid here; SHADOW_DECAL (and other shadow/projection/volume types) route into object-shadow
// code paths that assume a shadow-casting object + runtime shadow texture, which crashes for stacked
// FX decals. Coerce anything else to SHADOW_ALPHA_DECAL.
ShadowType decalType;
if (data->m_type == SHADOW_ADDITIVE_DECAL)
decalType = SHADOW_ADDITIVE_DECAL;
else if (data->m_type == SHADOW_ALPHA_DECAL)
decalType = SHADOW_ALPHA_DECAL;
else
{
DEBUG_CRASH(("W3DDecalDraw: Style must be SHADOW_ALPHA_DECAL or SHADOW_ADDITIVE_DECAL (got 0x%x); "
"SHADOW_DECAL and shadow/projection types are not supported for FX decals and can crash. "
"Coercing to SHADOW_ALPHA_DECAL.", (Int)data->m_type));
decalType = SHADOW_ALPHA_DECAL;
}
shadowInfo.m_type = decalType;
// honor the drawable's per-instance scale so FX-nugget scale variance affects decal size
Real scale = getDrawable()->getInstanceScale();
shadowInfo.m_sizeX = data->m_decalSizeX * scale;
shadowInfo.m_sizeY = data->m_decalSizeY * scale;
shadowInfo.m_offsetX = 0.0f; // TODO
shadowInfo.m_offsetY = 0.0f; // TODO
shadowInfo.m_waterRenderMode = data->m_renderAboveWater ? SHADOW_WATER_ABOVE : SHADOW_WATER_BELOW;
//shadowInfo.m_hasDynamicLength = FALSE;

DEBUG_ASSERTCRASH(m_shadow == nullptr, ("m_shadow is not null"));
Expand All @@ -149,8 +171,11 @@ void W3DDecalDraw::init_renderBox(const Matrix3D* transformMtx)
{
const W3DDecalDrawModuleData* data = getW3DDecalDrawModuleData();

// honor the drawable's per-instance scale so FX-nugget scale variance affects decal size
Real scale = getDrawable()->getInstanceScale();

Vector3 center = { 0, 0, 0 };
Vector3 extent = { data->m_decalSizeX, data->m_decalSizeY, 1.0f };
Vector3 extent = { data->m_decalSizeX * scale, data->m_decalSizeY * scale, 1.0f };

m_renderBox = NEW OBBoxRenderObjClass(
OBBoxClass(center, extent)
Expand Down
34 changes: 27 additions & 7 deletions Generals/Code/GameEngine/Include/GameClient/Shadow.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ static const char* const TheShadowNames[] =

#define MAX_SHADOW_LIGHTS 1 //maximum number of shadow casting light sources in scene - support for more than 1 has been dropped from most code.

// Per-decal ordering relative to water (evaluated only by the Zero Hour render path; inert here).
enum ShadowWaterMode
{
SHADOW_WATER_DEFAULT = 0, //follow the global RadiusDecalsAboveWater flag
SHADOW_WATER_ABOVE, //always draw above water
SHADOW_WATER_BELOW //always draw below water (shadow-like)
};

class RenderObjClass; //forward reference
class RenderCost; //forward reference

Expand All @@ -83,6 +91,7 @@ class Shadow
m_sizeY = 0.0f;
m_offsetX = 0.0f;
m_offsetY = 0.0f;
m_waterRenderMode = SHADOW_WATER_DEFAULT;
}

char m_ShadowName[64]; //when set, overrides the default model shadow (used mostly for Decals).
Expand All @@ -93,9 +102,13 @@ class Shadow
Real m_sizeY; //world size of decal projection
Real m_offsetX; //world shift along x axis
Real m_offsetY; //world shift along y axis
Int m_waterRenderMode; //ShadowWaterMode: above/below/default water ordering
};

Shadow(void) : m_diffuse(0xffffffff), m_color(0xffffffff), m_opacity (0x000000ff), m_localAngle(0.0f) {}
Shadow(void) : m_diffuse(0xffffffff), m_color(0xffffffff), m_opacity (0x000000ff), m_localAngle(0.0f), m_waterRenderMode(SHADOW_WATER_DEFAULT) {}

void setWaterRenderMode(Int mode) { m_waterRenderMode = mode; }
Int getWaterRenderMode(void) const { return m_waterRenderMode; }

///<if this is set, then no render will occur, even if enableShadowRender() is enabled. Used by Shroud.
void enableShadowInvisible(Bool isEnabled);
Expand Down Expand Up @@ -143,6 +156,7 @@ class Shadow
Real m_decalSizeX; /// 1/(world space extent of texture in x direction)
Real m_decalSizeY; /// 1/(world space extent of texture in y direction)
Real m_localAngle; /// yaw or rotation around z-axis of shadow image when not bound to robj/drawable.
Int m_waterRenderMode; /// ShadowWaterMode: chooses above/below/default water ordering (Zero Hour only).
};


Expand Down Expand Up @@ -174,9 +188,12 @@ inline void Shadow::setOpacity(Int value)
if (m_type & SHADOW_ADDITIVE_DECAL)
{
Real fvalue=(Real)m_opacity/255.0f;
m_diffuse=REAL_TO_INT(((Real)(m_color & 0xff) * fvalue))
|REAL_TO_INT(((Real)((m_color >> 8) & 0xff) * fvalue))
|REAL_TO_INT(((Real)((m_color >> 16) & 0xff) * fvalue));
// Premultiply each channel by opacity and pack into its correct byte (D3DCOLOR 0xAARRGGBB).
// Additive blend (ONE/ONE) ignores alpha, so fade is done by scaling RGB toward black.
Int r = REAL_TO_INT((Real)((m_color >> 16) & 0xff) * fvalue);
Int g = REAL_TO_INT((Real)((m_color >> 8) & 0xff) * fvalue);
Int b = REAL_TO_INT((Real)( m_color & 0xff) * fvalue);
m_diffuse = (r << 16) | (g << 8) | b;
}
}
}
Expand All @@ -194,9 +211,12 @@ inline void Shadow::setColor(Color value)
if (m_type & SHADOW_ADDITIVE_DECAL)
{
Real fvalue=(Real)m_opacity/255.0f;
m_diffuse=REAL_TO_INT(((Real)(m_color & 0xff) * fvalue))
|REAL_TO_INT(((Real)((m_color >> 8) & 0xff) * fvalue))
|REAL_TO_INT(((Real)((m_color >> 16) & 0xff) * fvalue));
// Premultiply each channel by opacity and pack into its correct byte (D3DCOLOR 0xAARRGGBB).
// Additive blend (ONE/ONE) ignores alpha, so fade is done by scaling RGB toward black.
Int r = REAL_TO_INT((Real)((m_color >> 16) & 0xff) * fvalue);
Int g = REAL_TO_INT((Real)((m_color >> 8) & 0xff) * fvalue);
Int b = REAL_TO_INT((Real)( m_color & 0xff) * fvalue);
m_diffuse = (r << 16) | (g << 8) | b;
}
}
}
Expand Down
9 changes: 1 addition & 8 deletions GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,19 +592,12 @@ class GlobalData : public SubsystemInterface

DeathTypeFlags m_defaultExcludedDeathTypes;
Bool m_heightAboveTerrainIncludesWater;
Bool m_radiusDecalsAboveWater; ///< if true, radius decals (cursors) render over water instead of under it
Bool m_hideScorchmarksAboveGround;
Bool m_weaponScatterOnWaterSurfaceDefault; ///< default for WeaponTemplate ScatterOnWaterSurface when not set per-weapon
Bool m_reverseMoveIgnoreAngleThreshold; ///< if true, a manual REVERSE_MOVE order reverses regardless of heading; if false, only when the goal is behind us
Real m_smartGarrisonRange; ///< radius searched for additional transports by the Smart Garrison command

// Water depth lighting
RGBColor m_terrainHeightAmbientLightColor1;
RGBColor m_terrainHeightAmbientLightColor2;
Real m_terrainHeightAmbientLightHeightStart;
Real m_terrainHeightAmbientLightHeight1;
Real m_terrainHeightAmbientLightHeight2;
Bool m_terrainHeightAmbientLightAdditive;

// the trailing '\' is included!
const AsciiString &getPath_UserData() const { return m_userDataDir; }

Expand Down
9 changes: 9 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/Common/MapData.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@ class MapData : public SubsystemInterface
Real m_HeightmapScale;
Bool m_enableShips;

// Height based terrain ambient light (e.g. water depth lighting). Per-map.
RGBColor m_terrainHeightAmbientLightColor1;
RGBColor m_terrainHeightAmbientLightColor2;
Real m_terrainHeightAmbientLightHeightStart;
Real m_terrainHeightAmbientLightHeight1;
Real m_terrainHeightAmbientLightHeight2;
Bool m_terrainHeightAmbientLightAdditive;

private:
void setDefaults();
static const FieldParse s_MapDataFieldParseTable[];
};

Expand Down
Loading
Loading