Skip to content

Commit

Permalink
Alternate Explosion Animations.
Browse files Browse the repository at this point in the history
Up to 5 alternate explosion animations can now be loaded using the following
settings:

	alt_frames_1 = ResData\ExplosionsAlt.dat-0
	alt_frames_2 = ResData\ExplosionsAlt.dat-1
	alt_frames_3 = ResData\ExplosionsAlt.dat-2
	alt_frames_4 = ResData\ExplosionsAlt.dat-3
	ds2_frames = ResData\ExplosionsAlt.dat-4

These settings have to be added to each explosion material file. During the DS2
mission, if ds2_frames is specified, then only those frames will be displayed.
However, DS2 frames are also displayed in regular missions too.
  • Loading branch information
Prof-Butts committed Oct 12, 2021
1 parent 84d5a22 commit a364df0
Show file tree
Hide file tree
Showing 9 changed files with 384 additions and 84 deletions.
147 changes: 92 additions & 55 deletions impl11/ddraw/Direct3DDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ Mission Index:
Skirmish: 0
PPG: 6 (looks like this is complicated in TFTC).
Death Star: 52
The Death Star mission index isn't used anywhere. Lights are automatically turned on when there are no global
lights. The only mission in XWA where this happens is mission 52.
Lights are automatically turned on when there are no global lights. The only mission in XWA where this happens is mission 52.
*/

/*
Expand Down Expand Up @@ -474,7 +473,7 @@ bool g_bResetDC = false;
// DS2 Effects
int g_iReactorExplosionCount = 0;
// Replace regular explosions with procedural explosions during the DS2 mission to improve visibility.
bool g_bDS2ForceProceduralExplosions = true;
bool g_bDS2ForceProceduralExplosions = false;

/*********************************************************/
// High Resolution Timers
Expand Down Expand Up @@ -3114,8 +3113,9 @@ HRESULT Direct3DDevice::Execute(
//bIsSkyDome = lastTextureSelected->is_SkydomeLight;
bIsDS2CoreExplosion = lastTextureSelected->is_DS2_Reactor_Explosion;
bIsElectricity = lastTextureSelected->is_Electricity;
bIsExplosion = lastTextureSelected->is_Explosion;
bHasMaterial = lastTextureSelected->bHasMaterial;
bIsExplosion = lastTextureSelected->is_Explosion;
if (bIsExplosion) g_bExplosionsDisplayedOnCurrentFrame = true;
}
g_bPrevIsSkyBox = g_bIsSkyBox;
// bIsSkyBox is true if we're about to render the SkyBox
Expand Down Expand Up @@ -4516,60 +4516,97 @@ HRESULT Direct3DDevice::Execute(
}

