Merge branch 'develop' into realtime_shader_reloading

This commit is contained in:
Lwmte 2024-12-25 13:47:26 +01:00
commit 529ffb50dd
10 changed files with 170 additions and 48 deletions

View file

@ -3,7 +3,15 @@
The dates are in European standard format where date is presented as **YYYY-MM-DD**.
TombEngine releases are located in this repository (alongside with Tomb Editor): https://github.com/TombEngine/TombEditorReleases
## Version 1.7 - xxxx-xx-xx
## Version 1.8 - xxxx-xx-xx
### Bug fixes
### New Features
### Lua API changes
## [Version 1.7](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.7.3) - 2024-12-25
### Bug fixes
* Significantly improved renderer performance.
@ -57,7 +65,6 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
### Lua API changes
* Added Flow.Statistics class, Flow.GetStatistics() and Flow.SetStatistics() functions.
* Added Flow.GetFreezeMode() and Flow.SetFreezeMode() functions.
* Added Flow.GetNextLevel() function to get script entry for incoming level, if it's about to start.
* Added Effects.EmitSpotLight() function for directional spotlights.
* Added optional cast shadow and name parameters for Effects.EmitLight() function.
* Added Effects.GetWind() function to get current wind speed vector.
@ -68,7 +75,6 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
* Added extra argument for Sound.SetAmbientTrack() function to specify if new ambient track should play from the beginning.
* Added new View.CameraType enum entries and return it by View.GetCameraType(), when flyby camera or binoculars/lasersight is active.
* Added new primitive Time class, which allows to manipulate and format game time without precision loss.
* Allow to use TR4-like load cameras by playing fixed camera from OnEnd() event and removing loadScreenFile field from level's gameflow entry.
* Renamed Flow.WeaponType enumeration to Objects.WeaponType, and removed similar Objects.LaraWeaponType enumeration for consistency.
* Renamed Objects.PlayerAmmoType to Objects.AmmoType for consistency.
* Fixed Strings.DisplayString class not supporting some Unicode characters and empty lines in multiline strings.

View file

@ -167,10 +167,6 @@ scripts too.</p>
<td class="summary">Returns the level that the game control is running in that moment.</td>
</tr>
<tr>
<td class="name" ><a href="#GetNextLevel">GetNextLevel()</a></td>
<td class="summary">Returns the level that is about to load.</td>
</tr>
<tr>
<td class="name" ><a href="#EndLevel">EndLevel([index][, startPos])</a></td>
<td class="summary">Finishes the current level, with optional level index and start position index provided.</td>
</tr>
@ -559,27 +555,6 @@ have an ID of 0, the second an ID of 1, and so on.
</dd>
<dt>
<a name = "GetNextLevel"></a>
<strong>GetNextLevel()</strong>
</dt>
<dd>
Returns the level that is about to load. If no new level is about to load, returns current level.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../2 classes/Flow.Level.html#">Level</a></span>
incoming new level or current level, if no new level is loading
</ol>
</dd>
<dt>
<a name = "EndLevel"></a>

View file

@ -66,6 +66,7 @@
#include "Renderer/Structures/RendererRoomAmbientMap.h"
#include "Renderer/Structures/RendererObject.h"
#include "Renderer/Structures/RendererStar.h"
#include "Structures/RendererShader.h"
enum GAME_OBJECT_ID : short;
enum class SphereSpaceType;
@ -332,6 +333,9 @@ namespace TEN::Renderer
RenderTarget2D _SSAOBlurredRenderTarget;
std::vector<Vector4> _SSAOKernel;
RendererShader _sSSAO;
RendererShader _sSSAOBlur;
// New ambient light techinque
RenderTarget2D _roomAmbientMapFront;
@ -358,6 +362,9 @@ namespace TEN::Renderer
ShaderManager _shaderManager;
RendererShader CompileOrLoadShader(const std::string& fileName, const std::string& funcName, ShaderType type, const D3D_SHADER_MACRO* defines = nullptr);
void BindShader(const RendererShader& shader);
void ApplySMAA(RenderTarget2D* renderTarget, RenderView& view);
void ApplyFXAA(RenderTarget2D* renderTarget, RenderView& view);
void BindTexture(TextureRegister registerType, TextureBase* texture, SamplerStateRegister samplerType);

View file

