Skip to content

Commit

Permalink
Added support to load numbered frame sequences from a directory.
Browse files Browse the repository at this point in the history
The format is:

frame_seq = path, fps, is_lightmap, bloom-intensity, black-to-alpha

Animated DC covers need to have is_lightmap = 0 and black-to-alpha = 1. Also,
there must be a cover texture or the animation won't be activated (because
there's nothing to replace).
  • Loading branch information
Prof-Butts committed Feb 2, 2021
1 parent 71526a4 commit 21eaa1c
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 19 deletions.
6 changes: 5 additions & 1 deletion impl11/ddraw/Direct3DDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4991,7 +4991,9 @@ HRESULT Direct3DDevice::Execute(
ATCIndex = lastTextureSelected->material.LightMapATCIndex;
}
else {
resources->InitPixelShader(resources->_noGlassPS);
// If we're rendering a DC element, we don't want to replace the shader
if (g_PSCBuffer.DynCockpitSlots == 0)
resources->InitPixelShader(resources->_noGlassPS);
ATCIndex = lastTextureSelected->material.TextureATCIndex;
}

Expand All @@ -5001,6 +5003,8 @@ HRESULT Direct3DDevice::Execute(

//int rand_idx = rand() % lastTextureSelected->material.LightMapSequence.size();
int extraTexIdx = atc->Sequence[idx].ExtraTextureIndex;
if (atc->BlackToAlpha)
g_PSCBuffer.special_control = SPECIAL_CONTROL_BLACK_TO_ALPHA;

/*
// DEBUG
Expand Down
116 changes: 113 additions & 3 deletions impl11/ddraw/Materials.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
#include "Materials.h"
#include "utils.h"
#include <string.h>
#include <string>
#include <filesystem>
#include "Vectors.h"
#include "ShadowMapping.h"
#include "DeviceResources.h"

namespace fs = std::filesystem;

bool g_bReloadMaterialsEnabled = false;
Material g_DefaultGlobalMaterial;

Expand Down Expand Up @@ -84,6 +88,16 @@ bool LoadLightColor(char* buf, Vector3* Light)
return true;
}

void ListFilesInDir(char *path)
{
std::string s_path = std::string("Animations\\") + std::string(path);
log_debug("[DBG] Listing files under path: %s", s_path.c_str());
for (const auto & entry : fs::directory_iterator(s_path)) {
// Surely there's a better way to get the filename...
log_debug("[DBG] file: %s", entry.path().filename().string().c_str());
}
}

#define SKIP_WHITESPACES(s) {\
while (*s != 0 && *s == ' ') s++;\
if (*s == 0) return false;\
Expand Down Expand Up @@ -185,6 +199,74 @@ bool LoadTextureSequence(char *buf, std::vector<TexSeqElem> &tex_sequence) {
return true;
}

bool LoadFrameSequence(char *buf, std::vector<TexSeqElem> &tex_sequence, int *is_lightmap, int *black_to_alpha) {
int res = 0;
char *s = NULL, *t = NULL, path[256];
float fps = 30.0f, intensity = 0.0f;
*is_lightmap = 0, *black_to_alpha = 1;

//log_debug("[DBG] [MAT] Reading texture sequence");
s = strchr(buf, '=');
if (s == NULL) return false;

// Skip the equals sign:
s += 1;

// Skip to the next comma
t = s;
while (*t != 0 && *t != ',') t++;
// If we reached the end of the string, that's an error
if (*t == 0) return false;
// End this string on the comma so that we can parse a string
*t = 0;
// Parse the texture name
try {
res = sscanf_s(s, "%s", path, 256);
if (res < 1) log_debug("[DBG] [MAT] Error reading path in '%s'", s);
}
catch (...) {
log_debug("[DBG] [MAT} Could not read path in '%s'", s);
return false;
}

// Skip the comma
s = t; s += 1;
SKIP_WHITESPACES(s);

// Parse the remaining fields: fps, lightmap, intensity, black-to-alpha
try {
res = sscanf_s(s, "%f, %d, %f, %d", &fps, is_lightmap, &intensity, black_to_alpha);
if (res < 4) {
log_debug("[DBG] [MAT] Error (using defaults), expected at least 4 elements in %s", s);
}
log_debug("[DBG] [MAT] frame_seq read: %f, %d, %f, %d", fps, *is_lightmap, intensity, *black_to_alpha);
}
catch (...) {
log_debug("[DBG] [MAT] Could not read (fps, lightmap, intensity, black-to-alpha) from %s", s);
return false;
}

// We just finished reading the path where a frame sequence is stored
// Now we need to load all the frames in that path into a tex_seq_elem
TexSeqElem tex_seq_elem;
std::string s_path = std::string("Animations\\") + std::string(path);
//log_debug("[DBG] Listing files under path: %s", s_path.c_str());
for (const auto & entry : fs::directory_iterator(s_path)) {
// Surely there's a better way to get the filename...
std::string filename = std::string(path) + "\\" + entry.path().filename().string();
//log_debug("[DBG] file: %s", filename.c_str());

strcpy_s(tex_seq_elem.texname, MAX_TEX_SEQ_NAME, filename.c_str());
tex_seq_elem.seconds = 1.0f / fps;
tex_seq_elem.intensity = intensity;
// The texture itself will be loaded later. So the reference index is initialized to -1 here:
tex_seq_elem.ExtraTextureIndex = -1;
tex_sequence.push_back(tex_seq_elem);
}

return true;
}

void ReadMaterialLine(char* buf, Material* curMaterial) {
char param[256], svalue[512];
float fValue = 0.0f;
Expand Down Expand Up @@ -319,10 +401,10 @@ void ReadMaterialLine(char* buf, Material* curMaterial) {
_stricmp(param, "anim_seq") == 0 ||
_stricmp(param, "anim_rand") == 0) {
// TOOD: Add support for multiline sequences
// TODO: Fix the alpha issues with side-loaded animations (remove the artifacts around the edges)
AnimatedTexControl atc;
atc.IsRandom = (_stricmp(param, "lightmap_rand") == 0) || (_stricmp(param, "anim_rand") == 0);
atc.IsLightMap = (_stricmp(param, "lightmap_rand") == 0) || (_stricmp(param, "lightmap_seq") == 0);
bool IsLightMap = (_stricmp(param, "lightmap_rand") == 0) || (_stricmp(param, "lightmap_seq") == 0);
atc.BlackToAlpha = false;
// Clear the current Sequence and release the associated textures in the DeviceResources...
// TODO: Either release the ExtraTextures pointed at by LightMapSequence, or garbage-collect them
// later...
Expand All @@ -337,7 +419,7 @@ void ReadMaterialLine(char* buf, Material* curMaterial) {
atc.TimeLeft = atc.Sequence[0].seconds;
// Add a reference to this material on the list of animated materials
g_AnimatedMaterials.push_back(atc);
if (atc.IsLightMap)
if (IsLightMap)
curMaterial->LightMapATCIndex = g_AnimatedMaterials.size() - 1;
else
curMaterial->TextureATCIndex = g_AnimatedMaterials.size() - 1;
Expand All @@ -354,6 +436,34 @@ void ReadMaterialLine(char* buf, Material* curMaterial) {
log_debug("[DBG] [MAT] ERROR: No Animation Data Loaded for [%s]", buf);
}
}
else if (_stricmp(param, "frame_seq") == 0) {
AnimatedTexControl atc;
int is_lightmap, black_to_alpha;
atc.IsRandom = 0;
// Clear the current Sequence and release the associated textures in the DeviceResources...
// TODO: Either release the ExtraTextures pointed at by LightMapSequence, or garbage-collect them
// later...
atc.Sequence.clear();
log_debug("[DBG] [MAT] Loading Frame Sequence data for [%s]", buf);
if (!LoadFrameSequence(buf, atc.Sequence, &is_lightmap, &black_to_alpha))
log_debug("[DBG] [MAT] Error loading animated LightMap/Texture data for [%s], syntax error?", buf);
if (atc.Sequence.size() > 0) {
log_debug("[DBG] [MAT] Sequence.size() = %d for Texture [%s]", atc.Sequence.size(), buf);
// Initialize the timer for this animation
atc.AnimIdx = 0;
atc.TimeLeft = atc.Sequence[0].seconds;
atc.BlackToAlpha = (bool)black_to_alpha;
// Add a reference to this material on the list of animated materials
g_AnimatedMaterials.push_back(atc);
if (is_lightmap)
curMaterial->LightMapATCIndex = g_AnimatedMaterials.size() - 1;
else
curMaterial->TextureATCIndex = g_AnimatedMaterials.size() - 1;
}
else {
log_debug("[DBG] [MAT] ERROR: No Animation Data Loaded for [%s]", buf);
}
}
/*
else if (_stricmp(param, "LavaNormalMult") == 0) {
LoadLightColor(buf, &(curMaterial->LavaNormalMult));
Expand Down
5 changes: 2 additions & 3 deletions impl11/ddraw/Materials.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@ typedef struct AnimatedTexControlStruct {
std::vector<TexSeqElemStruct> Sequence;
int AnimIdx; // This is the current index in the Sequence, it can increase monotonically, or it can be random.
float TimeLeft; // Time left for the current index in the sequence.
bool IsRandom;
bool IsLightMap; // True if the current ATC is a LightMap animation
bool IsRandom, BlackToAlpha;

AnimatedTexControlStruct() {
Sequence.clear();
AnimIdx = 0;
TimeLeft = 1.0f;
IsRandom = false;
IsLightMap = true;
BlackToAlpha = false;
}

// Updates the timer/index on the current animated material. Only call this function
Expand Down
9 changes: 7 additions & 2 deletions impl11/shaders/PixelShaderAnimLightMap.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ PixelShaderOutput main(PixelShaderInput input)
PixelShaderOutput output;
float4 texelColor = texture0.Sample(sampler0, input.tex);
float alpha = texelColor.w;
float3 color = texelColor.rgb;
float3 HSV = RGBtoHSV(color);
if (special_control == SPECIAL_CONTROL_BLACK_TO_ALPHA)
alpha = HSV.z;

float3 diffuse = lerp(input.color.xyz, 1.0, fDisableDiffuse);
float3 P = input.pos3D.xyz;
float SSAOAlpha = saturate(min(alpha - fSSAOAlphaOfs, fPosNormalAlpha));
Expand All @@ -46,6 +51,8 @@ PixelShaderOutput main(PixelShaderInput input)
output.pos3D = float4(P, SSAOAlpha);
output.ssMask = 0;



// hook_normals code:
float3 N = normalize(input.normal.xyz * 2.0 - 1.0);
N.y = -N.y; // Invert the Y axis, originally Y+ is down
Expand All @@ -69,9 +76,7 @@ PixelShaderOutput main(PixelShaderInput input)
//output.pos3D = 0;
//output.normal = 0;
//output.diffuse = 0;
float3 color = texelColor.rgb;
// This is a light texture, process the bloom mask accordingly
float3 HSV = RGBtoHSV(color);
float val = HSV.z;
// Enhance = true
if (bIsLightTexture > 1) {
Expand Down
16 changes: 11 additions & 5 deletions impl11/shaders/PixelShaderDC.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,12 @@ uint getBGColor(uint i) {
PixelShaderOutput main(PixelShaderInput input)
{
PixelShaderOutput output;
float4 coverColor = texture0.Sample(sampler0, input.tex); // coverColor is the cover texture
const float coverAlpha = coverColor.w; // alpha of the cover texture
float4 coverColor = texture0.Sample(sampler0, input.tex); // coverColor/texelColor is the cover texture
float coverAlpha = coverColor.w; // alpha of the cover texture
float3 HSV = RGBtoHSV(coverColor.rgb);
if (special_control == SPECIAL_CONTROL_BLACK_TO_ALPHA)
coverAlpha = HSV.z;

// DEBUG: Make the cover texture transparent to show the DC contents clearly
//const float coverAlpha = 0.0;
// DEBUG
Expand Down Expand Up @@ -176,13 +180,13 @@ PixelShaderOutput main(PixelShaderInput input)
// on areas with a high lightness value

// coverColor is the cover_texture right now
float3 HSV = RGBtoHSV(coverColor.xyz);
//float3 HSV = RGBtoHSV(coverColor.xyz);
float brightness = ct_brightness;
// The cover texture is bright enough, go shadeless and make it brighter
if (HSV.z * coverAlpha >= 0.8) {
diffuse = 1;
// Increase the brightness:
HSV = RGBtoHSV(coverColor.xyz);
//HSV = RGBtoHSV(coverColor.xyz); // Redundant
HSV.z *= 1.2;
coverColor.xyz = HSVtoRGB(HSV);
output.bloom = float4(fBloomStrength * coverColor.xyz, 1);
Expand Down Expand Up @@ -216,7 +220,9 @@ PixelShaderOutput main(PixelShaderInput input)
output.ssMask = float4(0.0, 1.0, 0.0, 1.0); // No NM, White Spec Val, unused
}

// At this point, coverColor is the blended cover texture (if it exists) and the HUD contents
if (dc_bloom) {
// coverColor may have changed, we need to convert to HSV again
float3 HSV = RGBtoHSV(coverColor.xyz);
if (HSV.z >= 0.8) {
diffuse = 1.0;
Expand All @@ -227,7 +233,7 @@ PixelShaderOutput main(PixelShaderInput input)
}
}

output.color = float4(diffuse * coverColor.xyz, coverColor.w);
output.color = float4(diffuse * coverColor.xyz, coverAlpha);
if (bInHyperspace) output.color.a = 1.0;

// Text DC elements can be made to float inside the cockpit. In that case, we might want
Expand Down
9 changes: 7 additions & 2 deletions impl11/shaders/PixelShaderEmptyDC.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
#include "PixelShaderTextureCommon.h"
#include "DC_common.h"

// Cover texture
Texture2D texture0 : register(t0);
SamplerState sampler0 : register(s0);

// HUD offscreen buffer
Texture2D texture1 : register(t1);
SamplerState sampler1 : register(s1);

Expand Down Expand Up @@ -43,6 +45,9 @@ PixelShaderOutput main(PixelShaderInput input)
PixelShaderOutput output;
float4 texelColor = texture0.Sample(sampler0, input.tex);
float alpha = texelColor.w;
float3 HSV = RGBtoHSV(texelColor.rgb); // texelColor is the cover texture
if (special_control == SPECIAL_CONTROL_BLACK_TO_ALPHA)
alpha = HSV.z;
float3 diffuse = lerp(input.color.xyz, 1.0, fDisableDiffuse);
// Zero-out the bloom mask.
output.bloom = float4(0, 0, 0, 0);
Expand Down Expand Up @@ -70,14 +75,14 @@ PixelShaderOutput main(PixelShaderInput input)
// We assume the caller will set this pixel shader iff DynCockpitSlots == 0 && bUseCoverTexture > 0

// texelColor is the cover_texture right now
float3 HSV = RGBtoHSV(texelColor.xyz);
//float3 HSV = RGBtoHSV(texelColor.xyz);
float4 hud_texelColor = float4(0, 0, 0, 1);
float brightness = ct_brightness;
if (HSV.z * alpha >= 0.8) {
// The cover texture is bright enough, go shadeless and make it brighter
diffuse = float3(1, 1, 1);
// Increase the brightness:
HSV = RGBtoHSV(texelColor.xyz);
//HSV = RGBtoHSV(texelColor.xyz); // Redundant line
HSV.z *= 1.2;
texelColor.xyz = HSVtoRGB(HSV);
output.bloom = float4(fBloomStrength * texelColor.xyz, 1);
Expand Down
5 changes: 4 additions & 1 deletion impl11/shaders/PixelShaderNoGlass.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ PixelShaderOutput main(PixelShaderInput input)
PixelShaderOutput output;
float4 texelColor = texture0.Sample(sampler0, input.tex);
float alpha = texelColor.a;
float3 HSV = RGBtoHSV(texelColor.rgb);
if (special_control == SPECIAL_CONTROL_BLACK_TO_ALPHA)
alpha = HSV.z;

float3 diffuse = lerp(input.color.xyz, 1.0, fDisableDiffuse);
float3 P = input.pos3D.xyz;
Expand All @@ -52,6 +55,7 @@ PixelShaderOutput main(PixelShaderInput input)
output.color = texelColor;
output.pos3D = float4(P, SSAOAlpha);
output.ssMask = 0;


// hook_normals code:
float3 N = normalize(input.normal.xyz * 2.0 - 1.0);
Expand All @@ -67,7 +71,6 @@ PixelShaderOutput main(PixelShaderInput input)
output.ssMask = float4(fNMIntensity, fSpecVal, fAmbient, alpha);

// bloom
float3 HSV = RGBtoHSV(texelColor.rgb);
if (HSV.z >= 0.8) {
float bloom_alpha = saturate(fBloomStrength);
diffuse = 1.0;
Expand Down
4 changes: 2 additions & 2 deletions impl11/shaders/PixelShaderTextureCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
cbuffer ConstantBuffer : register(b0)
{
float brightness; // Used to dim some elements to prevent the Bloom effect -- mostly for ReShade compatibility
uint DynCockpitSlots; // (Unused here) How many DC slots will be used.
uint bUseCoverTexture; // (Unused here) When set, use the first texture as cover texture for the dynamic cockpit
uint DynCockpitSlots; // (DC) How many DC slots will be used.
uint bUseCoverTexture; // (DC) When set, use the first texture as cover texture for the dynamic cockpit
uint bInHyperspace; // 1 if we're rendering while in hyperspace
// 16 bytes

Expand Down
1 change: 1 addition & 0 deletions impl11/shaders/shader_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ LaserPointerCBuffer : register(b8)
#define SPECIAL_CONTROL_HIGHLIGHT 5 // Used for debugging purposes (to highlight specific elements)
#define SPECIAL_CONTROL_NO_COLOR_ALPHA 6 // When this is set, the alpha value for the color output is forced to 0. Used in AlphaToBloom.hlsl
#define SPECIAL_CONTROL_EXPLOSION 7
#define SPECIAL_CONTROL_BLACK_TO_ALPHA 8 // Used when rendering animated textures so that black becomes transparent

// Register slot for the metric reconstruction constant buffer
#define METRIC_REC_CB_SLOT 6
Expand Down

0 comments on commit 21eaa1c

Please sign in to comment.