// Render the procedural explosions
if (bIsExplosion && bHasMaterial &&
(lastTextureSelected->material.ExplosionBlendMode > 0 ||
// The newest explosions by MechDonald are bigger and longer. Unfortunately, during the DS2 mission, this can
// block a lot of visibility in the tunnel. So if we're in the DS2 mission, let's use procedural explosions
// instead.
(g_bDS2ForceProceduralExplosions && *missionIndexLoaded == DEATH_STAR_MISSION_INDEX)))
if (bIsExplosion && bHasMaterial)
{
static float iTime = 0.0f;
//iTime += 0.05f;
iTime += lastTextureSelected->material.ExplosionSpeed;

bModifiedShaders = true;
bModifiedPixelShader = true;
bModifiedSamplerState = true;
resources->InitPixelShader(resources->_explosionPS);
// Set the noise texture and sampler state with wrap/repeat enabled.
context->PSSetShaderResources(1, 1, resources->_grayNoiseSRV.GetAddressOf());
// bModifiedSamplerState restores this sampler state at the end of this instruction.
context->PSSetSamplers(1, 1, resources->_repeatSamplerState.GetAddressOf());
if (lastTextureSelected->material.ExplosionBlendMode > 0 ||
// The newest explosions by MechDonald are bigger and longer. Unfortunately, during the DS2 mission, this can
// block a lot of visibility in the tunnel. So if we're in the DS2 mission, let's use procedural explosions
// instead.
(g_bDS2ForceProceduralExplosions && *missionIndexLoaded == DEATH_STAR_MISSION_INDEX))
{
static float iTime = 0.0f;
iTime += lastTextureSelected->material.ExplosionSpeed;

int GroupId = 0, ImageId = 0;
if (!lastTextureSelected->material.DATGroupImageIdParsed) {
// TODO: Maybe I can extract the group Id and image Id from the DAT's name during tagging and
// get rid of the DATGroupImageIdParsed field in the material property.
GetGroupIdImageIdFromDATName(lastTextureSelected->_surface->_name, &GroupId, &ImageId);
lastTextureSelected->material.GroupId = GroupId;
lastTextureSelected->material.ImageId = ImageId;
lastTextureSelected->material.DATGroupImageIdParsed = true;
bModifiedShaders = true;
bModifiedPixelShader = true;
bModifiedSamplerState = true;
resources->InitPixelShader(resources->_explosionPS);
// Set the noise texture and sampler state with wrap/repeat enabled.
context->PSSetShaderResources(1, 1, resources->_grayNoiseSRV.GetAddressOf());
// bModifiedSamplerState restores this sampler state at the end of this instruction.
context->PSSetSamplers(1, 1, resources->_repeatSamplerState.GetAddressOf());

int GroupId = 0, ImageId = 0;
if (!lastTextureSelected->material.DATGroupImageIdParsed) {
// TODO: Maybe I can extract the group Id and image Id from the DAT's name during tagging and
// get rid of the DATGroupImageIdParsed field in the material property.
GetGroupIdImageIdFromDATName(lastTextureSelected->_surface->_name, &GroupId, &ImageId);
lastTextureSelected->material.GroupId = GroupId;
lastTextureSelected->material.ImageId = ImageId;
lastTextureSelected->material.DATGroupImageIdParsed = true;
}
else {
GroupId = lastTextureSelected->material.GroupId;
ImageId = lastTextureSelected->material.ImageId;
}
// TODO: The following time will increase in steps, but I'm not sure it's possible to do a smooth
// increase because there's no way to uniquely identify two different explosions on the same frame.
// The same GroupId can appear mutiple times on the screen belonging to different crafts and they
// may even be at different stages of the animation.
float ExplosionTime = min(1.0f, (float)ImageId / (float)lastTextureSelected->material.TotalFrames);
//log_debug("[DBG] Explosion Id: %d, Frame: %d, TotalFrames: %d, Time: %0.3f",
// GroupId, ImageId, lastTextureSelected->material.TotalFrames, ExplosionTime);
//log_debug("[DBG] Explosion Id: %d", GroupId);

g_ShadertoyBuffer.iTime = iTime;
// ExplosionBlendMode:
// 0: Original texture,
// 1: Blend with procedural explosion,
// 2: Use procedural explosions only
// AlphaBlendEnabled: true blend with original texture, false: replace original texture
g_ShadertoyBuffer.bDisneyStyle = lastTextureSelected->material.ExplosionBlendMode;
g_ShadertoyBuffer.tunnel_speed = lerp(3.0f, -1.0f, ExplosionTime); // ExplosionTime: 3..-1 The animation is performed by iTime in VolumetricExplosion()
// ExplosionScale: 4.0 == small, 2.0 == normal, 1.0 == big.
// The value from ExplosionScale is translated from user-facing units to shader units in the ReadMaterialLine() function
g_ShadertoyBuffer.twirl = lastTextureSelected->material.ExplosionScale;
// Set the constant buffer
resources->InitPSConstantBufferHyperspace(resources->_hyperspaceConstantBuffer.GetAddressOf(), &g_ShadertoyBuffer);
}
else {
GroupId = lastTextureSelected->material.GroupId;
ImageId = lastTextureSelected->material.ImageId;
else { // ExplosionBlendMode == 0
int AltExplosionSelectorIdx = lastTextureSelected->DATGroupId - 2000; // 2000 is the first explosion GroupId
if (AltExplosionSelectorIdx >= 0 && AltExplosionSelectorIdx < MAX_XWA_EXPLOSIONS) {
int RandomAltIdx = g_AltExplosionSelector[AltExplosionSelectorIdx];
// Debug override: force a specific index so that we can see each alternate explosion set if we want to.
if (g_iForceAltExplosion > -1 && g_iForceAltExplosion < MAX_ALT_EXPLOSIONS)
RandomAltIdx = g_iForceAltExplosion;
if (RandomAltIdx > -1) {
Material *material = &lastTextureSelected->material;
// If we're in the DS2 mission, we need to load the alternate explosion designed for it.
// Otherwise we select one of the alternatives at random.
int AltExpIndex = (*missionIndexLoaded == DEATH_STAR_MISSION_INDEX) ? DS2_ALT_EXPLOSION_IDX : RandomAltIdx;
int ATCIndex = material->AltExplosionIdx[AltExpIndex];
if (ATCIndex > -1) {
AnimatedTexControl *atc = &(g_AnimatedMaterials[ATCIndex]);
int frame = lastTextureSelected->DATImageId;
if (-1 < frame && frame < (int)atc->Sequence.size()) {
int extraTexIdx = atc->Sequence[frame].ExtraTextureIndex;
if (extraTexIdx > -1)
resources->InitPSShaderResourceView(resources->_extraTextures[extraTexIdx]);
else // Skip this frame
goto out;
}
else
// The alternate explosion has less frame than the original. Skip this frame.
// If we *don't* skip this frame, then the original animation will play after the alternate
// animation. That usually looks weird.
goto out;
}
// else: ATCIndex is -1: there's no alternate explosion, use the original version
}
// else: RandomAltIdx is -1, use the original version
}
// else: Unknown Explosion group!
}
// TODO: The following time will increase in steps, but I'm not sure it's possible to do a smooth
// increase because there's no way to uniquely identify two different explosions on the same frame.
// The same GroupId can appear mutiple times on the screen belonging to different crafts and they
// may even be at different stages of the animation.
float ExplosionTime = min(1.0f, (float)ImageId / (float)lastTextureSelected->material.TotalFrames);
//log_debug("[DBG] Explosion Id: %d, Frame: %d, TotalFrames: %d, Time: %0.3f",
// GroupId, ImageId, lastTextureSelected->material.TotalFrames, ExplosionTime);
//log_debug("[DBG] Explosion Id: %d", GroupId);

g_ShadertoyBuffer.iTime = iTime;
// ExplosionBlendMode:
// 0: Original texture,
// 1: Blend with procedural explosion,
// 2: Use procedural explosions only
g_ShadertoyBuffer.bDisneyStyle = lastTextureSelected->material.ExplosionBlendMode; // AlphaBlendEnabled: true blend with original texture, false: replace original texture
g_ShadertoyBuffer.tunnel_speed = lerp(3.0f, -1.0f, ExplosionTime); // ExplosionTime: 3..-1 The animation is performed by iTime in VolumetricExplosion()
// ExplosionScale: 4.0 == small, 2.0 == normal, 1.0 == big.
// The value from ExplosionScale is translated from user-facing units to shader units in the ReadMaterialLine() function
g_ShadertoyBuffer.twirl = lastTextureSelected->material.ExplosionScale;
// Set the constant buffer
resources->InitPSConstantBufferHyperspace(resources->_hyperspaceConstantBuffer.GetAddressOf(), &g_ShadertoyBuffer);
}

// Capture the centroid of the current sun texture and store it.
Expand Down Expand Up @@ -6455,8 +6492,8 @@ HRESULT Direct3DDevice::BeginScene()
float hull = 100.0f * (1.0f - (float)craftInstance->HullDamageReceived / (float)craftInstance->HullStrength);
hull = max(0.0f, hull);
if (g_bDumpSSAOBuffers) log_debug("[DBG] Hull health: %0.3f", hull);
g_GameEvent.HullEvent = EVT_NONE;
// Update the Hull event
g_GameEvent.HullEvent = EVT_NONE;
if (hull > 75.0f)
g_GameEvent.HullEvent = EVT_NONE;
else if (50.0f < hull && hull <= 75.0f)
Expand Down
47 changes: 41 additions & 6 deletions impl11/ddraw/Direct3DTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ Direct3DTexture::Direct3DTexture(DeviceResources* deviceResources, TextureSurfac
this->_refCount = 1;
this->_deviceResources = deviceResources;
this->_surface = surface;
this->DATImageId = -1;
this->DATGroupId = -1;
this->is_Tagged = false;
this->TagCount = 3;
this->is_Reticle = false;
Expand Down Expand Up @@ -723,6 +725,8 @@ void Direct3DTexture::TagTexture() {
this->is_DAT = true;
// Check if this DAT image is a custom reticle
if (GetGroupIdImageIdFromDATName(surface->_name, &GroupId, &ImageId)) {
this->DATGroupId = GroupId;
this->DATImageId = ImageId;
if (GroupId == 12000 && ImageId > 5000) {
this->is_Reticle = true; // Custom Reticle
//log_debug("[DBG] CUSTOM RETICLE: %s", surface->_name);
Expand Down Expand Up @@ -1172,10 +1176,10 @@ void Direct3DTexture::TagTexture() {
greeble_data->greebleBlendMode[i] == GBM_UV_DISP_AND_NORMAL_MAP) {
greeble_data->UVDispMapResolution.x = Width;
greeble_data->UVDispMapResolution.y = Height;
log_debug("[DBG] [GRB] UVDispMapResolution: %0.0f, %0.0f",
greeble_data->UVDispMapResolution.x, greeble_data->UVDispMapResolution.y);
//log_debug("[DBG] [GRB] UVDispMapResolution: %0.0f, %0.0f",
// greeble_data->UVDispMapResolution.x, greeble_data->UVDispMapResolution.y);
}
log_debug("[DBG] [GRB] Loaded Greeble Texture at index: %d", greeble_data->GreebleTexIndex[i]);
//log_debug("[DBG] [GRB] Loaded Greeble Texture at index: %d", greeble_data->GreebleTexIndex[i]);
}
}
// Load Lightmap Greebles
Expand All @@ -1190,16 +1194,45 @@ void Direct3DTexture::TagTexture() {
// I may need to add support for more maps later.
greeble_data->UVDispMapResolution.x = Width;
greeble_data->UVDispMapResolution.y = Height;
log_debug("[DBG] [GRB] UVDispMapResolution (Lightmap): %0.0f, %0.0f",
greeble_data->UVDispMapResolution.x, greeble_data->UVDispMapResolution.y);
//log_debug("[DBG] [GRB] UVDispMapResolution (Lightmap): %0.0f, %0.0f",
// greeble_data->UVDispMapResolution.x, greeble_data->UVDispMapResolution.y);
}
log_debug("[DBG] [GRB] Loaded Lightmap Greeble Texture at index: %d", greeble_data->GreebleLightMapIndex[i]);
//log_debug("[DBG] [GRB] Loaded Lightmap Greeble Texture at index: %d", greeble_data->GreebleLightMapIndex[i]);
}
}
}

}