@ -3507,7 +3507,7 @@ namespace TEN::Renderer
SetScissor(objectInfo->Room->ClipBounds);
if (objectInfo->Bucket->Animated != 0)
_shaderManager.Bind(Shader::RoomsAnimated);
_shaderManager.Bind(Shader::RoomsAnimated
SetBlendMode(objectInfo->Bucket->BlendMode);
SetAlphaTest(AlphaTestMode::None, ALPHA_TEST_THRESHOLD);

View file

@ -246,6 +246,8 @@ namespace TEN::Renderer
_fullscreenTriangleVertexBuffer = VertexBuffer<PostProcessVertex>(_device.Get(), 3, &vertices[0]);
_sPostProcess = CompileOrLoadShader("PostProcess", "", ShaderType::PixelAndVertex);
D3D11_INPUT_ELEMENT_DESC postProcessInputLayoutItems[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
@ -600,4 +602,152 @@ namespace TEN::Renderer
UpdateWindow(WindowsHandle);
}
void Renderer::BindShader(const RendererShader& shader)
{
if (shader.Vertex.Shader != nullptr) _context->VSSetShader(shader.Vertex.Shader.Get(), nullptr, 0);
if (shader.Pixel.Shader != nullptr) _context->PSSetShader(shader.Pixel.Shader.Get(), nullptr, 0);
if (shader.Compute.Shader != nullptr) _context->CSSetShader(shader.Compute.Shader.Get(), nullptr, 0);
}
RendererShader Renderer::CompileOrLoadShader(const std::string& fileName, const std::string& funcName, ShaderType type, const D3D_SHADER_MACRO* defines)
{
RendererShader result = {};
// We need to increment the counter to avoid overwriting compiled shaders with the same source file name.
static int compileCounter = 0;
// Define paths for native (uncompiled) shaders and compiled shaders.
std::wstring shaderPath = GetAssetPath(L"Shaders\\");
std::wstring compiledShaderPath = shaderPath + L"Bin\\";
std::wstring wideFileName = TEN::Utils::ToWString(fileName);
// Ensure the /Bin subdirectory exists.
std::filesystem::create_directories(compiledShaderPath);
// Helper function to load or compile a shader.
auto loadOrCompileShader = [this, type, defines, shaderPath, compiledShaderPath]
(const std::wstring& baseFileName, const std::string& shaderType, const std::string& functionName, const char* model, ComPtr<ID3D10Blob>& bytecode)
{
// Construct the full paths using GetAssetPath.
auto prefix = ((compileCounter < 10) ? L"0" : L"") + std::to_wstring(compileCounter) + L"_";
auto csoFileName = compiledShaderPath + prefix + baseFileName + L"." + std::wstring(shaderType.begin(), shaderType.end()) + L".cso";
auto srcFileName = shaderPath + baseFileName;
// Try both .hlsl and .fx extensions for the source shader.
auto srcFileNameWithExtension = srcFileName + L".hlsl";
if (!std::filesystem::exists(srcFileNameWithExtension))
{
srcFileNameWithExtension = srcFileName + L".fx";
if (!std::filesystem::exists(srcFileNameWithExtension))
{
TENLog("Shader source file not found: " + TEN::Utils::ToString(srcFileNameWithExtension), LogLevel::Error);
throw std::runtime_error("Shader source file not found");
}
}
// Check modification dates of the source and compiled files.
bool shouldRecompile = false;
if (std::filesystem::exists(csoFileName))
{
auto csoTime = std::filesystem::last_write_time(csoFileName);
auto srcTime = std::filesystem::last_write_time(srcFileNameWithExtension);
shouldRecompile = srcTime > csoTime; // Recompile if the source is newer.
}
// Load compiled shader if it exists and is up to date.
if (!shouldRecompile)
{
std::ifstream csoFile(csoFileName, std::ios::binary);
if (csoFile.is_open())
{
// Load compiled shader.
csoFile.seekg(0, std::ios::end);
size_t fileSize = csoFile.tellg();
csoFile.seekg(0, std::ios::beg);
std::vector<char> buffer(fileSize);
csoFile.read(buffer.data(), fileSize);
csoFile.close();
D3DCreateBlob(fileSize, &bytecode);
memcpy(bytecode->GetBufferPointer(), buffer.data(), fileSize);
return;
}
}
// Set up compilation flags according to the build configuration.
unsigned int flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
if constexpr (DebugBuild)
flags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
else
flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_IEEE_STRICTNESS;
auto trimmedFileName = std::filesystem::path(srcFileNameWithExtension).filename().string();
TENLog("Compiling shader: " + trimmedFileName, LogLevel::Info);
// Compile shader.
ComPtr<ID3D10Blob> errors;
HRESULT res = D3DCompileFromFile(srcFileNameWithExtension.c_str(), defines, D3D_COMPILE_STANDARD_FILE_INCLUDE,
(shaderType + functionName).c_str(), model, flags, 0, bytecode.GetAddressOf(), errors.GetAddressOf());
if (FAILED(res))
{
if (errors)
{
auto error = std::string(static_cast<const char*>(errors->GetBufferPointer()));
TENLog(error, LogLevel::Error);
throw std::runtime_error(error);
}
else
{
TENLog("Error while compiling shader: " + trimmedFileName, LogLevel::Error);
throwIfFailed(res);
}
}
// Save compiled shader to .cso file.
std::ofstream outCsoFile(csoFileName, std::ios::binary);
if (outCsoFile.is_open())
{
outCsoFile.write(reinterpret_cast<const char*>(bytecode->GetBufferPointer()), bytecode->GetBufferSize());
outCsoFile.close();
}
};
// Load or compile and create pixel shader.
if (type == ShaderType::Pixel || type == ShaderType::PixelAndVertex)
{
loadOrCompileShader(wideFileName, "PS", funcName, "ps_5_0", result.Pixel.Blob);
throwIfFailed(_device->CreatePixelShader(result.Pixel.Blob->GetBufferPointer(), result.Pixel.Blob->GetBufferSize(),
nullptr, result.Pixel.Shader.GetAddressOf()
));
}
// Load or compile and create vertex shader.
if (type == ShaderType::Vertex || type == ShaderType::PixelAndVertex)
{
loadOrCompileShader(wideFileName, "VS", funcName, "vs_5_0", result.Vertex.Blob);
throwIfFailed(_device->CreateVertexShader(result.Vertex.Blob->GetBufferPointer(), result.Vertex.Blob->GetBufferSize(),
nullptr, result.Vertex.Shader.GetAddressOf()
));
}
// Load or compile and create compute shader.
if (type == ShaderType::Compute)
{
loadOrCompileShader(wideFileName, "CS", funcName, "cs_5_0", result.Compute.Blob);
throwIfFailed(_device->CreateComputeShader(result.Compute.Blob->GetBufferPointer(), result.Compute.Blob->GetBufferSize(),
nullptr, result.Compute.Shader.GetAddressOf()
));
}
// Increment the compile counter.
compileCounter++;
return result;
}
}