// Load the alternate explosions here...
for (int AltExpIdx = 0; AltExpIdx < MAX_ALT_EXPLOSIONS; AltExpIdx++) {
int ATCIndex = this->material.AltExplosionIdx[AltExpIdx];
if (ATCIndex != -1) {
AnimatedTexControl *atc = &(g_AnimatedMaterials[ATCIndex]);
// Make sure we only load this sequence once
if (!atc->SequenceLoaded) {
log_debug("[DBG] Loading AltExplosionIdx[%d]: %d", AltExpIdx, ATCIndex);
for (uint32_t j = 0; j < atc->Sequence.size(); j++) {
TexSeqElem tex_seq_elem = atc->Sequence[j];
ID3D11ShaderResourceView *texSRV = nullptr;
if (atc->Sequence[j].ExtraTextureIndex == -1) {
HRESULT res = LoadDATImage(tex_seq_elem.texname, tex_seq_elem.GroupId,
/* ImageId */ j, &texSRV);
if (FAILED(res)) {
log_debug("[DBG] [MAT] ***** Could not load DAT texture [%s-%d-%d]: 0x%x",
tex_seq_elem.texname, tex_seq_elem.GroupId, j, res);
}
else {
resources->_extraTextures.push_back(texSRV);
atc->Sequence[j].ExtraTextureIndex = resources->_extraTextures.size() - 1;
}
}
}
atc->SequenceLoaded = true; // Make extra-sure we only load this animation once
}
}
}