View file

@ -11,6 +11,7 @@
#include "Renderer/Structures/RendererShader.h"
#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h"
#include "Specific/trutils.h"
#include "Structures/RendererShader.h"
namespace TEN::Renderer::Utils
{

View file

@ -224,7 +224,6 @@ static constexpr char ScriptReserved_IsTagPresent[] = "IsTagPresent";
static constexpr char ScriptReserved_AddLevel[] = "AddLevel";
static constexpr char ScriptReserved_GetLevel[] = "GetLevel";
static constexpr char ScriptReserved_GetCurrentLevel[] = "GetCurrentLevel";
static constexpr char ScriptReserved_GetNextLevel[] = "GetNextLevel";
static constexpr char ScriptReserved_SetIntroImagePath[] = "SetIntroImagePath";
static constexpr char ScriptReserved_SetTitleScreenImagePath[] = "SetTitleScreenImagePath";
static constexpr char ScriptReserved_SetFarView[] = "SetFarView";

View file

@ -137,12 +137,6 @@ have an ID of 0, the second an ID of 1, and so on.
*/
tableFlow.set_function(ScriptReserved_GetCurrentLevel, &FlowHandler::GetCurrentLevel, this);
/*** Returns the level that is about to load. If no new level is about to load, returns current level.
@function GetNextLevel
@treturn Flow.Level incoming new level or current level, if no new level is loading
*/
tableFlow.set_function(ScriptReserved_GetNextLevel, &FlowHandler::GetNextLevel, this);
/*** Finishes the current level, with optional level index and start position index provided.
If level index is not provided or is zero, jumps to next level. If level index is more than
level count, jumps to title. If LARA\_START\_POS objects are present in level, player will be
@ -467,15 +461,6 @@ Level* FlowHandler::GetCurrentLevel()
return Levels[CurrentLevel];
}
Level* FlowHandler::GetNextLevel()
{
if (NextLevel == CurrentLevel)
return Levels[CurrentLevel];
// NOTE: Negative value indicates incoming savegame.
return Levels[abs(NextLevel)];
}
int FlowHandler::GetNumLevels() const
{
return (int)Levels.size();

View file

@ -54,7 +54,6 @@ public:
void SetLanguageNames(sol::as_table_t<std::vector<std::string>>&& src);
Level* GetLevel(int id);
Level* GetCurrentLevel();
Level* GetNextLevel();
int GetLevelNumber(const std::string& flieName);
int GetNumLevels() const;
void EndLevel(std::optional<int> nextLevel, std::optional<int> startPosIndex);

View file

@ -128,9 +128,9 @@ float3 DoShadow(float3 worldPos, float3 normal, float3 lighting, float bias)
float samples = 0;
// Perform basic PCF filtering with distance-based kernel size
for (float y = -kernelSize; y <= kernelSize; y += 1.0)
for (float y = -SHADOW_BLUR_MIN; y <= SHADOW_BLUR_MIN; y += 1.0)
{
for (float x = -kernelSize; x <= kernelSize; x += 1.0)
for (float x = -SHADOW_BLUR_MIN; x <= SHADOW_BLUR_MIN; x += 1.0)
{
sum += ShadowMap.SampleCmpLevelZero(ShadowMapSampler, float3(lightClipSpace.xy + TexOffset(x, y), i), lightClipSpace.z);
samples += 1.0;