// DEBUG
/*if (bIsDat) {
log_debug("[DBG] [MAT] [%s] --> Material: %0.3f, %0.3f, %0.3f",
Expand Down Expand Up @@ -1258,6 +1291,8 @@ HRESULT Direct3DTexture::Load(
this->is_EngineGlow = d3dTexture->is_EngineGlow;
this->is_Electricity = d3dTexture->is_Electricity;
this->is_Explosion = d3dTexture->is_Explosion;
this->DATImageId = d3dTexture->DATImageId;
this->DATGroupId = d3dTexture->DATGroupId;
this->is_Smoke = d3dTexture->is_Smoke;
this->is_CockpitTex = d3dTexture->is_CockpitTex;
this->is_GunnerTex = d3dTexture->is_GunnerTex;
Expand Down
2 changes: 2 additions & 0 deletions impl11/ddraw/Direct3DTexture.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class Direct3DTexture : public IDirect3DTexture
// have to be tagged at least two times to allow them to be recognized as custom reticles.
// The field below helps us tag these resources multiple times to recognize custom reticles.
uint8_t TagCount;
// These indices store the GroupId and ImageId of this texture (if it's a DAT image)
int DATGroupId, DATImageId;
// Used to tell whether the current texture is part of the aiming HUD and should not be scalled.
// This flag is set during resource Load
bool is_Reticle;
Expand Down
Loading

0 comments on commit a364df0

Please sign in to comment.