2021.4
This commit is contained in:
parent
28c4c6fb3a
commit
806249048b
|
@ -0,0 +1,128 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\HelloTexturedCubeGame.h" />
|
||||
<ClInclude Include="src\pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\HelloTexturedCubeGame.cpp" />
|
||||
<ClCompile Include="src\main.cpp" />
|
||||
<ClCompile Include="src\pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\HelloTexturedCubeShader.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RendererDirect3D12\RendererDirect3D12.vcxproj">
|
||||
<Project>{53923514-84b2-4b78-889a-8709c6bfa3a5}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\RendererVulkan\RendererVulkan.vcxproj">
|
||||
<Project>{c9195a1c-9224-4b40-bbbc-aa90ef3be3e0}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Verus\Verus.vcxproj">
|
||||
<Project>{b154d670-e4b1-4d8a-885c-69546a5bd833}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\VulkanShaderCompiler\VulkanShaderCompiler.vcxproj">
|
||||
<Project>{1ea5f5d1-9138-406d-871b-3cd75343e14c}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{26bd6e61-e36d-464a-a312-4110adf10083}</ProjectGuid>
|
||||
<RootNamespace>HelloTexturedCube</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\Verus\Verus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\Verus\Verus.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y $(ProjectDir)src\HelloTexturedCubeShader.hlsl $(OutDir)Data\Shaders\
|
||||
xcopy /y $(ProjectDir)src\HelloTexturedCube.dds $(OutDir)Data\Textures\</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y $(ProjectDir)src\HelloTexturedCubeShader.hlsl $(OutDir)Data\Shaders\
|
||||
xcopy /y $(ProjectDir)src\HelloTexturedCube.dds $(OutDir)Data\Textures\</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{15ea43db-379c-4b0c-9691-a1b7e080aefb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\HelloTexturedCubeGame.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\pch.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\HelloTexturedCubeGame.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\main.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\pch.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\HelloTexturedCubeShader.hlsl">
|
||||
<Filter>src</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
Binary file not shown.
|
@ -0,0 +1,168 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "pch.h"
|
||||
|
||||
using namespace verus;
|
||||
using namespace verus::Game;
|
||||
|
||||
HelloTexturedCubeGame::HelloTexturedCubeGame()
|
||||
{
|
||||
Utils::I().SetWritableFolderName("HelloTexturedCube");
|
||||
}
|
||||
|
||||
HelloTexturedCubeGame::~HelloTexturedCubeGame()
|
||||
{
|
||||
CGI::Renderer::I()->WaitIdle();
|
||||
}
|
||||
|
||||
void HelloTexturedCubeGame::BaseGame_UpdateSettings()
|
||||
{
|
||||
VERUS_QREF_SETTINGS;
|
||||
settings._displayOffscreenDraw = false; // Draw directly to swap chain.
|
||||
GetEngineInit().ReducedFeatureSet(); // Don't try to load any resources.
|
||||
}
|
||||
|
||||
void HelloTexturedCubeGame::BaseGame_LoadContent()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
GetCameraSpirit().MoveTo(Point3::Replicate(3));
|
||||
GetCameraSpirit().LookAt(Point3(0), true);
|
||||
|
||||
// Create geometry:
|
||||
{
|
||||
const Vertex cubeVerts[] =
|
||||
{
|
||||
{-1, -1, -1, VERUS_COLOR_RGBA(0, 0, 0, 255)},
|
||||
{+1, -1, -1, VERUS_COLOR_RGBA(255, 0, 0, 255)},
|
||||
{-1, +1, -1, VERUS_COLOR_RGBA(0, 255, 0, 255)},
|
||||
{+1, +1, -1, VERUS_COLOR_RGBA(255, 255, 0, 255)},
|
||||
{-1, -1, +1, VERUS_COLOR_RGBA(0, 0, 255, 255)},
|
||||
{+1, -1, +1, VERUS_COLOR_RGBA(255, 0, 255, 255)},
|
||||
{-1, +1, +1, VERUS_COLOR_RGBA(0, 255, 255, 255)},
|
||||
{+1, +1, +1, VERUS_COLOR_RGBA(255, 255, 255, 255)}
|
||||
};
|
||||
_vertCount = VERUS_COUNT_OF(cubeVerts);
|
||||
|
||||
const UINT16 cubeIndices[] =
|
||||
{
|
||||
// -X
|
||||
2, 0, 6,
|
||||
6, 0, 4,
|
||||
|
||||
// +X
|
||||
1, 3, 5,
|
||||
5, 3, 7,
|
||||
|
||||
// -Y
|
||||
0, 1, 4,
|
||||
4, 1, 5,
|
||||
|
||||
// +Y
|
||||
2, 6, 3,
|
||||
3, 6, 7,
|
||||
|
||||
// -Z
|
||||
5, 7, 4,
|
||||
4, 7, 6,
|
||||
|
||||
// +Z
|
||||
1, 0, 3,
|
||||
3, 0, 2
|
||||
};
|
||||
_indexCount = VERUS_COUNT_OF(cubeIndices);
|
||||
|
||||
CGI::GeometryDesc geoDesc;
|
||||
geoDesc._name = "HelloTexturedCube.Geo"; // Optional name, for RenderDoc, etc.
|
||||
const CGI::VertexInputAttrDesc viaDesc[] =
|
||||
{
|
||||
{0, offsetof(Vertex, _x), CGI::ViaType::floats, 3, CGI::ViaUsage::position, 0}, // 3 floats for position.
|
||||
{0, offsetof(Vertex, _color), CGI::ViaType::ubytes, 4, CGI::ViaUsage::color, 0}, // Color can be stored as 32-bit unsigned integer.
|
||||
CGI::VertexInputAttrDesc::End()
|
||||
};
|
||||
geoDesc._pVertexInputAttrDesc = viaDesc;
|
||||
const int strides[] = { sizeof(Vertex), 0 };
|
||||
geoDesc._pStrides = strides;
|
||||
_geo.Init(geoDesc);
|
||||
_geo->CreateVertexBuffer(_vertCount, 0);
|
||||
_geo->UpdateVertexBuffer(cubeVerts, 0); // Copy command. When BaseGame_LoadContent is called, the command buffer is already recording commands.
|
||||
_geo->CreateIndexBuffer(_indexCount);
|
||||
_geo->UpdateIndexBuffer(cubeIndices); // Copy command.
|
||||
}
|
||||
|
||||
// Create shader:
|
||||
{
|
||||
_shader.Init("[Shaders]:HelloTexturedCubeShader.hlsl"); // HLSL file was copied by Post-Build Event.
|
||||
_shader->CreateDescriptorSet(0, &_ubShaderVS, sizeof(_ubShaderVS), 100, {}, CGI::ShaderStageFlags::vs); // Uniform buffer used only by vertex shader.
|
||||
_shader->CreateDescriptorSet(1, &_ubShaderFS, sizeof(_ubShaderFS), 100,
|
||||
{
|
||||
CGI::Sampler::aniso // Immutable sampler for this set.
|
||||
}, CGI::ShaderStageFlags::fs); // Uniform buffer used only by fragment shader.
|
||||
_shader->CreatePipelineLayout();
|
||||
}
|
||||
|
||||
// Create pipeline:
|
||||
{
|
||||
// What to draw? How to draw? Where to draw?
|
||||
CGI::PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_AutoWithDepth()); // Reuse existing render pass.
|
||||
_pipe.Init(pipeDesc);
|
||||
}
|
||||
|
||||
_tex.Init("[Textures]:HelloTexturedCube.dds"); // Texture file was copied by Post-Build Event.
|
||||
}
|
||||
|
||||
void HelloTexturedCubeGame::BaseGame_UnloadContent()
|
||||
{
|
||||
}
|
||||
|
||||
void HelloTexturedCubeGame::BaseGame_HandleInput()
|
||||
{
|
||||
}
|
||||
|
||||
void HelloTexturedCubeGame::BaseGame_Update()
|
||||
{
|
||||
VERUS_QREF_TIMER;
|
||||
|
||||
_rotation += Vector3(dt * 0.03f, dt * 0.05f, dt * 0.07f);
|
||||
}
|
||||
|
||||
void HelloTexturedCubeGame::BaseGame_Draw()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_TIMER;
|
||||
|
||||
if (!_csh.IsSet() && _tex->IsLoaded())
|
||||
_csh = _shader->BindDescriptorSetTextures(1, { _tex });
|
||||
|
||||
ImGui::Text("HelloTexturedCube");
|
||||
ImGui::Text("Use Mouse and WASD keys");
|
||||
|
||||
Scene::RCamera camera = GetCamera();
|
||||
Transform3 matW = Transform3::rotationZYX(_rotation);
|
||||
|
||||
auto cb = renderer.GetCommandBuffer(); // Default command buffer for this frame.
|
||||
|
||||
_ubShaderVS._matW = matW.UniformBufferFormat();
|
||||
_ubShaderVS._matVP = camera.GetMatrixVP().UniformBufferFormat();
|
||||
_ubShaderFS._phase = pow(abs(0.5f - glm::fract(timer.GetTime() * 0.25f)) * 2, 4.f); // Blink.
|
||||
|
||||
cb->BeginRenderPass(
|
||||
renderer.GetRenderPassHandle_AutoWithDepth(),
|
||||
renderer.GetFramebufferHandle_AutoWithDepth(renderer->GetSwapChainBufferIndex()),
|
||||
{ Vector4(0), Vector4(1) });
|
||||
|
||||
if (_csh.IsSet()) // Texture is loaded asynchronously. Don't draw the cube, while the texture is loading.
|
||||
{
|
||||
cb->BindPipeline(_pipe);
|
||||
cb->BindVertexBuffers(_geo);
|
||||
cb->BindIndexBuffer(_geo);
|
||||
_shader->BeginBindDescriptors(); // Map.
|
||||
cb->BindDescriptors(_shader, 0); // Update uniform buffer for set=0. (Copy from _ubShaderVS)
|
||||
cb->BindDescriptors(_shader, 1, _csh); // Update uniform buffer for set=1. (Copy from _ubShaderFS). Also set textures.
|
||||
_shader->EndBindDescriptors(); // Unmap.
|
||||
cb->DrawIndexed(_indexCount);
|
||||
}
|
||||
|
||||
renderer->ImGuiRenderDrawData(); // Also draw Dear ImGui, please.
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
namespace verus
|
||||
{
|
||||
namespace Game
|
||||
{
|
||||
class HelloTexturedCubeGame : public Singleton<HelloTexturedCubeGame>, public BaseGame
|
||||
{
|
||||
struct Vertex
|
||||
{
|
||||
float _x, _y, _z;
|
||||
UINT32 _color;
|
||||
};
|
||||
VERUS_TYPEDEFS(Vertex);
|
||||
|
||||
VERUS_UBUFFER UB_ShaderVS
|
||||
{
|
||||
mataff _matW;
|
||||
matrix _matVP;
|
||||
};
|
||||
|
||||
VERUS_UBUFFER UB_ShaderFS
|
||||
{
|
||||
float _phase;
|
||||
};
|
||||
|
||||
Vector3 _rotation = Vector3(0);
|
||||
CGI::GeometryPwn _geo;
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwn _pipe;
|
||||
CGI::TexturePwn _tex;
|
||||
CSZ _shaderCode;
|
||||
CGI::CSHandle _csh; // Complex set handle. Simple set has one uniform buffer. Complex set additionally has textures.
|
||||
UB_ShaderVS _ubShaderVS;
|
||||
UB_ShaderFS _ubShaderFS;
|
||||
int _vertCount = 0;
|
||||
int _indexCount = 0;
|
||||
|
||||
public:
|
||||
HelloTexturedCubeGame();
|
||||
~HelloTexturedCubeGame();
|
||||
|
||||
virtual void BaseGame_UpdateSettings() override;
|
||||
virtual void BaseGame_LoadContent() override;
|
||||
virtual void BaseGame_UnloadContent() override;
|
||||
virtual void BaseGame_HandleInput() override;
|
||||
virtual void BaseGame_Update() override;
|
||||
virtual void BaseGame_Draw() override;
|
||||
};
|
||||
VERUS_TYPEDEFS(HelloTexturedCubeGame);
|
||||
}
|
||||
}
|
||||
|
||||
#define VERUS_QREF_GAME Game::RHelloTexturedCubeGame game = Game::HelloTexturedCubeGame::I()
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
|
||||
// Copied from Lib.hlsl:
|
||||
#define VERUS_UBUFFER struct
|
||||
#define mataff float4x3
|
||||
#ifdef _VULKAN
|
||||
# define VK_LOCATION_POSITION [[vk::location(0)]]
|
||||
# define VK_LOCATION_COLOR0 [[vk::location(3)]]
|
||||
#else
|
||||
# define VK_LOCATION_POSITION
|
||||
# define VK_LOCATION_COLOR0
|
||||
#endif
|
||||
|
||||
VERUS_UBUFFER UB_ShaderVS
|
||||
{
|
||||
mataff _matW;
|
||||
matrix _matVP;
|
||||
};
|
||||
|
||||
VERUS_UBUFFER UB_ShaderFS
|
||||
{
|
||||
float _phase;
|
||||
};
|
||||
|
||||
ConstantBuffer<UB_ShaderVS> g_ubShaderVS : register(b0, space0);
|
||||
ConstantBuffer<UB_ShaderFS> g_ubShaderFS : register(b0, space1);
|
||||
|
||||
Texture2D g_tex : register(t1, space1);
|
||||
SamplerState g_sam : register(s1, space1);
|
||||
|
||||
struct VSI
|
||||
{
|
||||
VK_LOCATION_POSITION float3 pos : POSITION;
|
||||
VK_LOCATION_COLOR0 float4 color : COLOR0;
|
||||
};
|
||||
|
||||
struct VSO
|
||||
{
|
||||
float4 pos : SV_Position;
|
||||
float3 tcCube : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
};
|
||||
|
||||
struct FSO
|
||||
{
|
||||
float4 color : SV_Target0;
|
||||
};
|
||||
|
||||
#ifdef _VS
|
||||
VSO mainVS(VSI si)
|
||||
{
|
||||
VSO so;
|
||||
|
||||
const float3 posW = mul(float4(si.pos, 1), g_ubShaderVS._matW);
|
||||
so.pos = mul(float4(posW, 1), g_ubShaderVS._matVP);
|
||||
so.tcCube = si.pos.xyz * float3(1, -1, 1);
|
||||
so.color = si.color;
|
||||
|
||||
return so;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _FS
|
||||
FSO mainFS(VSO si)
|
||||
{
|
||||
FSO so;
|
||||
|
||||
// Generate texture coordinates using CubeMap method:
|
||||
float2 tc = 0.0;
|
||||
const float3 mag = abs(si.tcCube);
|
||||
if (mag.x >= mag.y && mag.x >= mag.z)
|
||||
tc = 0.5 * (si.tcCube.zy / mag.x + 1.0);
|
||||
else if (mag.y >= mag.x && mag.y >= mag.z)
|
||||
tc = 0.5 * (si.tcCube.xz / mag.y + 1.0);
|
||||
else
|
||||
tc = 0.5 * (si.tcCube.xy / mag.z + 1.0);
|
||||
|
||||
so.color = g_tex.Sample(g_sam, tc);
|
||||
|
||||
so.color = lerp(so.color, si.color, g_ubShaderFS._phase);
|
||||
|
||||
return so;
|
||||
}
|
||||
#endif
|
||||
|
||||
//@main:#
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "pch.h"
|
||||
|
||||
using namespace verus;
|
||||
|
||||
int main(VERUS_MAIN_DEFAULT_ARGS)
|
||||
{
|
||||
Game::HelloTexturedCubeGame game;
|
||||
try
|
||||
{
|
||||
game.Initialize(argc, argv);
|
||||
game.Run();
|
||||
}
|
||||
catch (D::RcRuntimeError e)
|
||||
{
|
||||
D::Log::I().Write(e.what(), e.GetThreadID(), e.GetFile(), e.GetLine(), D::Log::Severity::error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
VERUS_LOG_ERROR(e.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "pch.h"
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
#include <verus.h>
|
||||
|
||||
#include "HelloTexturedCubeGame.h"
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\HelloTriangleGame.h" />
|
||||
<ClInclude Include="src\pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\HelloTriangleGame.cpp" />
|
||||
<ClCompile Include="src\main.cpp" />
|
||||
<ClCompile Include="src\pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RendererDirect3D12\RendererDirect3D12.vcxproj">
|
||||
<Project>{53923514-84b2-4b78-889a-8709c6bfa3a5}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\RendererVulkan\RendererVulkan.vcxproj">
|
||||
<Project>{c9195a1c-9224-4b40-bbbc-aa90ef3be3e0}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Verus\Verus.vcxproj">
|
||||
<Project>{b154d670-e4b1-4d8a-885c-69546a5bd833}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\VulkanShaderCompiler\VulkanShaderCompiler.vcxproj">
|
||||
<Project>{1ea5f5d1-9138-406d-871b-3cd75343e14c}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\HelloTriangleShader.hlsl">
|
||||
<FileType>Document</FileType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{bc17acd3-97eb-4d5c-a2c9-574cdaa7576b}</ProjectGuid>
|
||||
<RootNamespace>HelloTriangle</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\Verus\Verus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\Verus\Verus.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{b500ecb1-338a-4b8b-ad40-389727e8a8cf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\HelloTriangleGame.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\pch.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\HelloTriangleGame.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\main.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\pch.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\HelloTriangleShader.hlsl">
|
||||
<Filter>src</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "pch.h"
|
||||
|
||||
using namespace verus;
|
||||
using namespace verus::Game;
|
||||
|
||||
HelloTriangleGame::HelloTriangleGame()
|
||||
{
|
||||
Utils::I().SetWritableFolderName("HelloTriangle");
|
||||
}
|
||||
|
||||
HelloTriangleGame::~HelloTriangleGame()
|
||||
{
|
||||
CGI::Renderer::I()->WaitIdle();
|
||||
}
|
||||
|
||||
void HelloTriangleGame::BaseGame_UpdateSettings()
|
||||
{
|
||||
VERUS_QREF_SETTINGS;
|
||||
settings._displayOffscreenDraw = false; // Draw directly to swap chain.
|
||||
GetEngineInit().ReducedFeatureSet(); // Don't try to load any resources.
|
||||
}
|
||||
|
||||
void HelloTriangleGame::BaseGame_LoadContent()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
// Create geometry:
|
||||
{
|
||||
const Vertex triangle[] =
|
||||
{
|
||||
{ 0, 0.5f, 0, VERUS_COLOR_RGBA(255, 0, 0, 255)}, // Red vertex (on top).
|
||||
{-0.5f, -0.5f, 0, VERUS_COLOR_RGBA(0, 255, 0, 255)}, // Green vertex.
|
||||
{ 0.5f, -0.5f, 0, VERUS_COLOR_RGBA(0, 0, 255, 255)}, // Blue vertex.
|
||||
};
|
||||
_vertCount = VERUS_COUNT_OF(triangle);
|
||||
|
||||
CGI::GeometryDesc geoDesc;
|
||||
geoDesc._name = "HelloTriangle.Geo"; // Optional name, for RenderDoc, etc.
|
||||
const CGI::VertexInputAttrDesc viaDesc[] =
|
||||
{
|
||||
{0, offsetof(Vertex, _x), CGI::ViaType::floats, 3, CGI::ViaUsage::position, 0}, // 3 floats for position.
|
||||
{0, offsetof(Vertex, _color), CGI::ViaType::ubytes, 4, CGI::ViaUsage::color, 0}, // Color can be stored as 32-bit unsigned integer.
|
||||
CGI::VertexInputAttrDesc::End()
|
||||
};
|
||||
geoDesc._pVertexInputAttrDesc = viaDesc;
|
||||
const int strides[] = { sizeof(Vertex), 0 };
|
||||
geoDesc._pStrides = strides;
|
||||
_geo.Init(geoDesc);
|
||||
_geo->CreateVertexBuffer(_vertCount, 0);
|
||||
_geo->UpdateVertexBuffer(triangle, 0); // Copy command. When BaseGame_LoadContent is called, the command buffer is already recording commands.
|
||||
}
|
||||
|
||||
// Create shader:
|
||||
{
|
||||
// Shader code can be provided as a string.
|
||||
_shaderCode =
|
||||
#include "HelloTriangleShader.hlsl"
|
||||
;
|
||||
CSZ branches[] =
|
||||
{
|
||||
"main:#",
|
||||
nullptr
|
||||
};
|
||||
|
||||
CGI::ShaderDesc shaderDesc;
|
||||
shaderDesc._source = _shaderCode;
|
||||
shaderDesc._branches = branches;
|
||||
_shader.Init(shaderDesc);
|
||||
_shader->CreateDescriptorSet(0, &_ubShaderVS, sizeof(_ubShaderVS), 100, {}, CGI::ShaderStageFlags::vs); // Uniform buffer used only by vertex shader.
|
||||
_shader->CreateDescriptorSet(1, &_ubShaderFS, sizeof(_ubShaderFS), 100, {}, CGI::ShaderStageFlags::fs); // Uniform buffer used only by fragment shader.
|
||||
_shader->CreatePipelineLayout();
|
||||
}
|
||||
|
||||
// Create pipeline:
|
||||
{
|
||||
// What to draw? How to draw? Where to draw?
|
||||
CGI::PipelineDesc pipeDesc(_geo, _shader, "#", renderer.GetRenderPassHandle_AutoWithDepth()); // Reuse existing render pass.
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe.Init(pipeDesc);
|
||||
}
|
||||
}
|
||||
|
||||
void HelloTriangleGame::BaseGame_UnloadContent()
|
||||
{
|
||||
}
|
||||
|
||||
void HelloTriangleGame::BaseGame_HandleInput()
|
||||
{
|
||||
//_stateMachine.HandleInput();
|
||||
}
|
||||
|
||||
void HelloTriangleGame::BaseGame_Update()
|
||||
{
|
||||
//_stateMachine.Update();
|
||||
}
|
||||
|
||||
void HelloTriangleGame::BaseGame_Draw()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_TIMER;
|
||||
|
||||
//ImGui::Text("HelloTriangle");
|
||||
|
||||
auto cb = renderer.GetCommandBuffer(); // Default command buffer for this frame.
|
||||
|
||||
const Matrix4 matWVP = Matrix4::scale(
|
||||
Vector3(
|
||||
0.9f + 0.2f * sin(timer.GetTime() * VERUS_PI * 0.41f), // Wobble.
|
||||
0.9f + 0.2f * sin(timer.GetTime() * VERUS_PI * 0.47f),
|
||||
1));
|
||||
_ubShaderVS._matWVP = matWVP.UniformBufferFormat();
|
||||
_ubShaderFS._phase = pow(abs(0.5f - glm::fract(timer.GetTime())) * 2, 4.f); // Blink.
|
||||
|
||||
cb->BeginRenderPass(
|
||||
renderer.GetRenderPassHandle_AutoWithDepth(),
|
||||
renderer.GetFramebufferHandle_AutoWithDepth(renderer->GetSwapChainBufferIndex()),
|
||||
{ Vector4(0), Vector4(1) });
|
||||
|
||||
cb->BindPipeline(_pipe);
|
||||
cb->BindVertexBuffers(_geo);
|
||||
_shader->BeginBindDescriptors(); // Map.
|
||||
cb->BindDescriptors(_shader, 0); // Update uniform buffer for set=0. (Copy from _ubShaderVS)
|
||||
cb->BindDescriptors(_shader, 1); // Update uniform buffer for set=1. (Copy from _ubShaderFS)
|
||||
_shader->EndBindDescriptors(); // Unmap.
|
||||
cb->Draw(_vertCount);
|
||||
|
||||
renderer->ImGuiRenderDrawData(); // Also draw Dear ImGui, please.
|
||||
|
||||
cb->EndRenderPass();
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
namespace verus
|
||||
{
|
||||
namespace Game
|
||||
{
|
||||
// Epigraph
|
||||
// "Vulkan – (it takes) 1000 lines to draw a triangle"
|
||||
// "- I thought you only needed 3 lines to draw a triangle"
|
||||
// https://www.reddit.com/r/linux/comments/58fyqn/vulkan_1000_lines_to_draw_a_triangle/
|
||||
|
||||
class HelloTriangleGame : public Singleton<HelloTriangleGame>, public BaseGame
|
||||
{
|
||||
struct Vertex
|
||||
{
|
||||
float _x, _y, _z;
|
||||
UINT32 _color;
|
||||
};
|
||||
VERUS_TYPEDEFS(Vertex);
|
||||
|
||||
VERUS_UBUFFER UB_ShaderVS
|
||||
{
|
||||
matrix _matWVP;
|
||||
};
|
||||
|
||||
VERUS_UBUFFER UB_ShaderFS
|
||||
{
|
||||
float _phase;
|
||||
};
|
||||
|
||||
CGI::GeometryPwn _geo;
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwn _pipe;
|
||||
CSZ _shaderCode;
|
||||
UB_ShaderVS _ubShaderVS;
|
||||
UB_ShaderFS _ubShaderFS;
|
||||
int _vertCount = 0;
|
||||
|
||||
public:
|
||||
HelloTriangleGame();
|
||||
~HelloTriangleGame();
|
||||
|
||||
virtual void BaseGame_UpdateSettings() override;
|
||||
virtual void BaseGame_LoadContent() override;
|
||||
virtual void BaseGame_UnloadContent() override;
|
||||
virtual void BaseGame_HandleInput() override;
|
||||
virtual void BaseGame_Update() override;
|
||||
virtual void BaseGame_Draw() override;
|
||||
};
|
||||
VERUS_TYPEDEFS(HelloTriangleGame);
|
||||
}
|
||||
}
|
||||
|
||||
#define VERUS_QREF_GAME Game::RHelloTriangleGame game = Game::HelloTriangleGame::I()
|
|
@ -0,0 +1,70 @@
|
|||
R"(
|
||||
|
||||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
|
||||
// Copied from Lib.hlsl:
|
||||
#define VERUS_UBUFFER struct
|
||||
#ifdef _VULKAN
|
||||
# define VK_LOCATION_POSITION [[vk::location(0)]]
|
||||
# define VK_LOCATION_COLOR0 [[vk::location(3)]]
|
||||
#else
|
||||
# define VK_LOCATION_POSITION
|
||||
# define VK_LOCATION_COLOR0
|
||||
#endif
|
||||
|
||||
VERUS_UBUFFER UB_ShaderVS
|
||||
{
|
||||
matrix _matWVP;
|
||||
};
|
||||
|
||||
VERUS_UBUFFER UB_ShaderFS
|
||||
{
|
||||
float _phase;
|
||||
};
|
||||
|
||||
ConstantBuffer<UB_ShaderVS> g_ubShaderVS : register(b0, space0);
|
||||
ConstantBuffer<UB_ShaderFS> g_ubShaderFS : register(b0, space1);
|
||||
|
||||
struct VSI
|
||||
{
|
||||
VK_LOCATION_POSITION float4 pos : POSITION;
|
||||
VK_LOCATION_COLOR0 float4 color : COLOR0;
|
||||
};
|
||||
|
||||
struct VSO
|
||||
{
|
||||
float4 pos : SV_Position;
|
||||
float4 color : COLOR0;
|
||||
};
|
||||
|
||||
struct FSO
|
||||
{
|
||||
float4 color : SV_Target0;
|
||||
};
|
||||
|
||||
#ifdef _VS
|
||||
VSO mainVS(VSI si)
|
||||
{
|
||||
VSO so;
|
||||
|
||||
so.pos = mul(si.pos, g_ubShaderVS._matWVP);
|
||||
so.color = si.color;
|
||||
|
||||
return so;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _FS
|
||||
FSO mainFS(VSO si)
|
||||
{
|
||||
FSO so;
|
||||
|
||||
so.color = saturate(si.color + g_ubShaderFS._phase);
|
||||
|
||||
return so;
|
||||
}
|
||||
#endif
|
||||
|
||||
//@main:#
|
||||
|
||||
)"
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "pch.h"
|
||||
|
||||
using namespace verus;
|
||||
|
||||
int main(VERUS_MAIN_DEFAULT_ARGS)
|
||||
{
|
||||
Game::HelloTriangleGame game;
|
||||
try
|
||||
{
|
||||
game.Initialize(argc, argv);
|
||||
game.Run(false);
|
||||
}
|
||||
catch (D::RcRuntimeError e)
|
||||
{
|
||||
D::Log::I().Write(e.what(), e.GetThreadID(), e.GetFile(), e.GetLine(), D::Log::Severity::error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
VERUS_LOG_ERROR(e.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "pch.h"
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
#include <verus.h>
|
||||
|
||||
#include "HelloTriangleGame.h"
|
35
README.md
35
README.md
|
@ -1,8 +1,29 @@
|
|||
# verus
|
||||
Game Engine
|
||||
# Verus Engine
|
||||
|
||||
# Release
|
||||
undef VERUS_RELEASE_DEBUG
|
||||
UseFullPaths=false
|
||||
DebugInformationFormat=None
|
||||
GenerateDebugInformation=false (Link)
|
||||
## What is Verus Engine?
|
||||
Verus Engine is a modern, platform-agnostic 3D game engine. It is developed using **C++** and **HLSL**. It is based on **Direct3D 12** and **Vulkan** graphics APIs. The code is user friendly and well optimized. The engine is intended to be a full-featured solution for making games. It includes modules to handle input, audio, networking and other things. Hence there is no need to search for third-party libraries or write custom code.
|
||||
|
||||
## Supported systems
|
||||
* **Windows 10**, 8, 8.1 *(via Vulkan renderer)*
|
||||
* **64-bit only**, 32-bit is not supported
|
||||
|
||||
## Supported graphics libraries
|
||||
* Vulkan
|
||||
* Direct3D 12
|
||||
|
||||
## Features
|
||||
* Native cross-platform code
|
||||
* Same HLSL shader code for all APIs
|
||||
* Deferred shading
|
||||
* Efficient textures and streaming
|
||||
* Large terrain support
|
||||
* Built-in audio system
|
||||
* Multiplayer support
|
||||
* Custom user interface module
|
||||
* Collision and physics support
|
||||
* A bunch of post-processing effects
|
||||
* Filesystem abstraction
|
||||
* Other things
|
||||
|
||||
## License
|
||||
Verus Engine is free for non-commercial use
|
||||
|
|
|
@ -374,6 +374,12 @@ void RendererD3D12::CreateSamplers()
|
|||
init.MinLOD = 0;
|
||||
init.MaxLOD = D3D12_FLOAT32_MAX;
|
||||
|
||||
desc = init;
|
||||
desc.Filter = D3D12_FILTER_ANISOTROPIC;
|
||||
desc.MipLODBias = -2;
|
||||
desc.MaxAnisotropy = settings._gpuAnisotropyLevel;
|
||||
_vSamplers[+Sampler::lodBias] = desc;
|
||||
|
||||
desc = init;
|
||||
desc.Filter = (settings._sceneShadowQuality <= App::Settings::Quality::low) ?
|
||||
D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT : D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
|
||||
|
@ -888,6 +894,10 @@ void RendererD3D12::SetDescriptorHeaps(PBaseCommandBuffer p)
|
|||
|
||||
void RendererD3D12::UpdateUtilization()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
renderer.AddUtilization("D3D12 Views", _dhViews.GetOffset(), _dhViews.GetCapacity());
|
||||
renderer.AddUtilization("D3D12 Samplers", _dhSamplers.GetOffset(), _dhSamplers.GetCapacity());
|
||||
|
||||
for (auto& x : TStoreGeometry::_list)
|
||||
x.UpdateUtilization();
|
||||
for (auto& x : TStoreShaders::_list)
|
||||
|
|
|
@ -629,6 +629,12 @@ void RendererVulkan::CreateSamplers()
|
|||
return sampler;
|
||||
};
|
||||
|
||||
vksci = init;
|
||||
vksci.mipLodBias = -2;
|
||||
vksci.anisotropyEnable = (settings._gpuAnisotropyLevel > 0) ? VK_TRUE : VK_FALSE;
|
||||
vksci.maxAnisotropy = static_cast<float>(settings._gpuAnisotropyLevel);
|
||||
_vSamplers[+Sampler::lodBias] = Create(vksci);
|
||||
|
||||
vksci = init;
|
||||
if (settings._sceneShadowQuality <= App::Settings::Quality::low)
|
||||
{
|
||||
|
|
12
Verus.sln
12
Verus.sln
|
@ -15,6 +15,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PAKBuilder", "PAKBuilder\PA
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextureTool", "TextureTool\TextureTool.vcxproj", "{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloTriangle", "HelloTriangle\HelloTriangle.vcxproj", "{BC17ACD3-97EB-4D5C-A2C9-574CDAA7576B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloTexturedCube", "HelloTexturedCube\HelloTexturedCube.vcxproj", "{26BD6E61-E36D-464A-A312-4110ADF10083}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -45,6 +49,14 @@ Global
|
|||
{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}.Debug|x64.Build.0 = Debug|x64
|
||||
{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}.Release|x64.ActiveCfg = Release|x64
|
||||
{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}.Release|x64.Build.0 = Release|x64
|
||||
{BC17ACD3-97EB-4D5C-A2C9-574CDAA7576B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BC17ACD3-97EB-4D5C-A2C9-574CDAA7576B}.Debug|x64.Build.0 = Debug|x64
|
||||
{BC17ACD3-97EB-4D5C-A2C9-574CDAA7576B}.Release|x64.ActiveCfg = Release|x64
|
||||
{BC17ACD3-97EB-4D5C-A2C9-574CDAA7576B}.Release|x64.Build.0 = Release|x64
|
||||
{26BD6E61-E36D-464A-A312-4110ADF10083}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{26BD6E61-E36D-464A-A312-4110ADF10083}.Debug|x64.Build.0 = Debug|x64
|
||||
{26BD6E61-E36D-464A-A312-4110ADF10083}.Release|x64.ActiveCfg = Release|x64
|
||||
{26BD6E61-E36D-464A-A312-4110ADF10083}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.20.1-bin\include;C:\Home\Middleware\SDL2-2.0.14\include;C:\VulkanSDK\1.2.170.0\Include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.20.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.14\lib\x64;C:\VulkanSDK\1.2.170.0\Lib;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\Compressonator_3.2.4691\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.20.1-bin\include;C:\Home\Middleware\SDL2-2.0.14\include;C:\VulkanSDK\1.2.176.1\Include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Compressonator_3.2.4691\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.20.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.14\lib\x64;C:\VulkanSDK\1.2.176.1\Lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup />
|
||||
<ItemGroup />
|
||||
|
|
|
@ -181,6 +181,7 @@
|
|||
<ClInclude Include="src\Global\Timer.h" />
|
||||
<ClInclude Include="src\Global\Utils.h" />
|
||||
<ClInclude Include="src\GUI\Animator.h" />
|
||||
<ClInclude Include="src\GUI\Bars.h" />
|
||||
<ClInclude Include="src\GUI\Button.h" />
|
||||
<ClInclude Include="src\GUI\Chat.h" />
|
||||
<ClInclude Include="src\GUI\Container.h" />
|
||||
|
@ -378,6 +379,7 @@
|
|||
<ClCompile Include="src\Global\Timer.cpp" />
|
||||
<ClCompile Include="src\Global\Utils.cpp" />
|
||||
<ClCompile Include="src\GUI\Animator.cpp" />
|
||||
<ClCompile Include="src\GUI\Bars.cpp" />
|
||||
<ClCompile Include="src\GUI\Button.cpp" />
|
||||
<ClCompile Include="src\GUI\Chat.cpp" />
|
||||
<ClCompile Include="src\GUI\Container.cpp" />
|
||||
|
|
|
@ -756,6 +756,9 @@
|
|||
<ClInclude Include="src\Game\ActiveMechanics.h">
|
||||
<Filter>src\Game</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\GUI\Bars.h">
|
||||
<Filter>src\GUI</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\CGI\BaseGeometry.cpp">
|
||||
|
@ -1292,6 +1295,9 @@
|
|||
<ClCompile Include="src\Game\ActiveMechanics.cpp">
|
||||
<Filter>src\Game</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\GUI\Bars.cpp">
|
||||
<Filter>src\GUI</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="src\Shaders\Lib.hlsl">
|
||||
|
|
|
@ -80,39 +80,46 @@ void Animation::Update(int alphaTrackCount, PAlphaTrack pAlphaTracks)
|
|||
|
||||
if (_playing)
|
||||
{
|
||||
if (_blending)
|
||||
float dt2 = dt;
|
||||
if (_blending) // Still blending?
|
||||
{
|
||||
_blendTimer += dt;
|
||||
if (_blendTimer >= _blendDuration)
|
||||
_blendTime += dt2;
|
||||
if (_blendTime >= _blendDuration)
|
||||
{
|
||||
_blending = false;
|
||||
dt2 -= _blendTime - _blendDuration;
|
||||
}
|
||||
}
|
||||
else if (!_currentMotion.empty())
|
||||
if (!_blending && !_currentMotion.empty()) // Done blending?
|
||||
{
|
||||
RMotionData md = *_pCollection->Find(_C(_currentMotion));
|
||||
const float len = md._motion.GetDuration();
|
||||
if (_time < len + 0.5f)
|
||||
const float duration = md._motion.GetDuration();
|
||||
_time += dt2;
|
||||
md._motion.ProcessTriggers(_time, this, GetTriggerStatesArray());
|
||||
if (_time >= duration)
|
||||
{
|
||||
_time += dt;
|
||||
md._motion.ProcessTriggers(_time, this, GetTriggerStatesArray());
|
||||
if (_time >= len)
|
||||
{
|
||||
if (_pDelegate)
|
||||
_pDelegate->Animation_OnEnd(_C(_currentMotion));
|
||||
_time = md._loop ? fmod(_time, len) : len + 1;
|
||||
md._motion.ResetTriggers(GetTriggerStatesArray()); // New loop, reset triggers.
|
||||
}
|
||||
_playing = md._loop; // Continue?
|
||||
_time = md._loop ? fmod(_time, duration) : duration;
|
||||
md._motion.ResetTriggers(GetTriggerStatesArray()); // New loop, reset triggers.
|
||||
if (_pDelegate)
|
||||
_pDelegate->Animation_OnEnd(_C(_currentMotion)); // This can call BlendTo and change everything.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateSkeleton(alphaTrackCount, pAlphaTracks);
|
||||
}
|
||||
|
||||
void Animation::UpdateSkeleton(int alphaTrackCount, PAlphaTrack pAlphaTracks)
|
||||
{
|
||||
if (!_currentMotion.empty() && alphaTrackCount >= 0) // Alpha track (-1) should not modify the skeleton.
|
||||
{
|
||||
RMotionData md = *_pCollection->Find(_C(_currentMotion));
|
||||
|
||||
int alphaMotionCount = 0;
|
||||
Skeleton::AlphaMotion alphaMotions[4];
|
||||
Skeleton::AlphaMotion alphaMotions[s_maxAlphaTracks];
|
||||
|
||||
for (int i = 0; i < alphaTrackCount && i < 4; ++i)
|
||||
for (int i = 0; i < alphaTrackCount && i < s_maxAlphaTracks; ++i)
|
||||
{
|
||||
alphaMotions[i]._pMotion = pAlphaTracks[i]._pAnimation->GetMotion(); // Can be in blend state.
|
||||
alphaMotions[i]._rootBone = pAlphaTracks[i]._rootBone;
|
||||
|
@ -123,7 +130,7 @@ void Animation::Update(int alphaTrackCount, PAlphaTrack pAlphaTracks)
|
|||
|
||||
if (_blending)
|
||||
{
|
||||
md._motion.BindBlendMotion(&_blendMotion, _blendTimer / _blendDuration);
|
||||
md._motion.BindBlendMotion(&_blendMotion, Math::ApplyEasing(_easing, _blendTime / _blendDuration));
|
||||
_pSkeleton->ApplyMotion(md._motion, _time, alphaMotionCount, alphaMotions);
|
||||
}
|
||||
else
|
||||
|
@ -147,20 +154,6 @@ void Animation::BindSkeleton(PSkeleton p)
|
|||
_pSkeleton = p;
|
||||
}
|
||||
|
||||
void Animation::SetCurrentMotion(CSZ name)
|
||||
{
|
||||
// Reset triggers:
|
||||
if (!_currentMotion.empty())
|
||||
_pCollection->Find(_C(_currentMotion))->_motion.ResetTriggers(GetTriggerStatesArray());
|
||||
if (name)
|
||||
{
|
||||
_pCollection->Find(name)->_motion.ResetTriggers(GetTriggerStatesArray());
|
||||
_currentMotion = name;
|
||||
}
|
||||
else
|
||||
_currentMotion.clear();
|
||||
}
|
||||
|
||||
void Animation::Play()
|
||||
{
|
||||
_playing = true;
|
||||
|
@ -177,22 +170,22 @@ void Animation::Pause()
|
|||
_playing = false;
|
||||
}
|
||||
|
||||
void Animation::BlendTo(CSZ name, Range<float> duration, int randTime, PMotion pMotionFrom)
|
||||
void Animation::BlendTo(CSZ name, Range<float> duration, int randTime, PMotion pFromMotion)
|
||||
{
|
||||
VERUS_QREF_UTILS;
|
||||
|
||||
PMotion pMotion = pMotionFrom;
|
||||
if (!_currentMotion.empty() || pMotionFrom)
|
||||
PMotion pMotion = pFromMotion;
|
||||
if (!_currentMotion.empty() || pFromMotion)
|
||||
{
|
||||
if (!pMotionFrom)
|
||||
if (!pFromMotion)
|
||||
pMotion = &_pCollection->Find(_C(_currentMotion))->_motion;
|
||||
if (_blending) // Already blending?
|
||||
pMotion->BindBlendMotion(&_blendMotion, _blendTimer / _blendDuration);
|
||||
pMotion->BindBlendMotion(&_blendMotion, Math::ApplyEasing(_easing, _blendTime / _blendDuration));
|
||||
pMotion->BakeMotionAt(_time, _blendMotion); // Capture current pose.
|
||||
pMotion->BindBlendMotion(nullptr, 0);
|
||||
}
|
||||
|
||||
if ((0 == duration._max) || (_currentMotion.empty() && name && _prevMotion == name && _blendTimer / _blendDuration < 0.5f))
|
||||
if ((0 == duration._max) || (_currentMotion.empty() && name && _prevMotion == name && _blendTime / _blendDuration < 0.5f))
|
||||
{
|
||||
_blending = false; // Special case for alpha tracks.
|
||||
}
|
||||
|
@ -200,7 +193,7 @@ void Animation::BlendTo(CSZ name, Range<float> duration, int randTime, PMotion p
|
|||
{
|
||||
_blending = true;
|
||||
_blendDuration = (_currentMotion == (name ? name : "")) ? duration._min : duration._max;
|
||||
_blendTimer = 0;
|
||||
_blendTime = 0;
|
||||
}
|
||||
|
||||
_prevMotion = _currentMotion;
|
||||
|
@ -219,16 +212,18 @@ void Animation::BlendTo(CSZ name, Range<float> duration, int randTime, PMotion p
|
|||
_time = (randTime >= 0 && pMotion) ? (randTime / 255.f) * pMotion->GetDuration() : 0;
|
||||
if (_time)
|
||||
pMotion->SkipTriggers(_time, GetTriggerStatesArray());
|
||||
|
||||
_playing = true;
|
||||
}
|
||||
|
||||
bool Animation::BlendToNew(std::initializer_list<CSZ> names, Range<float> duration, int randTime, PMotion pMotionFrom)
|
||||
bool Animation::BlendToNew(std::initializer_list<CSZ> names, Range<float> duration, int randTime, PMotion pFromMotion)
|
||||
{
|
||||
for (auto name : names)
|
||||
{
|
||||
if (_currentMotion == name)
|
||||
return false;
|
||||
}
|
||||
BlendTo(*names.begin(), duration, randTime, pMotionFrom);
|
||||
BlendTo(*names.begin(), duration, randTime, pFromMotion);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -251,7 +246,7 @@ PMotion Animation::GetMotion()
|
|||
p = &_pCollection->Find(_C(_currentMotion))->_motion;
|
||||
}
|
||||
if (p && _blending)
|
||||
p->BindBlendMotion(&_blendMotion, _blendTimer / _blendDuration);
|
||||
p->BindBlendMotion(&_blendMotion, Math::ApplyEasing(_easing, _blendTime / _blendDuration));
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -275,9 +270,9 @@ float Animation::GetAlpha(CSZ name) const
|
|||
fadeOut = matchPrevMotion && !matchCurrentMotion;
|
||||
}
|
||||
if (fadeIn)
|
||||
return Math::SmoothStep(0, 1, _blendTimer / _blendDuration);
|
||||
return Math::ApplyEasing(_easing, _blendTime / _blendDuration);
|
||||
if (fadeOut)
|
||||
return Math::SmoothStep(0, 1, 1 - _blendTimer / _blendDuration);
|
||||
return Math::ApplyEasing(_easing, 1 - _blendTime / _blendDuration);
|
||||
}
|
||||
if (name)
|
||||
return matchCurrentMotion ? 1.f : 0.f;
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace verus
|
|||
class Animation : public MotionDelegate
|
||||
{
|
||||
public:
|
||||
static const int s_maxAlphaTracks = 4;
|
||||
|
||||
enum class Edge : int
|
||||
{
|
||||
begin = (1 << 0),
|
||||
|
@ -67,9 +69,10 @@ namespace verus
|
|||
String _currentMotion;
|
||||
String _prevMotion;
|
||||
Vector<int> _vTriggerStates;
|
||||
Easing _easing = Easing::quadInOut;
|
||||
float _time = 0;
|
||||
float _blendDuration = 0;
|
||||
float _blendTimer = 0;
|
||||
float _blendTime = 0;
|
||||
bool _blending = false;
|
||||
bool _playing = false;
|
||||
|
||||
|
@ -78,12 +81,13 @@ namespace verus
|
|||
~Animation();
|
||||
|
||||
void Update(int alphaTrackCount = 0, PAlphaTrack pAlphaTracks = nullptr);
|
||||
void UpdateSkeleton(int alphaTrackCount = 0, PAlphaTrack pAlphaTracks = nullptr);
|
||||
|
||||
void BindCollection(PCollection p);
|
||||
void BindSkeleton(PSkeleton p);
|
||||
void SetCurrentMotion(CSZ name);
|
||||
PAnimationDelegate SetDelegate(PAnimationDelegate p) { return Utils::Swap(_pDelegate, p); }
|
||||
|
||||
bool IsPlaying() const { return _playing; }
|
||||
void Play();
|
||||
void Stop();
|
||||
void Pause();
|
||||
|
@ -91,11 +95,13 @@ namespace verus
|
|||
Str GetCurrentMotionName() const { return _C(_currentMotion); }
|
||||
|
||||
void BlendTo(CSZ name,
|
||||
Range<float> duration = 0.5f, int randTime = -1, PMotion pMotionFrom = nullptr);
|
||||
Range<float> duration = 0.5f, int randTime = -1, PMotion pFromMotion = nullptr);
|
||||
bool BlendToNew(std::initializer_list<CSZ> names,
|
||||
Range<float> duration = 0.5f, int randTime = -1, PMotion pMotionFrom = nullptr);
|
||||
Range<float> duration = 0.5f, int randTime = -1, PMotion pFromMotion = nullptr);
|
||||
bool IsBlending() const { return _blending; }
|
||||
|
||||
void SetEasing(Easing easing) { _easing = easing; }
|
||||
|
||||
virtual void Motion_OnTrigger(CSZ name, int state) override;
|
||||
|
||||
PMotion GetMotion();
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
using namespace verus;
|
||||
using namespace verus::Anim;
|
||||
|
||||
const float Motion::Bone::s_magicValueForCircle = 0.825f * 0.7071f * 4; // Octagon vertices will form a perfect circle.
|
||||
|
||||
// Motion::Bone::Rotation:
|
||||
|
||||
Motion::Bone::Rotation::Rotation()
|
||||
|
@ -130,9 +132,24 @@ bool Motion::Bone::FindKeyframeTrigger(int frame, int& state) const
|
|||
|
||||
void Motion::Bone::ComputeRotationAt(float time, RVector3 euler, RQuat q) const
|
||||
{
|
||||
Rotation prev, next, null(Quat(0));
|
||||
const float alpha = GetAlpha(_mapRot, prev, next, null, time);
|
||||
q = VMath::slerp(alpha, prev._q, next._q);
|
||||
int frames[4];
|
||||
Rotation keys[4];
|
||||
const float alpha = FindControlPoints(_mapRot, frames, keys, time);
|
||||
|
||||
if (_flags & Flags::slerpRot)
|
||||
{
|
||||
const Rotation null(Quat(0));
|
||||
RcRotation prev = (frames[1] == -1) ? null : keys[1];
|
||||
RcRotation next = (frames[2] == -1) ? null : keys[2];
|
||||
q = VMath::slerp(alpha, prev._q, next._q);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Rotation null(Quat(0));
|
||||
RcRotation prev = (frames[1] == -1) ? null : keys[1];
|
||||
RcRotation next = (frames[2] == -1) ? null : keys[2];
|
||||
q = Math::NLerp(alpha, prev._q, next._q);
|
||||
}
|
||||
|
||||
PMotion pBlendMotion = _pMotion->GetBlendMotion();
|
||||
if (pBlendMotion)
|
||||
|
@ -143,7 +160,12 @@ void Motion::Bone::ComputeRotationAt(float time, RVector3 euler, RQuat q) const
|
|||
Vector3 eulerBlend;
|
||||
Quat qBlend;
|
||||
if (pBone->FindKeyframeRotation(0, eulerBlend, qBlend))
|
||||
q = VMath::slerp(_pMotion->GetBlendAlpha(), qBlend, q);
|
||||
{
|
||||
if (_flags & Flags::slerpRot)
|
||||
q = VMath::slerp(_pMotion->GetBlendAlpha(), qBlend, q);
|
||||
else
|
||||
q = Math::NLerp(_pMotion->GetBlendAlpha(), qBlend, q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,9 +174,38 @@ void Motion::Bone::ComputeRotationAt(float time, RVector3 euler, RQuat q) const
|
|||
|
||||
void Motion::Bone::ComputePositionAt(float time, RVector3 pos) const
|
||||
{
|
||||
Vector3 prev, next, null(0);
|
||||
const float alpha = GetAlpha(_mapPos, prev, next, null, time);
|
||||
pos = VMath::lerp(alpha, prev, next);
|
||||
int frames[4];
|
||||
Vector3 keys[4];
|
||||
const float alpha = FindControlPoints(_mapPos, frames, keys, time);
|
||||
|
||||
if (_flags & Flags::splinePos)
|
||||
{
|
||||
const Vector3 null(0);
|
||||
if (frames[1] == -1) { frames[1] = 0; keys[1] = null; }
|
||||
if (frames[2] == -1) { frames[2] = 0; keys[2] = null; }
|
||||
// Extrapolate:
|
||||
if (frames[0] == -1) { frames[0] = frames[1] * 2 - frames[2]; keys[0] = keys[1] * 2 - keys[2]; }
|
||||
if (frames[3] == -1) { frames[3] = frames[2] * 2 - frames[1]; keys[3] = keys[2] * 2 - keys[1]; }
|
||||
// Ratio controls the direction and length of tangents. One keyframe can have different tangent lengths to match speed.
|
||||
const int intervals[3] =
|
||||
{
|
||||
frames[1] - frames[0],
|
||||
frames[2] - frames[1],
|
||||
frames[3] - frames[2]
|
||||
};
|
||||
const float ratioA = static_cast<float>(intervals[0]) / (intervals[0] + intervals[1]);
|
||||
const float ratioB = static_cast<float>(intervals[1]) / (intervals[1] + intervals[2]);
|
||||
const Vector3 tanA = VMath::lerp(ratioA, keys[1] - keys[0], keys[2] - keys[1]) * s_magicValueForCircle * (1 - ratioA);
|
||||
const Vector3 tanB = VMath::lerp(ratioB, keys[2] - keys[1], keys[3] - keys[2]) * s_magicValueForCircle * ratioB;
|
||||
pos = glm::hermite(keys[1].GLM(), tanA.GLM(), keys[2].GLM(), tanB.GLM(), alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Vector3 null(0);
|
||||
RcVector3 prev = (frames[1] == -1) ? null : keys[1];
|
||||
RcVector3 next = (frames[2] == -1) ? null : keys[2];
|
||||
pos = VMath::lerp(alpha, prev, next);
|
||||
}
|
||||
|
||||
PMotion pBlendMotion = _pMotion->GetBlendMotion();
|
||||
if (pBlendMotion)
|
||||
|
@ -171,9 +222,38 @@ void Motion::Bone::ComputePositionAt(float time, RVector3 pos) const
|
|||
|
||||
void Motion::Bone::ComputeScaleAt(float time, RVector3 scale) const
|
||||
{
|
||||
Vector3 prev, next, null(1, 1, 1);
|
||||
const float alpha = GetAlpha(_mapScale, prev, next, null, time);
|
||||
scale = VMath::lerp(alpha, prev, next);
|
||||
int frames[4];
|
||||
Vector3 keys[4];
|
||||
const float alpha = FindControlPoints(_mapScale, frames, keys, time);
|
||||
|
||||
if (_flags & Flags::splineScale)
|
||||
{
|
||||
const Vector3 null(1, 1, 1);
|
||||
if (frames[1] == -1) { frames[1] = 0; keys[1] = null; }
|
||||
if (frames[2] == -1) { frames[2] = 0; keys[2] = null; }
|
||||
// Extrapolate:
|
||||
if (frames[0] == -1) { frames[0] = frames[1] * 2 - frames[2]; keys[0] = keys[1] * 2 - keys[2]; }
|
||||
if (frames[3] == -1) { frames[3] = frames[2] * 2 - frames[1]; keys[3] = keys[2] * 2 - keys[1]; }
|
||||
// Ratio controls the direction and length of tangents. One keyframe can have different tangent lengths to match speed.
|
||||
const int intervals[3] =
|
||||
{
|
||||
frames[1] - frames[0],
|
||||
frames[2] - frames[1],
|
||||
frames[3] - frames[2]
|
||||
};
|
||||
const float ratioA = static_cast<float>(intervals[0]) / (intervals[0] + intervals[1]);
|
||||
const float ratioB = static_cast<float>(intervals[1]) / (intervals[1] + intervals[2]);
|
||||
const Vector3 tanA = VMath::lerp(ratioA, keys[1] - keys[0], keys[2] - keys[1]) * s_magicValueForCircle * (1 - ratioA);
|
||||
const Vector3 tanB = VMath::lerp(ratioB, keys[2] - keys[1], keys[3] - keys[2]) * s_magicValueForCircle * ratioB;
|
||||
scale = glm::hermite(keys[1].GLM(), tanA.GLM(), keys[2].GLM(), tanB.GLM(), alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Vector3 null(1, 1, 1);
|
||||
RcVector3 prev = (frames[1] == -1) ? null : keys[1];
|
||||
RcVector3 next = (frames[2] == -1) ? null : keys[2];
|
||||
scale = VMath::lerp(alpha, prev, next);
|
||||
}
|
||||
|
||||
PMotion pBlendMotion = _pMotion->GetBlendMotion();
|
||||
if (pBlendMotion)
|
||||
|
@ -195,7 +275,7 @@ void Motion::Bone::ComputeTriggerAt(float time, int& state) const
|
|||
state = 0;
|
||||
return;
|
||||
}
|
||||
const int frame = int(_pMotion->GetFps() * time);
|
||||
const int frame = static_cast<int>(_pMotion->GetFps() * time);
|
||||
TMapTrigger::const_iterator it = _mapTrigger.upper_bound(frame); // Find frame after 'time'.
|
||||
if (it != _mapTrigger.begin())
|
||||
{
|
||||
|
@ -211,22 +291,22 @@ void Motion::Bone::ComputeTriggerAt(float time, int& state) const
|
|||
void Motion::Bone::ComputeMatrixAt(float time, RTransform3 mat)
|
||||
{
|
||||
Quat q;
|
||||
Vector3 scale, euler, pos;
|
||||
Vector3 euler, pos, scale;
|
||||
ComputeRotationAt(time, euler, q);
|
||||
ComputePositionAt(time, pos);
|
||||
ComputeScaleAt(time, scale);
|
||||
mat = VMath::appendScale(Transform3(q, pos), scale);
|
||||
}
|
||||
|
||||
void Motion::Bone::MoveKeyframe(int direction, Type type, int frame)
|
||||
void Motion::Bone::MoveKeyframe(int direction, Channel channel, int frame)
|
||||
{
|
||||
const int frameDest = (direction >= 0) ? frame + 1 : frame - 1;
|
||||
if (frameDest < 0 || frameDest >= _pMotion->GetFrameCount())
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
switch (channel)
|
||||
{
|
||||
case Type::rotation:
|
||||
case Channel::rotation:
|
||||
{
|
||||
VERUS_IF_FOUND_IN(TMapRot, _mapRot, frame, it)
|
||||
{
|
||||
|
@ -238,7 +318,7 @@ void Motion::Bone::MoveKeyframe(int direction, Type type, int frame)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case Type::position:
|
||||
case Channel::position:
|
||||
{
|
||||
VERUS_IF_FOUND_IN(TMapPos, _mapPos, frame, it)
|
||||
{
|
||||
|
@ -250,7 +330,7 @@ void Motion::Bone::MoveKeyframe(int direction, Type type, int frame)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case Type::scale:
|
||||
case Channel::scale:
|
||||
{
|
||||
VERUS_IF_FOUND_IN(TMapScale, _mapScale, frame, it)
|
||||
{
|
||||
|
@ -262,7 +342,7 @@ void Motion::Bone::MoveKeyframe(int direction, Type type, int frame)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case Type::trigger:
|
||||
case Channel::trigger:
|
||||
{
|
||||
VERUS_IF_FOUND_IN(TMapTrigger, _mapTrigger, frame, it)
|
||||
{
|
||||
|
@ -277,8 +357,10 @@ void Motion::Bone::MoveKeyframe(int direction, Type type, int frame)
|
|||
}
|
||||
}
|
||||
|
||||
void Motion::Bone::Serialize(IO::RStream stream)
|
||||
void Motion::Bone::Serialize(IO::RStream stream, UINT16 version)
|
||||
{
|
||||
stream << _flags;
|
||||
|
||||
const int rotKeyframeCount = Utils::Cast32(_mapRot.size());
|
||||
const int posKeyframeCount = Utils::Cast32(_mapPos.size());
|
||||
const int scaleKeyframeCount = Utils::Cast32(_mapScale.size());
|
||||
|
@ -313,8 +395,12 @@ void Motion::Bone::Serialize(IO::RStream stream)
|
|||
}
|
||||
}
|
||||
|
||||
void Motion::Bone::Deserialize(IO::RStream stream)
|
||||
void Motion::Bone::Deserialize(IO::RStream stream, UINT16 version)
|
||||
{
|
||||
_flags = Flags::none;
|
||||
if (version >= 0x0102)
|
||||
stream >> _flags;
|
||||
|
||||
int rotKeyframeCount, posKeyframeCount, scaleKeyframeCount, triggerKeyframeCount, frame, state;
|
||||
Vector3 temp;
|
||||
Quat q;
|
||||
|
@ -603,6 +689,18 @@ void Motion::Bone::Scatter(int srcFrom, int srcTo, int dMin, int dMax)
|
|||
}
|
||||
}
|
||||
|
||||
bool Motion::Bone::SpaceTimeSync(Channel channel, int fromFrame, int toFrame)
|
||||
{
|
||||
if (fromFrame == toFrame) // Endpoints must not match.
|
||||
return false;
|
||||
switch (channel)
|
||||
{
|
||||
case Channel::position: return SpaceTimeSyncTemplate(_mapPos, fromFrame, toFrame);
|
||||
case Channel::scale: return SpaceTimeSyncTemplate(_mapScale, fromFrame, toFrame);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Motion::Bone::GetLastKeyframe() const
|
||||
{
|
||||
int frame = -1;
|
||||
|
@ -708,7 +806,7 @@ void Motion::Serialize(IO::RStream stream)
|
|||
{
|
||||
RBone bone = kv.second;
|
||||
stream.WriteString(_C(bone.GetName()));
|
||||
bone.Serialize(stream);
|
||||
bone.Serialize(stream, version);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,7 +819,7 @@ void Motion::Deserialize(IO::RStream stream)
|
|||
|
||||
UINT16 version = 0;
|
||||
stream >> version;
|
||||
if (s_xanVersion != version)
|
||||
if (s_xanVersion < version)
|
||||
throw VERUS_RECOVERABLE << "Deserialize(), invalid XAN version";
|
||||
|
||||
stream >> _frameCount;
|
||||
|
@ -743,7 +841,7 @@ void Motion::Deserialize(IO::RStream stream)
|
|||
{
|
||||
stream.ReadString(buffer);
|
||||
PBone pBone = InsertBone(buffer);
|
||||
pBone->Deserialize(stream);
|
||||
pBone->Deserialize(stream, version);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -902,7 +1000,7 @@ void Motion::ComputePlaybackSpeed(float duration)
|
|||
_playbackSpeedInv = 1 / _playbackSpeed;
|
||||
}
|
||||
|
||||
void Motion::Exec(CSZ code)
|
||||
void Motion::Exec(CSZ code, PBone pBone, Bone::Channel channel)
|
||||
{
|
||||
if (Str::StartsWith(code, "copy "))
|
||||
{
|
||||
|
@ -962,6 +1060,12 @@ void Motion::Exec(CSZ code)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (pBone && Str::StartsWith(code, "sts "))
|
||||
{
|
||||
int from = 0, to = 0;
|
||||
sscanf(code, "%*s %d %d", &from, &to);
|
||||
pBone->SpaceTimeSync(channel, from, to);
|
||||
}
|
||||
}
|
||||
|
||||
int Motion::GetLastKeyframe() const
|
||||
|
|
|
@ -22,8 +22,28 @@ namespace verus
|
|||
public:
|
||||
class Bone : public AllocatorAware
|
||||
{
|
||||
public:
|
||||
enum class Channel : int
|
||||
{
|
||||
rotation,
|
||||
position,
|
||||
scale,
|
||||
trigger
|
||||
};
|
||||
|
||||
enum class Flags : UINT32
|
||||
{
|
||||
none = 0,
|
||||
slerpRot = (1 << 0),
|
||||
splinePos = (1 << 1),
|
||||
splineScale = (1 << 2)
|
||||
};
|
||||
|
||||
private:
|
||||
friend class Motion;
|
||||
|
||||
static const float s_magicValueForCircle;
|
||||
|
||||
class Rotation
|
||||
{
|
||||
public:
|
||||
|
@ -47,63 +67,124 @@ namespace verus
|
|||
TMapScale _mapScale; //!< Scaling keyframes.
|
||||
TMapTrigger _mapTrigger; //!< Trigger keyframes.
|
||||
int _lastTriggerState = 0;
|
||||
Flags _flags = Flags::none;
|
||||
|
||||
template<typename TMap, typename T>
|
||||
float GetAlpha(const TMap& m, T& prev, T& next, const T& null, float time) const
|
||||
float FindControlPoints(const TMap& m, int frames[4], T keys[4], float time) const
|
||||
{
|
||||
frames[0] = frames[1] = frames[2] = frames[3] = -1;
|
||||
if (m.empty()) // No frames at all, so return null.
|
||||
{
|
||||
prev = null;
|
||||
next = null;
|
||||
return 0;
|
||||
}
|
||||
time = Math::Max(0.f, time); // Negative time is not allowed.
|
||||
float alpha;
|
||||
const int frame = static_cast<int>(_pMotion->GetFps() * time); // Frame is before or at 'time'.
|
||||
typename TMap::const_iterator it = m.upper_bound(frame); // Find frame after 'time'.
|
||||
if (it != m.end()) // There are frames greater (after 'time'):
|
||||
if (it != m.cend()) // There are frames greater (after 'time'):
|
||||
{
|
||||
if (it != m.begin()) // And there are less than (before 'time'), full interpolation:
|
||||
if (it != m.cbegin()) // And there are less than (before 'time'), full interpolation:
|
||||
{
|
||||
typename TMap::const_iterator itPrev = it;
|
||||
itPrev--;
|
||||
const float prevTime = itPrev->first * _pMotion->GetFpsInv();
|
||||
const float nextTime = it->first * _pMotion->GetFpsInv();
|
||||
const float delta = nextTime - prevTime;
|
||||
const float offset = nextTime - time;
|
||||
alpha = 1 - offset / delta;
|
||||
prev = itPrev->second;
|
||||
next = it->second;
|
||||
frames[1] = itPrev->first;
|
||||
keys[1] = itPrev->second;
|
||||
if (itPrev != m.cbegin())
|
||||
{
|
||||
itPrev--;
|
||||
frames[0] = itPrev->first;
|
||||
keys[0] = itPrev->second;
|
||||
}
|
||||
frames[2] = it->first;
|
||||
keys[2] = it->second;
|
||||
it++;
|
||||
if (it != m.cend())
|
||||
{
|
||||
frames[3] = it->first;
|
||||
keys[3] = it->second;
|
||||
}
|
||||
alpha = (time - (frames[1] * _pMotion->GetFpsInv())) / ((frames[2] - frames[1]) * _pMotion->GetFpsInv());
|
||||
}
|
||||
else // But there are no less than:
|
||||
{
|
||||
const float nextTime = it->first * _pMotion->GetFpsInv();
|
||||
const float delta = nextTime;
|
||||
const float offset = time;
|
||||
alpha = offset / delta;
|
||||
prev = null;
|
||||
next = it->second;
|
||||
frames[2] = it->first;
|
||||
keys[2] = it->second;
|
||||
it++;
|
||||
if (it != m.cend())
|
||||
{
|
||||
frames[3] = it->first;
|
||||
keys[3] = it->second;
|
||||
}
|
||||
alpha = time / (frames[2] * _pMotion->GetFpsInv());
|
||||
}
|
||||
}
|
||||
else // There are no frames greater, but there are less than:
|
||||
{
|
||||
it--;
|
||||
frames[1] = it->first;
|
||||
keys[1] = it->second;
|
||||
if (it != m.cbegin())
|
||||
{
|
||||
it--;
|
||||
frames[0] = it->first;
|
||||
keys[0] = it->second;
|
||||
}
|
||||
alpha = 0;
|
||||
prev = it->second;
|
||||
next = null;
|
||||
}
|
||||
return alpha;
|
||||
}
|
||||
|
||||
public:
|
||||
enum class Type : int
|
||||
template<typename TMap>
|
||||
static bool SpaceTimeSyncTemplate(TMap& m, int fromFrame, int toFrame)
|
||||
{
|
||||
rotation,
|
||||
position,
|
||||
scale,
|
||||
trigger
|
||||
};
|
||||
const auto itFrom = m.find(fromFrame);
|
||||
const auto itTo = m.find(toFrame);
|
||||
if (m.end() == itFrom || m.end() == itTo) // Endpoints must exist.
|
||||
return false;
|
||||
|
||||
const int totalFrames = toFrame - fromFrame;
|
||||
|
||||
auto it = itFrom;
|
||||
Vector<float> vSegments;
|
||||
vSegments.reserve(8);
|
||||
float totalDist = 0;
|
||||
while (it != itTo)
|
||||
{
|
||||
const auto& posA = it->second;
|
||||
it++;
|
||||
const auto& posB = it->second;
|
||||
const float d = VMath::dist(Point3(posA), Point3(posB));
|
||||
vSegments.push_back(d);
|
||||
totalDist += d;
|
||||
}
|
||||
if (totalDist < 1e-4f) // Distance is too small.
|
||||
return false;
|
||||
const float invTotalDist = 1.f / totalDist;
|
||||
|
||||
TMap tempMap;
|
||||
it = itFrom;
|
||||
it++;
|
||||
while (it != itTo) // Copy all keys in-between, delete original keys.
|
||||
{
|
||||
tempMap[it->first] = std::move(it->second);
|
||||
it = m.erase(it);
|
||||
}
|
||||
|
||||
it = tempMap.begin();
|
||||
float distAcc = 0;
|
||||
int i = 0;
|
||||
while (it != tempMap.end())
|
||||
{
|
||||
distAcc += vSegments[i++];
|
||||
int syncedFrame = fromFrame + static_cast<int>(totalFrames * (distAcc * invTotalDist) + 0.5f);
|
||||
while (m.end() != m.find(syncedFrame)) // Frame already occupied?
|
||||
syncedFrame++;
|
||||
m[syncedFrame] = it->second;
|
||||
it++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
Bone(Motion* pMotion = nullptr);
|
||||
~Bone();
|
||||
|
||||
|
@ -113,39 +194,46 @@ namespace verus
|
|||
int GetLastTriggerState() const { return _lastTriggerState; }
|
||||
void SetLastTriggerState(int state) { _lastTriggerState = state; }
|
||||
|
||||
Flags GetFlags() const { return _flags; }
|
||||
void SetFlags(Flags flags) { _flags = flags; }
|
||||
|
||||
void DeleteAll();
|
||||
|
||||
// Insert:
|
||||
void InsertKeyframeRotation(int frame, RcQuat q);
|
||||
void InsertKeyframeRotation(int frame, RcVector3 euler);
|
||||
void InsertKeyframePosition(int frame, RcVector3 pos);
|
||||
void InsertKeyframeScale(int frame, RcVector3 scale);
|
||||
void InsertKeyframeTrigger(int frame, int state);
|
||||
|
||||
// Delete:
|
||||
void DeleteKeyframeRotation(int frame);
|
||||
void DeleteKeyframePosition(int frame);
|
||||
void DeleteKeyframeScale(int frame);
|
||||
void DeleteKeyframeTrigger(int frame);
|
||||
|
||||
// Find:
|
||||
bool FindKeyframeRotation(int frame, RVector3 euler, RQuat q) const;
|
||||
bool FindKeyframePosition(int frame, RVector3 pos) const;
|
||||
bool FindKeyframeScale(int frame, RVector3 scale) const;
|
||||
bool FindKeyframeTrigger(int frame, int& state) const;
|
||||
|
||||
// Compute:
|
||||
void ComputeRotationAt(float time, RVector3 euler, RQuat q) const;
|
||||
void ComputePositionAt(float time, RVector3 pos) const;
|
||||
void ComputeScaleAt(float time, RVector3 scale) const;
|
||||
void ComputeTriggerAt(float time, int& state) const;
|
||||
void ComputeMatrixAt(float time, RTransform3 mat);
|
||||
|
||||
void MoveKeyframe(int direction, Type type, int frame);
|
||||
void MoveKeyframe(int direction, Channel channel, int frame);
|
||||
|
||||
int GetRotationKeyCount() const { return Utils::Cast32(_mapRot.size()); }
|
||||
int GetPositionKeyCount() const { return Utils::Cast32(_mapPos.size()); }
|
||||
int GetScaleKeyCount() const { return Utils::Cast32(_mapScale.size()); }
|
||||
int GetTriggerKeyCount() const { return Utils::Cast32(_mapTrigger.size()); }
|
||||
|
||||
VERUS_P(void Serialize(IO::RStream stream));
|
||||
VERUS_P(void Deserialize(IO::RStream stream));
|
||||
VERUS_P(void Serialize(IO::RStream stream, UINT16 version));
|
||||
VERUS_P(void Deserialize(IO::RStream stream, UINT16 version));
|
||||
|
||||
void DeleteRedundantKeyframes();
|
||||
void DeleteOddKeyframes();
|
||||
|
@ -157,12 +245,14 @@ namespace verus
|
|||
|
||||
void Scatter(int srcFrom, int srcTo, int dMin, int dMax);
|
||||
|
||||
bool SpaceTimeSync(Channel channel, int fromFrame, int toFrame);
|
||||
|
||||
int GetLastKeyframe() const;
|
||||
};
|
||||
VERUS_TYPEDEFS(Bone);
|
||||
|
||||
private:
|
||||
static const int s_xanVersion = 0x0101;
|
||||
static const int s_xanVersion = 0x0102;
|
||||
static const int s_maxFps = 10000;
|
||||
static const int s_maxBones = 10000;
|
||||
static const int s_maxFrames = 32 * 1024 * 1024;
|
||||
|
@ -171,9 +261,9 @@ namespace verus
|
|||
|
||||
TMapBones _mapBones;
|
||||
Motion* _pBlendMotion = nullptr;
|
||||
int _frameCount = 50;
|
||||
int _fps = 10;
|
||||
float _fpsInv = 0.1f;
|
||||
int _frameCount = 60;
|
||||
int _fps = 12;
|
||||
float _fpsInv = 1 / 12.f;
|
||||
float _blendAlpha = 0;
|
||||
float _playbackSpeed = 1;
|
||||
float _playbackSpeedInv = 1;
|
||||
|
@ -206,6 +296,16 @@ namespace verus
|
|||
void DeleteAllBones();
|
||||
PBone FindBone(CSZ name);
|
||||
|
||||
template<typename T>
|
||||
void ForEachBone(const T& fn)
|
||||
{
|
||||
for (auto& kv : _mapBones)
|
||||
{
|
||||
if (Continue::no == fn(kv.second))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Serialize(IO::RStream stream);
|
||||
void Deserialize(IO::RStream stream);
|
||||
|
||||
|
@ -233,7 +333,7 @@ namespace verus
|
|||
void ComputePlaybackSpeed(float duration);
|
||||
bool IsReversed() const { return _reversed; }
|
||||
|
||||
void Exec(CSZ code);
|
||||
void Exec(CSZ code, PBone pBone = nullptr, Bone::Channel channel = Bone::Channel::rotation);
|
||||
|
||||
int GetLastKeyframe() const;
|
||||
};
|
||||
|
|
|
@ -117,14 +117,14 @@ namespace verus
|
|||
void ForEachBone(const F& fn)
|
||||
{
|
||||
for (auto& kv : _mapBones)
|
||||
if (Continue::yes != fn(kv.second))
|
||||
if (Continue::no == fn(kv.second))
|
||||
return;
|
||||
}
|
||||
template<typename F>
|
||||
void ForEachBone(const F& fn) const
|
||||
{
|
||||
for (const auto& kv : _mapBones)
|
||||
if (Continue::yes != fn(kv.second))
|
||||
if (Continue::no == fn(kv.second))
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,108 @@
|
|||
using namespace verus;
|
||||
using namespace verus::App;
|
||||
|
||||
// QualitySettings:
|
||||
|
||||
bool QualitySettings::operator==(RcQualitySettings that) const
|
||||
{
|
||||
return
|
||||
_displayOffscreenDraw == that._displayOffscreenDraw &&
|
||||
_displayOffscreenScale == that._displayOffscreenScale &&
|
||||
_gpuAnisotropyLevel == that._gpuAnisotropyLevel &&
|
||||
_gpuAntialiasingLevel == that._gpuAntialiasingLevel &&
|
||||
_gpuShaderQuality == that._gpuShaderQuality &&
|
||||
_gpuTessellation == that._gpuTessellation &&
|
||||
_gpuTextureLodLevel == that._gpuTextureLodLevel &&
|
||||
_gpuTrilinearFilter == that._gpuTrilinearFilter &&
|
||||
_postProcessBloom == that._postProcessBloom &&
|
||||
_postProcessCinema == that._postProcessCinema &&
|
||||
_postProcessLightShafts == that._postProcessLightShafts &&
|
||||
_postProcessMotionBlur == that._postProcessMotionBlur &&
|
||||
_postProcessSSAO == that._postProcessSSAO &&
|
||||
_postProcessSSR == that._postProcessSSR &&
|
||||
_sceneAmbientOcclusion == that._sceneAmbientOcclusion &&
|
||||
_sceneGrassDensity == that._sceneGrassDensity &&
|
||||
_sceneShadowQuality == that._sceneShadowQuality &&
|
||||
_sceneWaterQuality == that._sceneWaterQuality;
|
||||
}
|
||||
|
||||
void QualitySettings::SetQuality(OverallQuality q)
|
||||
{
|
||||
if (OverallQuality::custom == q)
|
||||
return;
|
||||
|
||||
*this = QualitySettings(); // Start with medium.
|
||||
|
||||
switch (q)
|
||||
{
|
||||
case OverallQuality::low:
|
||||
_gpuAnisotropyLevel = 2;
|
||||
_gpuShaderQuality = Quality::low;
|
||||
_gpuTrilinearFilter = false;
|
||||
_postProcessBloom = false;
|
||||
_postProcessLightShafts = false;
|
||||
_postProcessSSAO = false;
|
||||
_sceneGrassDensity = 600;
|
||||
_sceneShadowQuality = Quality::low;
|
||||
_sceneWaterQuality = WaterQuality::solidColor;
|
||||
break;
|
||||
case OverallQuality::medium:
|
||||
break;
|
||||
case OverallQuality::high:
|
||||
_gpuAnisotropyLevel = 8;
|
||||
_gpuShaderQuality = Quality::high;
|
||||
_postProcessCinema = true;
|
||||
_sceneAmbientOcclusion = true;
|
||||
_sceneGrassDensity = 900;
|
||||
_sceneShadowQuality = Quality::high;
|
||||
_sceneWaterQuality = WaterQuality::trueWavesReflection;
|
||||
break;
|
||||
case OverallQuality::ultra:
|
||||
_gpuAnisotropyLevel = 16;
|
||||
_gpuShaderQuality = Quality::ultra;
|
||||
_postProcessCinema = true;
|
||||
_postProcessMotionBlur = true;
|
||||
_postProcessSSR = true;
|
||||
_sceneAmbientOcclusion = true;
|
||||
_sceneGrassDensity = 1000;
|
||||
_sceneShadowQuality = Quality::ultra;
|
||||
_sceneWaterQuality = WaterQuality::trueWavesRefraction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QualitySettings::OverallQuality QualitySettings::DetectQuality() const
|
||||
{
|
||||
QualitySettings reference;
|
||||
|
||||
reference.SetQuality(OverallQuality::low);
|
||||
if (*this == reference)
|
||||
return OverallQuality::low;
|
||||
|
||||
reference.SetQuality(OverallQuality::medium);
|
||||
if (*this == reference)
|
||||
return OverallQuality::medium;
|
||||
|
||||
reference.SetQuality(OverallQuality::high);
|
||||
if (*this == reference)
|
||||
return OverallQuality::high;
|
||||
|
||||
reference.SetQuality(OverallQuality::ultra);
|
||||
if (*this == reference)
|
||||
return OverallQuality::ultra;
|
||||
|
||||
return OverallQuality::custom;
|
||||
}
|
||||
|
||||
// Settings:
|
||||
|
||||
Settings::Settings()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (0x419 == GetUserDefaultUILanguage())
|
||||
_uiLang = "RU";
|
||||
#endif
|
||||
SetQuality(Quality::medium);
|
||||
SetQuality(OverallQuality::medium);
|
||||
}
|
||||
|
||||
Settings::~Settings()
|
||||
|
@ -47,6 +142,8 @@ void Settings::ParseCommandLineArgs(int argc, char* argv[])
|
|||
_commandLine._windowed = true;
|
||||
if (IsArg(i, "--bwnd"))
|
||||
_commandLine._borderlessWindowed = true;
|
||||
if (IsArg(i, "--restarted"))
|
||||
_commandLine._restarted = true;
|
||||
}
|
||||
|
||||
SetFilename("Settings.json");
|
||||
|
@ -57,73 +154,30 @@ void Settings::ParseCommandLineArgs(int argc, char* argv[])
|
|||
if (IsArg(i, "--q-low"))
|
||||
{
|
||||
const bool ret = IO::FileSystem::Delete(_C(pathname));
|
||||
SetQuality(Quality::low);
|
||||
SetQuality(OverallQuality::low);
|
||||
}
|
||||
if (IsArg(i, "--q-medium"))
|
||||
{
|
||||
const bool ret = IO::FileSystem::Delete(_C(pathname));
|
||||
SetQuality(Quality::medium);
|
||||
SetQuality(OverallQuality::medium);
|
||||
}
|
||||
if (IsArg(i, "--q-high"))
|
||||
{
|
||||
const bool ret = IO::FileSystem::Delete(_C(pathname));
|
||||
SetQuality(Quality::high);
|
||||
SetQuality(OverallQuality::high);
|
||||
}
|
||||
if (IsArg(i, "--q-ultra"))
|
||||
{
|
||||
const bool ret = IO::FileSystem::Delete(_C(pathname));
|
||||
SetQuality(Quality::ultra);
|
||||
SetQuality(OverallQuality::ultra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::SetQuality(Quality q)
|
||||
{
|
||||
_quality = q;
|
||||
|
||||
switch (q)
|
||||
{
|
||||
case Quality::low:
|
||||
_gpuAnisotropyLevel = 2;
|
||||
_gpuShaderQuality = Quality::low;
|
||||
_gpuTrilinearFilter = false;
|
||||
_postProcessBloom = false;
|
||||
_postProcessGodRays = false;
|
||||
_postProcessSSAO = false;
|
||||
_sceneGrassDensity = 600;
|
||||
_sceneShadowQuality = Quality::low;
|
||||
_sceneWaterQuality = WaterQuality::solidColor;
|
||||
break;
|
||||
case Quality::medium:
|
||||
break;
|
||||
case Quality::high:
|
||||
_gpuAnisotropyLevel = 8;
|
||||
_gpuShaderQuality = Quality::high;
|
||||
_postProcessCinema = true;
|
||||
_sceneAmbientOcclusion = true;
|
||||
_sceneGrassDensity = 900;
|
||||
_sceneShadowQuality = Quality::high;
|
||||
_sceneWaterQuality = WaterQuality::trueWavesReflection;
|
||||
break;
|
||||
case Quality::ultra:
|
||||
_gpuAnisotropyLevel = 16;
|
||||
_gpuShaderQuality = Quality::ultra;
|
||||
_postProcessCinema = true;
|
||||
_postProcessMotionBlur = true;
|
||||
_postProcessSSR = true;
|
||||
_sceneAmbientOcclusion = true;
|
||||
_sceneGrassDensity = 1000;
|
||||
_sceneShadowQuality = Quality::ultra;
|
||||
_sceneWaterQuality = WaterQuality::trueWavesRefraction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::Load()
|
||||
{
|
||||
Json::Load();
|
||||
|
||||
_quality = static_cast<Quality>(GetI("quality", +_quality));
|
||||
_displayAllowHighDPI = GetB("displayAllowHighDPI", _displayAllowHighDPI);
|
||||
_displayFOV = GetF("displayFOV", _displayFOV);
|
||||
_displayMode = static_cast<DisplayMode>(GetI("displayMode", +_displayMode));
|
||||
|
@ -142,7 +196,7 @@ void Settings::Load()
|
|||
_inputMouseSensitivity = GetF("inputMouseSensitivity", _inputMouseSensitivity);
|
||||
_postProcessBloom = GetB("postProcessBloom", _postProcessBloom);
|
||||
_postProcessCinema = GetB("postProcessCinema", _postProcessCinema);
|
||||
_postProcessGodRays = GetB("postProcessGodRays", _postProcessGodRays);
|
||||
_postProcessLightShafts = GetB("postProcessLightShafts", _postProcessLightShafts);
|
||||
_postProcessMotionBlur = GetB("postProcessMotionBlur", _postProcessMotionBlur);
|
||||
_postProcessSSAO = GetB("postProcessSSAO", _postProcessSSAO);
|
||||
_postProcessSSR = GetB("postProcessSSR", _postProcessSSR);
|
||||
|
@ -173,7 +227,7 @@ void Settings::HandleCommandLineArgs()
|
|||
{
|
||||
switch (_commandLine._gapi)
|
||||
{
|
||||
case 0: _gapi = 0; break;
|
||||
case 0: _gapi = 0; break;
|
||||
case 12: _gapi = 12; break;
|
||||
}
|
||||
|
||||
|
@ -185,8 +239,8 @@ void Settings::HandleCommandLineArgs()
|
|||
if (_commandLine._windowed)
|
||||
{
|
||||
_displayMode = DisplayMode::windowed;
|
||||
_displaySizeHeight = 720;
|
||||
_displaySizeWidth = 1280;
|
||||
_displaySizeHeight = 720;
|
||||
}
|
||||
if (_commandLine._borderlessWindowed)
|
||||
{
|
||||
|
@ -197,10 +251,9 @@ void Settings::HandleCommandLineArgs()
|
|||
|
||||
void Settings::Validate()
|
||||
{
|
||||
_quality = Math::Clamp(_quality, Quality::low, Quality::ultra);
|
||||
_displayFOV = Math::Clamp<float>(_displayFOV, 60, 90);
|
||||
_displaySizeHeight = Math::Clamp(_displaySizeHeight, 270, 0x2000);
|
||||
_displaySizeWidth = Math::Clamp(_displaySizeWidth, 480, 0x2000);
|
||||
_displaySizeHeight = Math::Clamp(_displaySizeHeight, 270, 0x2000);
|
||||
_gpuAnisotropyLevel = Math::Clamp(_gpuAnisotropyLevel, 0, 16);
|
||||
_gpuAntialiasingLevel = Math::Clamp(_gpuAntialiasingLevel, 0, 16);
|
||||
_gpuShaderQuality = Math::Clamp(_gpuShaderQuality, Quality::low, Quality::ultra);
|
||||
|
@ -217,7 +270,6 @@ void Settings::Save()
|
|||
{
|
||||
Clear();
|
||||
|
||||
Set("quality", +_quality);
|
||||
Set("displayAllowHighDPI", _displayAllowHighDPI);
|
||||
Set("displayFOV", _displayFOV);
|
||||
Set("displayMode", +_displayMode);
|
||||
|
@ -236,7 +288,7 @@ void Settings::Save()
|
|||
Set("inputMouseSensitivity", _inputMouseSensitivity);
|
||||
Set("postProcessBloom", _postProcessBloom);
|
||||
Set("postProcessCinema", _postProcessCinema);
|
||||
Set("postProcessGodRays", _postProcessGodRays);
|
||||
Set("postProcessLightShafts", _postProcessLightShafts);
|
||||
Set("postProcessMotionBlur", _postProcessMotionBlur);
|
||||
Set("postProcessSSAO", _postProcessSSAO);
|
||||
Set("postProcessSSR", _postProcessSSR);
|
||||
|
|
|
@ -12,6 +12,62 @@ namespace verus
|
|||
borderlessWindowed
|
||||
};
|
||||
|
||||
class QualitySettings
|
||||
{
|
||||
public:
|
||||
enum class OverallQuality : int
|
||||
{
|
||||
custom,
|
||||
low,
|
||||
medium,
|
||||
high,
|
||||
ultra
|
||||
};
|
||||
|
||||
enum class Quality : int
|
||||
{
|
||||
low,
|
||||
medium,
|
||||
high,
|
||||
ultra
|
||||
};
|
||||
|
||||
enum class WaterQuality : int
|
||||
{
|
||||
solidColor,
|
||||
simpleReflection,
|
||||
distortedReflection,
|
||||
trueWavesReflection,
|
||||
trueWavesRefraction
|
||||
};
|
||||
|
||||
public:
|
||||
bool _displayOffscreenDraw = true;
|
||||
float _displayOffscreenScale = 1;
|
||||
int _gpuAnisotropyLevel = 4;
|
||||
int _gpuAntialiasingLevel = 0;
|
||||
Quality _gpuShaderQuality = Quality::medium;
|
||||
bool _gpuTessellation = false;
|
||||
int _gpuTextureLodLevel = 0;
|
||||
bool _gpuTrilinearFilter = true;
|
||||
bool _postProcessBloom = true;
|
||||
bool _postProcessCinema = false;
|
||||
bool _postProcessLightShafts = true;
|
||||
bool _postProcessMotionBlur = false;
|
||||
bool _postProcessSSAO = true;
|
||||
bool _postProcessSSR = false;
|
||||
bool _sceneAmbientOcclusion = false;
|
||||
int _sceneGrassDensity = 800;
|
||||
Quality _sceneShadowQuality = Quality::medium;
|
||||
WaterQuality _sceneWaterQuality = WaterQuality::solidColor;
|
||||
|
||||
bool operator==(const QualitySettings& that) const;
|
||||
|
||||
void SetQuality(OverallQuality q);
|
||||
OverallQuality DetectQuality() const;
|
||||
};
|
||||
VERUS_TYPEDEFS(QualitySettings);
|
||||
|
||||
// Capacity is per frame. 3 frames are buffered.
|
||||
class Limits
|
||||
{
|
||||
|
@ -49,7 +105,7 @@ namespace verus
|
|||
};
|
||||
VERUS_TYPEDEFS(Limits);
|
||||
|
||||
class Settings : public Singleton<Settings>, IO::Json
|
||||
class Settings : public QualitySettings, public Singleton<Settings>, IO::Json
|
||||
{
|
||||
typedef Map<String, String> TMapLocalizedStrings;
|
||||
|
||||
|
@ -62,23 +118,7 @@ namespace verus
|
|||
bool _exclusiveFullscreen = false;
|
||||
bool _windowed = false;
|
||||
bool _borderlessWindowed = false;
|
||||
};
|
||||
|
||||
enum class Quality : int
|
||||
{
|
||||
low,
|
||||
medium,
|
||||
high,
|
||||
ultra
|
||||
};
|
||||
|
||||
enum class WaterQuality : int
|
||||
{
|
||||
solidColor,
|
||||
simpleReflection,
|
||||
distortedReflection,
|
||||
trueWavesReflection,
|
||||
trueWavesRefraction
|
||||
bool _restarted = false;
|
||||
};
|
||||
|
||||
enum Platform : int
|
||||
|
@ -87,47 +127,27 @@ namespace verus
|
|||
uwp
|
||||
};
|
||||
|
||||
Quality _quality = Quality::medium;
|
||||
bool _displayAllowHighDPI = true;
|
||||
float _displayFOV = 70;
|
||||
DisplayMode _displayMode = DisplayMode::windowed;
|
||||
bool _displayOffscreenDraw = true;
|
||||
float _displayOffscreenScale = 1;
|
||||
int _displaySizeHeight = 720;
|
||||
int _displaySizeWidth = 1280;
|
||||
bool _displayVSync = true;
|
||||
int _gapi = 0;
|
||||
int _gpuAnisotropyLevel = 4;
|
||||
int _gpuAntialiasingLevel = 0;
|
||||
Quality _gpuShaderQuality = Quality::medium;
|
||||
bool _gpuTessellation = false;
|
||||
int _gpuTextureLodLevel = 0;
|
||||
bool _gpuTrilinearFilter = true;
|
||||
float _inputMouseSensitivity = 1;
|
||||
bool _physicsSupportDebugDraw = false;
|
||||
bool _postProcessBloom = true;
|
||||
bool _postProcessCinema = false;
|
||||
bool _postProcessGodRays = true;
|
||||
bool _postProcessMotionBlur = false;
|
||||
bool _postProcessSSAO = true;
|
||||
bool _postProcessSSR = false;
|
||||
bool _sceneAmbientOcclusion = false;
|
||||
int _sceneGrassDensity = 800;
|
||||
Quality _sceneShadowQuality = Quality::medium;
|
||||
WaterQuality _sceneWaterQuality = WaterQuality::solidColor;
|
||||
String _uiLang = "EN";
|
||||
CommandLine _commandLine;
|
||||
Limits _limits;
|
||||
String _imguiFont;
|
||||
float _highDpiScale = 1;
|
||||
Platform _platform = Platform::classic;
|
||||
bool _displayAllowHighDPI = true;
|
||||
float _displayFOV = 70;
|
||||
DisplayMode _displayMode = DisplayMode::windowed;
|
||||
int _displaySizeHeight = 720;
|
||||
int _displaySizeWidth = 1280;
|
||||
bool _displayVSync = true;
|
||||
int _gapi = 0;
|
||||
float _inputMouseSensitivity = 1;
|
||||
bool _physicsSupportDebugDraw = false;
|
||||
String _uiLang = "EN";
|
||||
CommandLine _commandLine;
|
||||
Limits _limits;
|
||||
String _imguiFont;
|
||||
float _highDpiScale = 1;
|
||||
Platform _platform = Platform::classic;
|
||||
|
||||
Settings();
|
||||
~Settings();
|
||||
|
||||
void ParseCommandLineArgs(int argc, wchar_t* argv[]);
|
||||
void ParseCommandLineArgs(int argc, char* argv[]);
|
||||
void SetQuality(Quality q);
|
||||
|
||||
void Load();
|
||||
void HandleHighDpi();
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace verus
|
|||
int i = 0;
|
||||
for (auto& x : _vCommands)
|
||||
{
|
||||
if (Continue::yes != fn(x, i < _nextUndo))
|
||||
if (Continue::no == fn(x, i < _nextUndo))
|
||||
return;
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -112,6 +112,7 @@ void StreamPlayer::Update()
|
|||
|
||||
void StreamPlayer::AddTrack(PTrack pTrack)
|
||||
{
|
||||
VERUS_RT_ASSERT(IsInitialized());
|
||||
{
|
||||
VERUS_LOCK(*this);
|
||||
_vTracks.push_back(pTrack);
|
||||
|
|
|
@ -139,15 +139,18 @@ bool DebugDraw::AddPoint(
|
|||
bool DebugDraw::AddLine(
|
||||
RcPoint3 posA,
|
||||
RcPoint3 posB,
|
||||
UINT32 color)
|
||||
UINT32 colorA,
|
||||
UINT32 colorB)
|
||||
{
|
||||
if (!colorB)
|
||||
colorB = colorA;
|
||||
const int at = _offset + _vertCount;
|
||||
if (at + 2 > _maxVerts)
|
||||
return false;
|
||||
posA.ToArray3(_vDynamicBuffer[at]._pos);
|
||||
Utils::CopyColor(_vDynamicBuffer[at]._color, color);
|
||||
Utils::CopyColor(_vDynamicBuffer[at]._color, colorA);
|
||||
posB.ToArray3(_vDynamicBuffer[at + 1]._pos);
|
||||
Utils::CopyColor(_vDynamicBuffer[at + 1]._color, color);
|
||||
Utils::CopyColor(_vDynamicBuffer[at + 1]._color, colorB);
|
||||
_vertCount += 2;
|
||||
_peakLoad = Math::Max(_peakLoad, at + 2);
|
||||
return true;
|
||||
|
|
|
@ -64,7 +64,8 @@ namespace verus
|
|||
bool AddLine(
|
||||
RcPoint3 posA,
|
||||
RcPoint3 posB,
|
||||
UINT32 color);
|
||||
UINT32 colorA,
|
||||
UINT32 colorB = 0);
|
||||
bool AddTriangle(
|
||||
RcPoint3 posA,
|
||||
RcPoint3 posB,
|
||||
|
|
|
@ -24,7 +24,7 @@ bool Renderer::IsLoaded()
|
|||
return IsValidSingleton() && !!I()._pBaseRenderer;
|
||||
}
|
||||
|
||||
void Renderer::Init(PRendererDelegate pDelegate)
|
||||
void Renderer::Init(PRendererDelegate pDelegate, bool allowInitShaders)
|
||||
{
|
||||
VERUS_INIT();
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
|
@ -34,6 +34,10 @@ void Renderer::Init(PRendererDelegate pDelegate)
|
|||
|
||||
_pRendererDelegate = pDelegate;
|
||||
|
||||
_allowInitShaders = allowInitShaders;
|
||||
|
||||
VERUS_RT_ASSERT(_allowInitShaders || !settings._displayOffscreenDraw);
|
||||
|
||||
CSZ dll = "RendererVulkan.dll";
|
||||
switch (settings._gapi)
|
||||
{
|
||||
|
@ -54,10 +58,11 @@ void Renderer::Init(PRendererDelegate pDelegate)
|
|||
_commandBuffer.Init();
|
||||
|
||||
// Draw directly to swap chain buffer:
|
||||
const RP::Attachment::LoadOp loadOp = settings._displayOffscreenDraw ? RP::Attachment::LoadOp::dontCare : RP::Attachment::LoadOp::clear;
|
||||
const RP::Attachment::LoadOp colorLoadOp = settings._displayOffscreenDraw ? RP::Attachment::LoadOp::dontCare : RP::Attachment::LoadOp::clear;
|
||||
const RP::Attachment::LoadOp depthLoadOp = settings._displayOffscreenDraw ? RP::Attachment::LoadOp::load : RP::Attachment::LoadOp::clear;
|
||||
_rphSwapChain = _pBaseRenderer->CreateRenderPass(
|
||||
{
|
||||
RP::Attachment("Color", Format::srgbB8G8R8A8).SetLoadOp(loadOp).Layout(ImageLayout::undefined, ImageLayout::presentSrc)
|
||||
RP::Attachment("Color", Format::srgbB8G8R8A8).SetLoadOp(colorLoadOp).Layout(ImageLayout::undefined, ImageLayout::presentSrc)
|
||||
},
|
||||
{
|
||||
RP::Subpass("Sp0").Color({RP::Ref("Color", ImageLayout::colorAttachment)})
|
||||
|
@ -65,8 +70,8 @@ void Renderer::Init(PRendererDelegate pDelegate)
|
|||
{});
|
||||
_rphSwapChainWithDepth = _pBaseRenderer->CreateRenderPass(
|
||||
{
|
||||
RP::Attachment("Color", Format::srgbB8G8R8A8).SetLoadOp(loadOp).Layout(ImageLayout::undefined, ImageLayout::presentSrc),
|
||||
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilAttachment),
|
||||
RP::Attachment("Color", Format::srgbB8G8R8A8).SetLoadOp(colorLoadOp).Layout(ImageLayout::undefined, ImageLayout::presentSrc),
|
||||
RP::Attachment("Depth", Format::unormD24uintS8).SetLoadOp(depthLoadOp).Layout(ImageLayout::depthStencilAttachment),
|
||||
},
|
||||
{
|
||||
RP::Subpass("Sp0").Color(
|
||||
|
@ -109,32 +114,37 @@ void Renderer::Init(PRendererDelegate pDelegate)
|
|||
geoDesc._pStrides = strides;
|
||||
_geoQuad.Init(geoDesc);
|
||||
|
||||
_shader[SHADER_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl");
|
||||
_shader[SHADER_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), settings.GetLimits()._generateMips_ubCapacity,
|
||||
{
|
||||
Sampler::linearClampMipN,
|
||||
Sampler::storage,
|
||||
Sampler::storage,
|
||||
Sampler::storage,
|
||||
Sampler::storage
|
||||
},
|
||||
ShaderStageFlags::cs);
|
||||
_shader[SHADER_GENERATE_MIPS]->CreatePipelineLayout();
|
||||
if (_allowInitShaders)
|
||||
{
|
||||
_shader[SHADER_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl");
|
||||
_shader[SHADER_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), settings.GetLimits()._generateMips_ubCapacity,
|
||||
{
|
||||
Sampler::linearClampMipN,
|
||||
Sampler::storage,
|
||||
Sampler::storage,
|
||||
Sampler::storage,
|
||||
Sampler::storage
|
||||
},
|
||||
ShaderStageFlags::cs);
|
||||
_shader[SHADER_GENERATE_MIPS]->CreatePipelineLayout();
|
||||
|
||||
_shader[SHADER_QUAD].Init("[Shaders]:Quad.hlsl");
|
||||
_shader[SHADER_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), settings.GetLimits()._quad_ubVSCapacity, {}, ShaderStageFlags::vs);
|
||||
_shader[SHADER_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), settings.GetLimits()._quad_ubFSCapacity, { Sampler::linearClampMipN }, ShaderStageFlags::fs);
|
||||
_shader[SHADER_QUAD]->CreatePipelineLayout();
|
||||
_shader[SHADER_QUAD].Init("[Shaders]:Quad.hlsl");
|
||||
_shader[SHADER_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), settings.GetLimits()._quad_ubVSCapacity, {}, ShaderStageFlags::vs);
|
||||
_shader[SHADER_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), settings.GetLimits()._quad_ubFSCapacity, { Sampler::linearClampMipN }, ShaderStageFlags::fs);
|
||||
_shader[SHADER_QUAD]->CreatePipelineLayout();
|
||||
}
|
||||
|
||||
if (_allowInitShaders)
|
||||
{
|
||||
PipelineDesc pipeDesc(_shader[SHADER_GENERATE_MIPS], "#");
|
||||
_pipe[PIPE_GENERATE_MIPS].Init(pipeDesc);
|
||||
}
|
||||
if (_allowInitShaders)
|
||||
{
|
||||
PipelineDesc pipeDesc(_shader[SHADER_GENERATE_MIPS], "#Exposure");
|
||||
_pipe[PIPE_GENERATE_MIPS_EXPOSURE].Init(pipeDesc);
|
||||
}
|
||||
if (App::Settings::I()._displayOffscreenDraw)
|
||||
if (settings._displayOffscreenDraw)
|
||||
{
|
||||
PipelineDesc pipeDesc(_geoQuad, _shader[SHADER_QUAD], "#", _rphSwapChainWithDepth);
|
||||
pipeDesc._topology = PrimitiveTopology::triangleStrip;
|
||||
|
@ -147,7 +157,8 @@ void Renderer::Init(PRendererDelegate pDelegate)
|
|||
_pBaseRenderer->ImGuiInit(_rphSwapChainWithDepth);
|
||||
ImGuiUpdateStyle();
|
||||
|
||||
_ds.Init();
|
||||
if (_allowInitShaders)
|
||||
_ds.Init();
|
||||
|
||||
SetExposureValue(15);
|
||||
}
|
||||
|
@ -258,12 +269,18 @@ bool Renderer::OnWindowSizeChanged(int w, int h)
|
|||
_pBaseRenderer->ResizeSwapChain();
|
||||
|
||||
OnSwapChainResized(true, true);
|
||||
_ds.OnSwapChainResized(true, true);
|
||||
Scene::Water::I().OnSwapChainResized();
|
||||
Effects::Bloom::I().OnSwapChainResized();
|
||||
Effects::Ssao::I().OnSwapChainResized();
|
||||
Effects::Ssr::I().OnSwapChainResized();
|
||||
Effects::Blur::I().OnSwapChainResized();
|
||||
if (_ds.IsInitialized())
|
||||
_ds.OnSwapChainResized(true, true);
|
||||
if (Scene::Water::IsValidSingleton())
|
||||
Scene::Water::I().OnSwapChainResized();
|
||||
if (Effects::Bloom::IsValidSingleton())
|
||||
Effects::Bloom::I().OnSwapChainResized();
|
||||
if (Effects::Ssao::IsValidSingleton())
|
||||
Effects::Ssao::I().OnSwapChainResized();
|
||||
if (Effects::Ssr::IsValidSingleton())
|
||||
Effects::Ssr::I().OnSwapChainResized();
|
||||
if (Effects::Blur::IsValidSingleton())
|
||||
Effects::Blur::I().OnSwapChainResized();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -272,7 +289,8 @@ void Renderer::OnSwapChainResized(bool init, bool done)
|
|||
{
|
||||
if (done)
|
||||
{
|
||||
_shader[SHADER_QUAD]->FreeDescriptorSet(_cshOffscreenColor);
|
||||
if (_shader[SHADER_QUAD])
|
||||
_shader[SHADER_QUAD]->FreeDescriptorSet(_cshOffscreenColor);
|
||||
|
||||
_pBaseRenderer->DeleteFramebuffer(_fbhOffscreenWithDepth);
|
||||
_pBaseRenderer->DeleteFramebuffer(_fbhOffscreen);
|
||||
|
|
|
@ -84,6 +84,7 @@ namespace verus
|
|||
UB_QuadVS _ubQuadVS;
|
||||
UB_QuadFS _ubQuadFS;
|
||||
bool _autoExposure = true;
|
||||
bool _allowInitShaders = true;
|
||||
bool _showUtilization = false;
|
||||
|
||||
public:
|
||||
|
@ -94,7 +95,7 @@ namespace verus
|
|||
PBaseRenderer operator->();
|
||||
static bool IsLoaded();
|
||||
|
||||
void Init(PRendererDelegate pDelegate);
|
||||
void Init(PRendererDelegate pDelegate, bool allowInitShaders = true);
|
||||
void InitCmd();
|
||||
void Done();
|
||||
|
||||
|
|
|
@ -120,8 +120,9 @@ namespace verus
|
|||
enum class Sampler : int
|
||||
{
|
||||
custom, // Not immutable, not static sampler.
|
||||
storage, // Also known as UAV.
|
||||
input,
|
||||
storage, // Also known as UAV.
|
||||
lodBias,
|
||||
shadow,
|
||||
aniso, // Most common sampler for 3D.
|
||||
anisoClamp,
|
||||
|
|
|
@ -6,6 +6,8 @@ using namespace verus::D;
|
|||
|
||||
void Log::Write(CSZ txt, std::thread::id tid, CSZ filename, UINT32 line, Severity severity)
|
||||
{
|
||||
if (strstr(txt, "VUID-VkMappedMemoryRange-size-01389"))
|
||||
return;
|
||||
if (strstr(txt, "VUID-StandaloneSpirv-Offset-04663"))
|
||||
return;
|
||||
if (strstr(txt, "UNASSIGNED-BestPractices-vkAllocateMemory-small-allocation"))
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
using namespace verus;
|
||||
using namespace verus::Effects;
|
||||
|
||||
Bloom::UB_BloomVS Bloom::s_ubBloomVS;
|
||||
Bloom::UB_BloomFS Bloom::s_ubBloomFS;
|
||||
Bloom::UB_BloomGodRaysFS Bloom::s_ubBloomGodRaysFS;
|
||||
Bloom::UB_BloomVS Bloom::s_ubBloomVS;
|
||||
Bloom::UB_BloomFS Bloom::s_ubBloomFS;
|
||||
Bloom::UB_BloomLightShaftsFS Bloom::s_ubBloomLightShaftsFS;
|
||||
|
||||
Bloom::Bloom()
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ void Bloom::Init()
|
|||
}
|
||||
|
||||
_rph = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
|
||||
_rphGodRays = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8, CGI::RP::Attachment::LoadOp::load);
|
||||
_rphLightShafts = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8, CGI::RP::Attachment::LoadOp::load);
|
||||
|
||||
_shader.Init("[Shaders]:Bloom.hlsl");
|
||||
_shader->CreateDescriptorSet(0, &s_ubBloomVS, sizeof(s_ubBloomVS), 4, {}, CGI::ShaderStageFlags::vs);
|
||||
|
@ -38,7 +38,7 @@ void Bloom::Init()
|
|||
{
|
||||
CGI::Sampler::linearClampMipN
|
||||
}, CGI::ShaderStageFlags::fs);
|
||||
_shader->CreateDescriptorSet(2, &s_ubBloomGodRaysFS, sizeof(s_ubBloomGodRaysFS), 4,
|
||||
_shader->CreateDescriptorSet(2, &s_ubBloomLightShaftsFS, sizeof(s_ubBloomLightShaftsFS), 4,
|
||||
{
|
||||
CGI::Sampler::linearClampMipN,
|
||||
CGI::Sampler::shadow
|
||||
|
@ -51,13 +51,13 @@ void Bloom::Init()
|
|||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_MAIN].Init(pipeDesc);
|
||||
}
|
||||
if (settings._postProcessGodRays)
|
||||
if (settings._postProcessLightShafts)
|
||||
{
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#GodRays", _rphGodRays);
|
||||
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#LightShafts", _rphLightShafts);
|
||||
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
|
||||
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
|
||||
pipeDesc.DisableDepthTest();
|
||||
_pipe[PIPE_GOD_RAYS].Init(pipeDesc);
|
||||
_pipe[PIPE_LIGHT_SHAFTS].Init(pipeDesc);
|
||||
}
|
||||
|
||||
OnSwapChainResized();
|
||||
|
@ -73,14 +73,14 @@ void Bloom::InitByAtmosphere(CGI::TexturePtr texShadow)
|
|||
|
||||
_texAtmoShadow = texShadow;
|
||||
|
||||
_cshGodRays = _shader->BindDescriptorSetTextures(2, { renderer.GetTexDepthStencil(), _texAtmoShadow });
|
||||
_cshLightShafts = _shader->BindDescriptorSetTextures(2, { renderer.GetTexDepthStencil(), _texAtmoShadow });
|
||||
}
|
||||
|
||||
void Bloom::Done()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
renderer->DeleteFramebuffer(_fbh);
|
||||
renderer->DeleteRenderPass(_rphGodRays);
|
||||
renderer->DeleteRenderPass(_rphLightShafts);
|
||||
renderer->DeleteRenderPass(_rph);
|
||||
VERUS_DONE(Bloom);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ void Bloom::OnSwapChainResized()
|
|||
return;
|
||||
|
||||
{
|
||||
_shader->FreeDescriptorSet(_cshGodRays);
|
||||
_shader->FreeDescriptorSet(_cshLightShafts);
|
||||
_shader->FreeDescriptorSet(_csh);
|
||||
renderer->DeleteFramebuffer(_fbh);
|
||||
_tex.Done();
|
||||
|
@ -141,7 +141,7 @@ void Bloom::Generate()
|
|||
ImGui::DragFloat("Bloom (god rays) wideStrength", &_wideStrength, 0.01f);
|
||||
ImGui::DragFloat("Bloom (god rays) sunStrength", &_sunStrength, 0.01f);
|
||||
ImGui::Checkbox("Bloom blur", &_blur);
|
||||
ImGui::Checkbox("Bloom (god rays) blur", &_blurGodRays);
|
||||
ImGui::Checkbox("Bloom (light shafts) blur", &_blurLightShafts);
|
||||
}
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
|
@ -166,39 +166,39 @@ void Bloom::Generate()
|
|||
if (_blur)
|
||||
Blur::I().GenerateForBloom(false);
|
||||
|
||||
if (settings._postProcessGodRays)
|
||||
if (settings._postProcessLightShafts)
|
||||
{
|
||||
s_ubBloomGodRaysFS._matInvVP = Matrix4(VMath::inverse(sm.GetMainCamera()->GetMatrixVP())).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
|
||||
s_ubBloomGodRaysFS._sunColor = float4(atmo.GetSunColor().GLM(), 0);
|
||||
s_ubBloomGodRaysFS._eyePos = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.x = _maxDist;
|
||||
s_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.y = _sunGloss;
|
||||
s_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.z = _wideStrength;
|
||||
s_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.w = _sunStrength;
|
||||
s_ubBloomGodRaysFS._matShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._matScreenCSM = atmo.GetShadowMap().GetScreenMatrixVP().UniformBufferFormat();
|
||||
s_ubBloomGodRaysFS._csmSplitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
memcpy(&s_ubBloomGodRaysFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubBloomGodRaysFS._shadowConfig));
|
||||
s_ubBloomLightShaftsFS._matInvVP = Matrix4(VMath::inverse(sm.GetMainCamera()->GetMatrixVP())).UniformBufferFormat();
|
||||
s_ubBloomLightShaftsFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
|
||||
s_ubBloomLightShaftsFS._sunColor = float4(atmo.GetSunColor().GLM(), 0);
|
||||
s_ubBloomLightShaftsFS._eyePos = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
|
||||
s_ubBloomLightShaftsFS._maxDist_sunGloss_wideStrength_sunStrength.x = _maxDist;
|
||||
s_ubBloomLightShaftsFS._maxDist_sunGloss_wideStrength_sunStrength.y = _sunGloss;
|
||||
s_ubBloomLightShaftsFS._maxDist_sunGloss_wideStrength_sunStrength.z = _wideStrength;
|
||||
s_ubBloomLightShaftsFS._maxDist_sunGloss_wideStrength_sunStrength.w = _sunStrength;
|
||||
s_ubBloomLightShaftsFS._matShadow = atmo.GetShadowMap().GetShadowMatrix(0).UniformBufferFormat();
|
||||
s_ubBloomLightShaftsFS._matShadowCSM1 = atmo.GetShadowMap().GetShadowMatrix(1).UniformBufferFormat();
|
||||
s_ubBloomLightShaftsFS._matShadowCSM2 = atmo.GetShadowMap().GetShadowMatrix(2).UniformBufferFormat();
|
||||
s_ubBloomLightShaftsFS._matShadowCSM3 = atmo.GetShadowMap().GetShadowMatrix(3).UniformBufferFormat();
|
||||
s_ubBloomLightShaftsFS._matScreenCSM = atmo.GetShadowMap().GetScreenMatrixVP().UniformBufferFormat();
|
||||
s_ubBloomLightShaftsFS._csmSplitRanges = atmo.GetShadowMap().GetSplitRanges().GLM();
|
||||
memcpy(&s_ubBloomLightShaftsFS._shadowConfig, &atmo.GetShadowMap().GetConfig(), sizeof(s_ubBloomLightShaftsFS._shadowConfig));
|
||||
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
|
||||
cb->BeginRenderPass(_rphGodRays, _fbh, { _tex[TEX_PING]->GetClearValue() });
|
||||
cb->BeginRenderPass(_rphLightShafts, _fbh, { _tex[TEX_PING]->GetClearValue() });
|
||||
|
||||
cb->BindPipeline(_pipe[PIPE_GOD_RAYS]);
|
||||
cb->BindPipeline(_pipe[PIPE_LIGHT_SHAFTS]);
|
||||
_shader->BeginBindDescriptors();
|
||||
cb->BindDescriptors(_shader, 0);
|
||||
cb->BindDescriptors(_shader, 1, _csh);
|
||||
cb->BindDescriptors(_shader, 2, _cshGodRays);
|
||||
cb->BindDescriptors(_shader, 2, _cshLightShafts);
|
||||
_shader->EndBindDescriptors();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
cb->EndRenderPass();
|
||||
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
|
||||
|
||||
if (_blurGodRays)
|
||||
if (_blurLightShafts)
|
||||
Blur::I().GenerateForBloom(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace verus
|
|||
enum PIPE
|
||||
{
|
||||
PIPE_MAIN,
|
||||
PIPE_GOD_RAYS,
|
||||
PIPE_LIGHT_SHAFTS,
|
||||
PIPE_COUNT
|
||||
};
|
||||
|
||||
|
@ -23,19 +23,19 @@ namespace verus
|
|||
TEX_COUNT
|
||||
};
|
||||
|
||||
static UB_BloomVS s_ubBloomVS;
|
||||
static UB_BloomFS s_ubBloomFS;
|
||||
static UB_BloomGodRaysFS s_ubBloomGodRaysFS;
|
||||
static UB_BloomVS s_ubBloomVS;
|
||||
static UB_BloomFS s_ubBloomFS;
|
||||
static UB_BloomLightShaftsFS s_ubBloomLightShaftsFS;
|
||||
|
||||
CGI::ShaderPwn _shader;
|
||||
CGI::PipelinePwns<PIPE_COUNT> _pipe;
|
||||
CGI::TexturePwns<TEX_COUNT> _tex;
|
||||
CGI::TexturePtr _texAtmoShadow;
|
||||
CGI::RPHandle _rph;
|
||||
CGI::RPHandle _rphGodRays;
|
||||
CGI::RPHandle _rphLightShafts;
|
||||
CGI::FBHandle _fbh;
|
||||
CGI::CSHandle _csh;
|
||||
CGI::CSHandle _cshGodRays;
|
||||
CGI::CSHandle _cshLightShafts;
|
||||
float _colorScale = 0.8f;
|
||||
float _colorBias = 1.1f;
|
||||
float _maxDist = 20;
|
||||
|
@ -43,7 +43,7 @@ namespace verus
|
|||
float _wideStrength = 0.2f;
|
||||
float _sunStrength = 0.3f;
|
||||
bool _blur = true;
|
||||
bool _blurGodRays = true;
|
||||
bool _blurLightShafts = true;
|
||||
bool _editMode = false;
|
||||
|
||||
public:
|
||||
|
|
|
@ -274,7 +274,7 @@ void Blur::Generate()
|
|||
{
|
||||
}
|
||||
|
||||
void Blur::GenerateForBloom(bool forGodRays)
|
||||
void Blur::GenerateForBloom(bool forLightShafts)
|
||||
{
|
||||
VERUS_QREF_BLOOM;
|
||||
VERUS_QREF_CONST_SETTINGS;
|
||||
|
@ -283,10 +283,10 @@ void Blur::GenerateForBloom(bool forGodRays)
|
|||
if (bloom.IsEditMode())
|
||||
{
|
||||
ImGui::DragFloat("Bloom blur radius", &_bloomRadius, 0.001f);
|
||||
ImGui::DragFloat("Bloom (god rays) blur radius", &_bloomGodRaysRadius, 0.001f);
|
||||
ImGui::DragFloat("Bloom (god rays) blur radius", &_bloomLightShaftsRadius, 0.001f);
|
||||
}
|
||||
|
||||
const float radius = forGodRays ? _bloomGodRaysRadius : _bloomRadius;
|
||||
const float radius = forLightShafts ? _bloomLightShaftsRadius : _bloomRadius;
|
||||
float samplesPerPixel = 1;
|
||||
int maxSamples = 1;
|
||||
switch (settings._gpuShaderQuality)
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace verus
|
|||
CGI::CSHandle _cshMotionBlur;
|
||||
CGI::CSHandle _cshMotionBlurExtra;
|
||||
float _bloomRadius = 0.015f;
|
||||
float _bloomGodRaysRadius = 0.004f;
|
||||
float _bloomLightShaftsRadius = 0.004f;
|
||||
float _dofFocusDist = 10;
|
||||
float _dofBlurStrength = 0.2f;
|
||||
float _ssrRadius = 0.025f;
|
||||
|
@ -78,7 +78,7 @@ namespace verus
|
|||
void OnSwapChainResized();
|
||||
|
||||
void Generate();
|
||||
void GenerateForBloom(bool forGodRays);
|
||||
void GenerateForBloom(bool forLightShafts);
|
||||
void GenerateForDepthOfField();
|
||||
void GenerateForSsao();
|
||||
void GenerateForSsr();
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#include "verus.h"
|
||||
|
||||
using namespace verus;
|
||||
using namespace verus::GUI;
|
||||
|
||||
Bars::Bars()
|
||||
{
|
||||
}
|
||||
|
||||
Bars::~Bars()
|
||||
{
|
||||
}
|
||||
|
||||
PWidget Bars::Make()
|
||||
{
|
||||
return new Bars;
|
||||
}
|
||||
|
||||
void Bars::Update()
|
||||
{
|
||||
Widget::Update();
|
||||
}
|
||||
|
||||
void Bars::Draw()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_VM;
|
||||
|
||||
const float currentAspectRatio = renderer.GetSwapChainAspectRatio();
|
||||
const float barsRatio = Math::Max(0.f, 1 - (1 / _aspectRatio * currentAspectRatio));
|
||||
if (!barsRatio)
|
||||
return;
|
||||
|
||||
const float barRatio = barsRatio * 0.5f;
|
||||
float x, y;
|
||||
GetAbsolutePosition(x, y);
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
auto shader = vm.GetShader();
|
||||
auto& ubGui = vm.GetUbGui();
|
||||
auto& ubGuiFS = vm.GetUbGuiFS();
|
||||
|
||||
ubGuiFS._color = GetColor().GLM();
|
||||
|
||||
vm.BindPipeline(ViewManager::PIPE_SOLID_COLOR, cb);
|
||||
shader->BeginBindDescriptors();
|
||||
|
||||
ubGui._matW = Math::QuadMatrix(x, y, GetW(), GetH() * barRatio).UniformBufferFormat();
|
||||
cb->BindDescriptors(shader, 0);
|
||||
cb->BindDescriptors(shader, 1, vm.GetDefaultComplexSetHandle());
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
ubGui._matW = Math::QuadMatrix(x, y + GetH() * (1 - barRatio), GetW(), GetH() * barRatio).UniformBufferFormat();
|
||||
cb->BindDescriptors(shader, 0);
|
||||
cb->BindDescriptors(shader, 1, vm.GetDefaultComplexSetHandle());
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
shader->EndBindDescriptors();
|
||||
}
|
||||
|
||||
void Bars::Parse(pugi::xml_node node)
|
||||
{
|
||||
Widget::Parse(node);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (C) 2021, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
|
||||
#pragma once
|
||||
|
||||
namespace verus
|
||||
{
|
||||
namespace GUI
|
||||
{
|
||||
class Bars : public Widget
|
||||
{
|
||||
float _aspectRatio = 21 / 9.f;
|
||||
|
||||
public:
|
||||
Bars();
|
||||
virtual ~Bars();
|
||||
|
||||
static PWidget Make();
|
||||
|
||||
virtual void Update() override;
|
||||
virtual void Draw() override;
|
||||
virtual void Parse(pugi::xml_node node) override;
|
||||
};
|
||||
VERUS_TYPEDEFS(Bars);
|
||||
}
|
||||
}
|
|
@ -18,12 +18,13 @@ Container::~Container()
|
|||
|
||||
void Container::RegisterAll()
|
||||
{
|
||||
RegisterWidget("button", Button::Make);
|
||||
RegisterWidget("image", Image::Make);
|
||||
RegisterWidget("label", Label::Make);
|
||||
RegisterWidget("sizer", Sizer::Make);
|
||||
RegisterWidget("table", Table::Make);
|
||||
RegisterWidget("textBox", TextBox::Make);
|
||||
RegisterWidget("bars", &Bars::Make);
|
||||
RegisterWidget("button", &Button::Make);
|
||||
RegisterWidget("image", &Image::Make);
|
||||
RegisterWidget("label", &Label::Make);
|
||||
RegisterWidget("sizer", &Sizer::Make);
|
||||
RegisterWidget("table", &Table::Make);
|
||||
RegisterWidget("textBox", &TextBox::Make);
|
||||
}
|
||||
|
||||
void Container::RegisterWidget(CSZ type, PFNCREATOR pCreator)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "Image.h"
|
||||
#include "Button.h"
|
||||
#include "Table.h"
|
||||
#include "Bars.h"
|
||||
#include "Cursor.h"
|
||||
#include "ViewManager.h"
|
||||
#include "ViewController.h"
|
||||
|
|
|
@ -99,7 +99,7 @@ void Image::Draw()
|
|||
cb->BindDescriptors(shader, 0);
|
||||
cb->BindDescriptors(shader, 1, _solidColor ? vm.GetDefaultComplexSetHandle() : _csh);
|
||||
shader->EndBindDescriptors();
|
||||
renderer.DrawQuad();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
}
|
||||
|
||||
void Image::Parse(pugi::xml_node node)
|
||||
|
|
|
@ -70,7 +70,7 @@ void Table::Draw()
|
|||
cb->BindDescriptors(shader, 0);
|
||||
cb->BindDescriptors(shader, 1, vm.GetDefaultComplexSetHandle());
|
||||
shader->EndBindDescriptors();
|
||||
renderer.DrawQuad();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
}
|
||||
|
||||
VERUS_FOR(i, _cols)
|
||||
|
|
|
@ -57,7 +57,7 @@ void TextBox::Draw()
|
|||
cb->BindDescriptors(shader, 0);
|
||||
cb->BindDescriptors(shader, 1, vm.GetDefaultComplexSetHandle());
|
||||
shader->EndBindDescriptors();
|
||||
renderer.DrawQuad();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ void View::Parse(pugi::xml_node node)
|
|||
_cursor = node.attribute("cursor").as_bool(_cursor);
|
||||
_debug = node.attribute("debug").as_bool(_debug);
|
||||
_fadeSpeed = node.attribute("fadeSpeed").as_float(_fadeSpeed);
|
||||
_locale = node.attribute("forceLocale").as_string(_C(_locale));
|
||||
|
||||
CSZ bg = node.attribute("bg").value();
|
||||
if (strlen(bg) > 0)
|
||||
|
@ -223,7 +224,7 @@ void View::OnKey(int scancode)
|
|||
return;
|
||||
|
||||
const bool handled = InvokeOnKey(scancode);
|
||||
#ifdef _DEBUG
|
||||
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
|
||||
if (handled && scancode == SDL_SCANCODE_F5)
|
||||
return; // Reloaded, this pointer is invalid.
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,7 @@ void ViewController::Init(CSZ url)
|
|||
_pView = ViewManager::I().ParseView(url);
|
||||
_pView->SetDelegate(this);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
|
||||
ConnectOnKey(VERUS_EVENT_HANDLER(&ViewController::OnKey));
|
||||
#endif
|
||||
}
|
||||
|
@ -90,8 +90,20 @@ void ViewController::BeginFadeTo()
|
|||
ViewManager::I().BeginFadeTo(_C(_pView->GetName()));
|
||||
}
|
||||
|
||||
void ViewController::Activate()
|
||||
{
|
||||
ViewManager::I().Activate(_C(_pView->GetName()));
|
||||
}
|
||||
|
||||
void ViewController::Deactivate()
|
||||
{
|
||||
ViewManager::I().Deactivate(_C(_pView->GetName()));
|
||||
}
|
||||
|
||||
void ViewController::OnKey(RcEventArgs args)
|
||||
{
|
||||
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
|
||||
if (args._char == SDL_SCANCODE_F5)
|
||||
Reload();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace verus
|
|||
void ConnectOnTimeout /**/(TFnEvent fn, CSZ id = nullptr);
|
||||
|
||||
void BeginFadeTo();
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
|
||||
virtual void View_SetViewData(PView pView) override {}
|
||||
virtual void View_GetViewData(PView pView) override {}
|
||||
|
|
|
@ -213,23 +213,13 @@ void ViewManager::MsgBox(CSZ txt, int data)
|
|||
{
|
||||
if (txt) // Display MessageBox:
|
||||
{
|
||||
PView pView = GetViewByName("UI/MsgBox.xml");
|
||||
pView->Disable(false);
|
||||
pView->Show();
|
||||
pView->SetData();
|
||||
pView->ResetAnimators();
|
||||
pView->SetState(View::State::active);
|
||||
MoveToFront("UI/MsgBox.xml");
|
||||
PView pView = Activate("UI/MsgBox.xml");
|
||||
PLabel pLabel = static_cast<PLabel>(pView->GetWidgetById("MsgBoxText"));
|
||||
pLabel->SetText(txt);
|
||||
}
|
||||
else // Restore original view:
|
||||
{
|
||||
PView pView = GetViewByName("UI/MsgBox.xml");
|
||||
pView->Disable();
|
||||
pView->Hide();
|
||||
pView->SetState(View::State::done);
|
||||
MoveToBack("UI/MsgBox.xml");
|
||||
PView pView = Deactivate("UI/MsgBox.xml");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,6 +313,28 @@ void ViewManager::BeginFadeOut()
|
|||
}
|
||||
}
|
||||
|
||||
PView ViewManager::Activate(CSZ viewName)
|
||||
{
|
||||
PView pView = GetViewByName(viewName);
|
||||
pView->Disable(false);
|
||||
pView->Show();
|
||||
pView->SetData();
|
||||
pView->ResetAnimators();
|
||||
pView->SetState(View::State::active);
|
||||
MoveToFront(viewName);
|
||||
return pView;
|
||||
}
|
||||
|
||||
PView ViewManager::Deactivate(CSZ viewName)
|
||||
{
|
||||
PView pView = GetViewByName(viewName);
|
||||
pView->Disable();
|
||||
pView->Hide();
|
||||
pView->SetState(View::State::done);
|
||||
MoveToBack(viewName);
|
||||
return pView;
|
||||
}
|
||||
|
||||
bool ViewManager::HasAllViewsInDoneState()
|
||||
{
|
||||
for (const auto& pView : _vViews)
|
||||
|
|
|
@ -77,6 +77,8 @@ namespace verus
|
|||
PView MoveToBack /**/(CSZ viewName);
|
||||
PView BeginFadeTo /**/(CSZ viewName = ":VOID:");
|
||||
void BeginFadeOut();
|
||||
PView Activate(CSZ viewName);
|
||||
PView Deactivate(CSZ viewName);
|
||||
bool HasAllViewsInDoneState();
|
||||
bool HasSomeViewsInFadeState();
|
||||
VERUS_P(bool SwitchView());
|
||||
|
|
|
@ -83,7 +83,7 @@ void Widget::DrawInputStyle()
|
|||
cb->BindDescriptors(shader, 0);
|
||||
cb->BindDescriptors(shader, 1, vm.GetDefaultComplexSetHandle());
|
||||
shader->EndBindDescriptors();
|
||||
renderer.DrawQuad();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
}
|
||||
|
||||
void Widget::Update()
|
||||
|
|
|
@ -36,6 +36,23 @@ bool ActiveMechanics::HandleInput()
|
|||
|
||||
bool ActiveMechanics::Update()
|
||||
{
|
||||
bool popped = false;
|
||||
VERUS_WHILE(Vector<PMechanics>, _vStack, it)
|
||||
{
|
||||
if ((*it)->CanAutoPop())
|
||||
{
|
||||
popped = true;
|
||||
(*it)->OnEnd();
|
||||
it = _vStack.erase(it);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
if (popped)
|
||||
{
|
||||
std::sort(_vStack.begin(), _vStack.end());
|
||||
ActiveMechanics_OnChanged();
|
||||
}
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
{
|
||||
if (Continue::no == (*it)->Update())
|
||||
|
@ -54,6 +71,16 @@ bool ActiveMechanics::Draw()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ActiveMechanics::DrawOverlay()
|
||||
{
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
{
|
||||
if (Continue::no == (*it)->DrawOverlay())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ActiveMechanics::ApplyReport(const void* pReport)
|
||||
{
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
|
@ -70,6 +97,36 @@ bool ActiveMechanics::GetBotDomainCenter(int id, RPoint3 center)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ActiveMechanics::GetSpawnPosition(int id, RPoint3 pos)
|
||||
{
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
{
|
||||
if (Continue::no == (*it)->GetSpawnPosition(id, pos))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ActiveMechanics::IsInputEnabled()
|
||||
{
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
{
|
||||
if (!(*it)->IsInputEnabled())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActiveMechanics::OnDie(int id)
|
||||
{
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
{
|
||||
if (Continue::no == (*it)->OnDie(id))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ActiveMechanics::OnMouseMove(float x, float y)
|
||||
{
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
|
@ -80,6 +137,16 @@ bool ActiveMechanics::OnMouseMove(float x, float y)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ActiveMechanics::OnTakeDamage(int id, float amount)
|
||||
{
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
{
|
||||
if (Continue::no == (*it)->OnTakeDamage(id, amount))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ActiveMechanics::UpdateMultiplayer()
|
||||
{
|
||||
for (auto it = _vStack.begin(); it != _vStack.end(); ++it)
|
||||
|
|
|
@ -19,10 +19,15 @@ namespace verus
|
|||
bool HandleInput();
|
||||
bool Update();
|
||||
bool Draw();
|
||||
bool DrawOverlay();
|
||||
|
||||
void ApplyReport(const void* pReport);
|
||||
bool GetBotDomainCenter(int id, RPoint3 center);
|
||||
bool GetSpawnPosition(int id, RPoint3 pos);
|
||||
bool IsInputEnabled();
|
||||
bool OnDie(int id);
|
||||
bool OnMouseMove(float x, float y);
|
||||
bool OnTakeDamage(int id, float amount);
|
||||
bool UpdateMultiplayer();
|
||||
Scene::PMainCamera GetMainCamera();
|
||||
|
||||
|
|
|
@ -69,6 +69,9 @@ BaseGame::~BaseGame()
|
|||
Free_D();
|
||||
Utils::FreeEx(&_alloc);
|
||||
SDL_Quit();
|
||||
|
||||
if (_restartApp)
|
||||
RestartApp();
|
||||
}
|
||||
|
||||
void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc desc)
|
||||
|
@ -110,12 +113,14 @@ void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc desc)
|
|||
VERUS_QREF_MM;
|
||||
_p->_camera.SetAspectRatio(renderer.GetSwapChainAspectRatio());
|
||||
_p->_camera.Update();
|
||||
sm.SetCamera(&_p->_camera);
|
||||
if (Scene::SceneManager::IsValidSingleton())
|
||||
Scene::SceneManager::I().SetCamera(&_p->_camera);
|
||||
|
||||
renderer->BeginFrame(false); // Begin recording a command buffer.
|
||||
renderer.InitCmd();
|
||||
_engineInit.InitCmd();
|
||||
mm.InitCmd();
|
||||
if (Scene::MaterialManager::IsValidSingleton())
|
||||
Scene::MaterialManager::I().InitCmd();
|
||||
BaseGame_LoadContent();
|
||||
renderer->EndFrame(false); // End recording a command buffer.
|
||||
renderer->Sync(false);
|
||||
|
@ -124,11 +129,8 @@ void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc desc)
|
|||
void BaseGame::Run(bool relativeMouseMode)
|
||||
{
|
||||
VERUS_QREF_ASYNC;
|
||||
VERUS_QREF_ASYS;
|
||||
VERUS_QREF_BULLET;
|
||||
VERUS_QREF_KM;
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_SM;
|
||||
VERUS_QREF_TIMER;
|
||||
|
||||
if (relativeMouseMode)
|
||||
|
@ -207,7 +209,7 @@ void BaseGame::Run(bool relativeMouseMode)
|
|||
{
|
||||
if (renderer.OnWindowSizeChanged(event.window.data1, event.window.data2))
|
||||
{
|
||||
Scene::PCamera pCamera = sm.GetCamera();
|
||||
Scene::PCamera pCamera = Scene::SceneManager::IsValidSingleton() ? Scene::SceneManager::I().GetCamera() : nullptr;
|
||||
if (pCamera)
|
||||
{
|
||||
pCamera->SetAspectRatio(renderer.GetSwapChainAspectRatio());
|
||||
|
@ -247,7 +249,7 @@ void BaseGame::Run(bool relativeMouseMode)
|
|||
if (_p->_escapeKeyExitGame && km.IsKeyDownEvent(SDL_SCANCODE_ESCAPE))
|
||||
Exit();
|
||||
|
||||
if (_p->_minimized)
|
||||
if (_p->_minimized || _restartApp)
|
||||
continue;
|
||||
|
||||
//
|
||||
|
@ -272,9 +274,13 @@ void BaseGame::Run(bool relativeMouseMode)
|
|||
if (km.IsKeyPressed(SDL_SCANCODE_D))
|
||||
_p->_cameraSpirit.MoveSide(speed);
|
||||
}
|
||||
BaseGame_HandleInput();
|
||||
|
||||
bullet.Simulate();
|
||||
BaseGame_HandleInput();
|
||||
if (_restartApp)
|
||||
continue;
|
||||
|
||||
if (Physics::Bullet::IsValidSingleton())
|
||||
Physics::Bullet::I().Simulate();
|
||||
|
||||
if (_p->_defaultCameraMovement)
|
||||
{
|
||||
|
@ -289,12 +295,16 @@ void BaseGame::Run(bool relativeMouseMode)
|
|||
_p->_camera.ExcludeWaterLine();
|
||||
}
|
||||
_p->_camera.Update();
|
||||
sm.SetCamera(&_p->_camera);
|
||||
if (Scene::SceneManager::IsValidSingleton())
|
||||
Scene::SceneManager::I().SetCamera(&_p->_camera);
|
||||
}
|
||||
|
||||
BaseGame_Update();
|
||||
if (_restartApp)
|
||||
continue;
|
||||
|
||||
asys.Update();
|
||||
if (Audio::AudioSystem::IsValidSingleton())
|
||||
Audio::AudioSystem::I().Update();
|
||||
|
||||
// Draw current frame:
|
||||
renderer.Draw();
|
||||
|
@ -415,3 +425,39 @@ float BaseGame::GetMouseScale()
|
|||
const float rad = (VERUS_2PI / 360.f) / 3.f; // 3 pixels = 1 degree.
|
||||
return rad * settings._inputMouseSensitivity;
|
||||
}
|
||||
|
||||
void BaseGame::RestartApp()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
wchar_t pathname[MAX_PATH] = {};
|
||||
GetModuleFileName(nullptr, pathname, MAX_PATH);
|
||||
|
||||
wchar_t commandLine[MAX_PATH] = {};
|
||||
wcscpy_s(commandLine, L"--restarted");
|
||||
|
||||
STARTUPINFO si = {};
|
||||
PROCESS_INFORMATION pi = {};
|
||||
si.cb = sizeof(si);
|
||||
|
||||
CreateProcess(
|
||||
pathname,
|
||||
commandLine,
|
||||
nullptr,
|
||||
nullptr,
|
||||
FALSE,
|
||||
CREATE_NEW_PROCESS_GROUP,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&si,
|
||||
&pi);
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BaseGame::RequestAppRestart()
|
||||
{
|
||||
_restartApp = true;
|
||||
Exit();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace verus
|
|||
AlignedAllocator _alloc;
|
||||
EngineInit _engineInit;
|
||||
App::Window _window;
|
||||
bool _restartApp = false;
|
||||
|
||||
public:
|
||||
BaseGame();
|
||||
|
@ -27,7 +28,7 @@ namespace verus
|
|||
virtual void BaseGame_HandleInput() = 0;
|
||||
virtual void BaseGame_Update() = 0;
|
||||
virtual void BaseGame_Draw() = 0;
|
||||
virtual void BaseGame_DrawOverlay() = 0;
|
||||
virtual void BaseGame_DrawOverlay() {}
|
||||
virtual void BaseGame_OnWindowSizeChanged() {}
|
||||
virtual void BaseGame_OnActivated() {}
|
||||
virtual void BaseGame_OnDeactivated() {}
|
||||
|
@ -67,6 +68,9 @@ namespace verus
|
|||
void BulletDebugDraw();
|
||||
|
||||
static float GetMouseScale();
|
||||
|
||||
void RestartApp();
|
||||
void RequestAppRestart();
|
||||
};
|
||||
VERUS_TYPEDEFS(BaseGame);
|
||||
}
|
||||
|
|
|
@ -4,12 +4,546 @@
|
|||
using namespace verus;
|
||||
using namespace verus::Game;
|
||||
|
||||
// Cutscene::Command:
|
||||
|
||||
void Cutscene::Command::Parse(pugi::xml_node node)
|
||||
{
|
||||
_url = node.attribute("url").value();
|
||||
|
||||
CSZ delay = node.attribute("delay").value();
|
||||
if ('^' == *delay)
|
||||
{
|
||||
_prevDelay = static_cast<float>(atof(delay + 1));
|
||||
_delay = FLT_MAX;
|
||||
}
|
||||
else if (']' == *delay)
|
||||
{
|
||||
_endDelay = static_cast<float>(atof(delay + 1));
|
||||
_delay = FLT_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
_delay = static_cast<float>(atof(delay));
|
||||
}
|
||||
|
||||
_duration = node.attribute("duration").as_float(_duration);
|
||||
}
|
||||
|
||||
bool Cutscene::Command::Update()
|
||||
{
|
||||
const float time = GetTime();
|
||||
if (time >= _duration)
|
||||
{
|
||||
OnEnd();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cutscene::Command::UpdatePrevDelay(float newActiveDuration)
|
||||
{
|
||||
if (_prevDelay != FLT_MAX)
|
||||
{
|
||||
const float delay = newActiveDuration + _prevDelay;
|
||||
_delay = (FLT_MAX == _delay) ? delay : Math::Max(_delay, delay);
|
||||
}
|
||||
}
|
||||
|
||||
void Cutscene::Command::UpdateEndDelay(float newActiveDuration)
|
||||
{
|
||||
if (_endDelay != FLT_MAX)
|
||||
{
|
||||
const float delay = newActiveDuration + _endDelay;
|
||||
_delay = (FLT_MAX == _delay) ? delay : Math::Max(_delay, delay);
|
||||
}
|
||||
}
|
||||
|
||||
void Cutscene::Command::LimitActiveDuration(float limit)
|
||||
{
|
||||
VERUS_RT_ASSERT(_delay != FLT_MAX && _duration != FLT_MAX);
|
||||
const float activeDuration = _delay + _duration;
|
||||
const float diff = activeDuration - limit;
|
||||
if (diff > 0)
|
||||
{
|
||||
const float newDuration = _duration - diff;
|
||||
_duration = Math::Max(0.f, newDuration);
|
||||
if (newDuration < 0)
|
||||
_delay += newDuration;
|
||||
}
|
||||
}
|
||||
|
||||
// Cutscene::BarrierCommand:
|
||||
|
||||
Cutscene::PCommand Cutscene::BarrierCommand::Make()
|
||||
{
|
||||
return new BarrierCommand;
|
||||
}
|
||||
|
||||
// Cutscene::CameraCommand:
|
||||
|
||||
Cutscene::CameraCommand::~CameraCommand()
|
||||
{
|
||||
IO::Async::Cancel(this);
|
||||
}
|
||||
|
||||
Cutscene::PCommand Cutscene::CameraCommand::Make()
|
||||
{
|
||||
return new CameraCommand;
|
||||
}
|
||||
|
||||
void Cutscene::CameraCommand::Parse(pugi::xml_node node)
|
||||
{
|
||||
Command::Parse(node);
|
||||
|
||||
_duration = FLT_MAX;
|
||||
IO::Async::I().Load(_C(_url), this);
|
||||
}
|
||||
|
||||
bool Cutscene::CameraCommand::Update()
|
||||
{
|
||||
if (IsDelayed() || FLT_MAX == _duration)
|
||||
return true;
|
||||
|
||||
const float time = GetTime();
|
||||
if (time >= _duration)
|
||||
{
|
||||
OnEnd();
|
||||
return false;
|
||||
}
|
||||
|
||||
_motion.ProcessTriggers(time, this);
|
||||
|
||||
_pCutscene->_camera.ApplyMotion(_C(_cameraName), _motion, time);
|
||||
|
||||
if (!_pCutscene->_pCurrentCameraCommand)
|
||||
_pCutscene->_pCurrentCameraCommand = this;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cutscene::CameraCommand::OnBegin()
|
||||
{
|
||||
Command::OnBegin();
|
||||
|
||||
if (!_pCutscene->_pCurrentCameraCommand)
|
||||
_pCutscene->_pCurrentCameraCommand = this;
|
||||
}
|
||||
|
||||
void Cutscene::CameraCommand::OnEnd()
|
||||
{
|
||||
Command::OnEnd();
|
||||
|
||||
if (this == _pCutscene->_pCurrentCameraCommand)
|
||||
_pCutscene->_pCurrentCameraCommand = nullptr;
|
||||
}
|
||||
|
||||
void Cutscene::CameraCommand::Async_Run(CSZ url, RcBlob blob)
|
||||
{
|
||||
IO::StreamPtr sp(blob);
|
||||
_motion.Init();
|
||||
_motion.Deserialize(sp);
|
||||
_duration = _motion.GetDuration();
|
||||
if (_active)
|
||||
_pCutscene->OnNewActiveDuration(_delay + _duration);
|
||||
}
|
||||
|
||||
void Cutscene::CameraCommand::Motion_OnTrigger(CSZ name, int state)
|
||||
{
|
||||
if (!Str::StartsWith(name, "Camera."))
|
||||
return;
|
||||
if (state & 0x1)
|
||||
{
|
||||
_cameraName = name;
|
||||
_pCutscene->_camera.CutMotionBlur();
|
||||
}
|
||||
}
|
||||
|
||||
// Cutscene::ConfigCommand:
|
||||
|
||||
Cutscene::PCommand Cutscene::ConfigCommand::Make()
|
||||
{
|
||||
return new ConfigCommand;
|
||||
}
|
||||
|
||||
void Cutscene::ConfigCommand::Parse(pugi::xml_node node)
|
||||
{
|
||||
Command::Parse(node);
|
||||
|
||||
_tag = node.attribute("tag").as_int(_tag);
|
||||
_callOnEnd = node.attribute("callOnEnd").as_bool(_callOnEnd);
|
||||
_skipHere = node.attribute("skipHere").as_bool(_skipHere);
|
||||
}
|
||||
|
||||
void Cutscene::ConfigCommand::OnBegin()
|
||||
{
|
||||
if (_callOnEnd)
|
||||
{
|
||||
if (_pCutscene->_fnOnEnd)
|
||||
_pCutscene->_fnOnEnd(_tag); // Tag 1 and above means called from config command.
|
||||
}
|
||||
}
|
||||
|
||||
// Cutscene::FadeCommand:
|
||||
|
||||
Cutscene::PCommand Cutscene::FadeCommand::Make()
|
||||
{
|
||||
return new FadeCommand;
|
||||
}
|
||||
|
||||
void Cutscene::FadeCommand::Parse(pugi::xml_node node)
|
||||
{
|
||||
Command::Parse(node);
|
||||
|
||||
_from.FromColorString(node.attribute("from").value());
|
||||
_to.FromColorString(node.attribute("to").value());
|
||||
_easing = Math::EasingFromString(node.attribute("easing").value());
|
||||
_skipHere = node.attribute("skipHere").as_bool(_skipHere);
|
||||
}
|
||||
|
||||
bool Cutscene::FadeCommand::DrawOverlay()
|
||||
{
|
||||
if (IsDelayed())
|
||||
return false;
|
||||
|
||||
VERUS_QREF_RENDERER;
|
||||
VERUS_QREF_VM;
|
||||
|
||||
const float ratio = Math::Clamp<float>(GetTime() / _duration, 0, 1);
|
||||
const Vector4 color = VMath::lerp(Math::ApplyEasing(_easing, ratio), _from, _to);
|
||||
|
||||
auto cb = renderer.GetCommandBuffer();
|
||||
auto shader = vm.GetShader();
|
||||
|
||||
vm.GetUbGui()._matW = Transform3::UniformBufferFormatIdentity();
|
||||
vm.GetUbGuiFS()._color = color.GLM();
|
||||
|
||||
vm.BindPipeline(GUI::ViewManager::PIPE_SOLID_COLOR, cb);
|
||||
shader->BeginBindDescriptors();
|
||||
cb->BindDescriptors(shader, 0);
|
||||
cb->BindDescriptors(shader, 1, vm.GetDefaultComplexSetHandle());
|
||||
shader->EndBindDescriptors();
|
||||
renderer.DrawQuad(cb.Get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cutscene::MotionCommand:
|
||||
|
||||
Cutscene::PCommand Cutscene::MotionCommand::Make()
|
||||
{
|
||||
return new MotionCommand;
|
||||
}
|
||||
|
||||
bool Cutscene::MotionCommand::Update()
|
||||
{
|
||||
if (IsDelayed() || FLT_MAX == _duration)
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cutscene::MotionCommand::Motion_OnTrigger(CSZ name, int state)
|
||||
{
|
||||
}
|
||||
|
||||
// Cutscene::SoundCommand:
|
||||
|
||||
Cutscene::PCommand Cutscene::SoundCommand::Make()
|
||||
{
|
||||
return new SoundCommand;
|
||||
}
|
||||
|
||||
void Cutscene::SoundCommand::Parse(pugi::xml_node node)
|
||||
{
|
||||
Command::Parse(node);
|
||||
|
||||
_gain = node.attribute("gain").as_float(_gain);
|
||||
_pitch = node.attribute("pitch").as_float(_pitch);
|
||||
_duration = FLT_MAX;
|
||||
_sound.Init(_C(_url));
|
||||
}
|
||||
|
||||
bool Cutscene::SoundCommand::Update()
|
||||
{
|
||||
if (IsDelayed())
|
||||
return true;
|
||||
|
||||
if (FLT_MAX == _duration && _sound->IsLoaded())
|
||||
{
|
||||
_duration = _sound->GetLength();
|
||||
_pCutscene->OnNewActiveDuration(_delay + _duration);
|
||||
}
|
||||
|
||||
const float time = GetTime();
|
||||
if (time >= _duration)
|
||||
{
|
||||
OnEnd();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_source)
|
||||
{
|
||||
_sound->NewSource(&_source)->Play();
|
||||
_source->SetGain(_gain);
|
||||
_source->SetPitch(_pitch);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cutscene::SoundCommand::OnEnd()
|
||||
{
|
||||
Command::OnEnd();
|
||||
|
||||
if (_source)
|
||||
_source->Stop();
|
||||
}
|
||||
|
||||
// Cutscene:
|
||||
|
||||
Cutscene::Cutscene()
|
||||
{
|
||||
}
|
||||
|
||||
Cutscene::~Cutscene()
|
||||
{
|
||||
Done();
|
||||
}
|
||||
|
||||
void Cutscene::Init()
|
||||
{
|
||||
VERUS_INIT();
|
||||
|
||||
RegisterCommand("barrier", &BarrierCommand::Make);
|
||||
RegisterCommand("camera", &CameraCommand::Make);
|
||||
RegisterCommand("config", &ConfigCommand::Make);
|
||||
RegisterCommand("fade", &FadeCommand::Make);
|
||||
RegisterCommand("motion", &MotionCommand::Make);
|
||||
RegisterCommand("sound", &SoundCommand::Make);
|
||||
|
||||
OnWindowSizeChanged();
|
||||
}
|
||||
|
||||
void Cutscene::Done()
|
||||
{
|
||||
DeleteCommands();
|
||||
VERUS_DONE(Cutscene);
|
||||
}
|
||||
|
||||
void Cutscene::Next(CSZ url, bool preload)
|
||||
{
|
||||
_url = url;
|
||||
if (preload)
|
||||
Load(_C(_url));
|
||||
}
|
||||
|
||||
void Cutscene::Load(CSZ url)
|
||||
{
|
||||
Vector<BYTE> vData;
|
||||
IO::FileSystem::LoadResource(url, vData);
|
||||
|
||||
pugi::xml_document doc;
|
||||
const pugi::xml_parse_result result = doc.load_buffer_inplace(vData.data(), vData.size());
|
||||
if (!result)
|
||||
throw VERUS_RECOVERABLE << "load_buffer_inplace(), " << result.description();
|
||||
pugi::xml_node root = doc.first_child();
|
||||
|
||||
_interactive = root.attribute("interactive").as_bool(_interactive);
|
||||
|
||||
DeleteCommands();
|
||||
_vCommands.reserve(16);
|
||||
for (auto node : root.children())
|
||||
{
|
||||
CSZ commandType = node.name();
|
||||
PCommand pCommand = CreateCommand(commandType);
|
||||
if (pCommand)
|
||||
{
|
||||
pCommand->SetCutscene(this);
|
||||
pCommand->Parse(node);
|
||||
_vCommands.push_back(pCommand);
|
||||
}
|
||||
else
|
||||
throw VERUS_RECOVERABLE << "CreateCommand(), type=" << commandType;
|
||||
}
|
||||
}
|
||||
|
||||
void Cutscene::OnBegin()
|
||||
{
|
||||
if (_vCommands.empty())
|
||||
Load(_C(_url));
|
||||
}
|
||||
|
||||
void Cutscene::OnEnd()
|
||||
{
|
||||
if (_fnOnEnd)
|
||||
_fnOnEnd(0); // Tag 0 means whole cutscene.
|
||||
}
|
||||
|
||||
bool Cutscene::CanAutoPop()
|
||||
{
|
||||
return _beginIndex >= _vCommands.size(); // No more commands.
|
||||
}
|
||||
|
||||
void Cutscene::RegisterCommand(CSZ type, PFNCREATOR pCreator)
|
||||
{
|
||||
_mapCreators[type] = pCreator;
|
||||
}
|
||||
|
||||
Cutscene::PCommand Cutscene::CreateCommand(CSZ type)
|
||||
{
|
||||
VERUS_IF_FOUND_IN(TMapCreators, _mapCreators, type, it)
|
||||
return it->second();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Cutscene::DeleteCommands()
|
||||
{
|
||||
for (auto& p : _vCommands)
|
||||
delete p;
|
||||
_vCommands.clear();
|
||||
}
|
||||
|
||||
void Cutscene::Skip()
|
||||
{
|
||||
PCommand pSkipToDelayed = nullptr;
|
||||
for (int i = _beginIndex; i < _endIndex; ++i)
|
||||
{
|
||||
if (_vCommands[i]->IsActive() &&
|
||||
_vCommands[i]->SkipHere() &&
|
||||
_vCommands[i]->IsDelayed() &&
|
||||
_vCommands[i]->GetDelay() != FLT_MAX)
|
||||
{
|
||||
pSkipToDelayed = _vCommands[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSkipToDelayed) // Soft skip using fade command:
|
||||
{
|
||||
const float adjustDelayBy = pSkipToDelayed->GetTime();
|
||||
pSkipToDelayed->AdjustDelayBy(adjustDelayBy);
|
||||
const float delay = pSkipToDelayed->GetDelay();
|
||||
const float duration = pSkipToDelayed->GetDuration();
|
||||
const float maxActiveDuration = delay + duration;
|
||||
for (int i = _beginIndex; i < _endIndex; ++i)
|
||||
{
|
||||
if (_vCommands[i] != pSkipToDelayed && _vCommands[i]->IsActive())
|
||||
_vCommands[i]->LimitActiveDuration(maxActiveDuration);
|
||||
}
|
||||
}
|
||||
else // Hard skip using config command:
|
||||
{
|
||||
// Stop all current commands:
|
||||
for (int i = _beginIndex; i < _endIndex; ++i)
|
||||
{
|
||||
if (_vCommands[i]->IsActive())
|
||||
_vCommands[i]->OnEnd();
|
||||
}
|
||||
// Find where to skip:
|
||||
while (_endIndex < _vCommands.size())
|
||||
{
|
||||
if (_vCommands[_endIndex]->SkipHere())
|
||||
break;
|
||||
_endIndex++;
|
||||
}
|
||||
_beginIndex = _endIndex;
|
||||
_timeSinceBarrier = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Cutscene::SkipBarrier()
|
||||
{
|
||||
VERUS_RT_ASSERT(_beginIndex < _vCommands.size());
|
||||
if (!_vCommands[_beginIndex]->IsBarrier())
|
||||
return false;
|
||||
|
||||
_beginIndex++;
|
||||
_endIndex++;
|
||||
_timeSinceBarrier = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cutscene::RunParallelCommands()
|
||||
{
|
||||
VERUS_RT_ASSERT(_beginIndex < _vCommands.size());
|
||||
if (_vCommands[_beginIndex]->IsBarrier())
|
||||
return false;
|
||||
|
||||
while (_endIndex < _vCommands.size())
|
||||
{
|
||||
if (_vCommands[_endIndex]->IsBarrier())
|
||||
break;
|
||||
_vCommands[_endIndex++]->OnBegin();
|
||||
}
|
||||
|
||||
return _beginIndex != _endIndex;
|
||||
}
|
||||
|
||||
Continue Cutscene::Update()
|
||||
{
|
||||
VERUS_QREF_TIMER;
|
||||
|
||||
_timeSinceBarrier += dt;
|
||||
|
||||
bool hasActiveCommands = false;
|
||||
do
|
||||
{
|
||||
if (_beginIndex >= _vCommands.size()) // No more commands?
|
||||
break;
|
||||
|
||||
if (_beginIndex == _endIndex) // At barrier?
|
||||
{
|
||||
SkipBarrier();
|
||||
RunParallelCommands();
|
||||
|
||||
// Compute duration for this group:
|
||||
float maxActiveDuration = 0;
|
||||
for (int i = _beginIndex; i < _endIndex; ++i)
|
||||
{
|
||||
const float delay = _vCommands[i]->GetDelay();
|
||||
const float duration = _vCommands[i]->GetDuration();
|
||||
if (delay != FLT_MAX && duration != FLT_MAX)
|
||||
{
|
||||
const float activeDuration = delay + duration;
|
||||
if (i + 1 < _vCommands.size())
|
||||
_vCommands[i + 1]->UpdatePrevDelay(activeDuration);
|
||||
maxActiveDuration = Math::Max(maxActiveDuration, activeDuration);
|
||||
}
|
||||
}
|
||||
if (maxActiveDuration > 0)
|
||||
{
|
||||
for (int i = _beginIndex; i < _endIndex; ++i)
|
||||
_vCommands[i]->UpdateEndDelay(maxActiveDuration);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = _beginIndex; i < _endIndex; ++i)
|
||||
{
|
||||
if (_vCommands[i]->IsActive() && _vCommands[i]->Update())
|
||||
hasActiveCommands = true;
|
||||
}
|
||||
|
||||
if (!hasActiveCommands)
|
||||
_beginIndex = _endIndex; // Go to next barrier.
|
||||
} while (!hasActiveCommands); // Don't return while at barrier.
|
||||
|
||||
return Continue::yes;
|
||||
}
|
||||
|
||||
Continue Cutscene::DrawOverlay()
|
||||
{
|
||||
for (int i = _beginIndex; i < _endIndex; ++i)
|
||||
{
|
||||
if (_vCommands[i]->IsActive())
|
||||
_vCommands[i]->DrawOverlay();
|
||||
}
|
||||
return Continue::yes;
|
||||
}
|
||||
|
||||
bool Cutscene::IsInputEnabled()
|
||||
{
|
||||
return _interactive;
|
||||
}
|
||||
|
||||
Continue Cutscene::OnMouseMove(float x, float y)
|
||||
|
@ -17,17 +551,25 @@ Continue Cutscene::OnMouseMove(float x, float y)
|
|||
return _interactive ? Continue::yes : Continue::no;
|
||||
}
|
||||
|
||||
Continue Cutscene::HandleInput()
|
||||
{
|
||||
return _interactive ? Continue::yes : Continue::no;
|
||||
}
|
||||
|
||||
Continue Cutscene::Update()
|
||||
{
|
||||
return Continue::yes;
|
||||
}
|
||||
|
||||
Scene::PMainCamera Cutscene::GetMainCamera()
|
||||
{
|
||||
return _interactive ? nullptr : &_camera;
|
||||
return _pCurrentCameraCommand ? &_camera : nullptr;
|
||||
}
|
||||
|
||||
void Cutscene::OnWindowSizeChanged()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
_camera.SetAspectRatio(renderer.GetSwapChainAspectRatio());
|
||||
_camera.Update();
|
||||
}
|
||||
|
||||
void Cutscene::OnNewActiveDuration(float newActiveDuration)
|
||||
{
|
||||
VERUS_RT_ASSERT(newActiveDuration != 0 && newActiveDuration != FLT_MAX);
|
||||
for (int i = _beginIndex; i < _endIndex; ++i)
|
||||
{
|
||||
if (i + 1 < _vCommands.size())
|
||||
_vCommands[i + 1]->UpdatePrevDelay(newActiveDuration);
|
||||
_vCommands[i]->UpdateEndDelay(newActiveDuration);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,50 +5,173 @@ namespace verus
|
|||
{
|
||||
namespace Game
|
||||
{
|
||||
class Cutscene : public Mechanics
|
||||
class Cutscene : public Object, public Mechanics
|
||||
{
|
||||
public:
|
||||
enum class Fade : int
|
||||
class Command
|
||||
{
|
||||
none,
|
||||
black,
|
||||
count
|
||||
};
|
||||
protected:
|
||||
Cutscene* _pCutscene = nullptr;
|
||||
String _url;
|
||||
float _delay = 0;
|
||||
float _prevDelay = FLT_MAX;
|
||||
float _endDelay = FLT_MAX;
|
||||
float _duration = 0;
|
||||
bool _active = false;
|
||||
|
||||
class Event
|
||||
public:
|
||||
virtual ~Command() {}
|
||||
virtual void Parse(pugi::xml_node node);
|
||||
virtual bool Update();
|
||||
virtual bool DrawOverlay() { return false; }
|
||||
virtual void OnBegin() { _active = true; }
|
||||
virtual void OnEnd() { _active = false; }
|
||||
virtual bool IsBarrier() const { return false; }
|
||||
virtual bool SkipHere() const { return false; }
|
||||
|
||||
void SetCutscene(Cutscene* p) { _pCutscene = p; }
|
||||
bool IsActive() const { return _active; }
|
||||
bool IsDelayed() const { return _pCutscene->_timeSinceBarrier < _delay; }
|
||||
float GetDelay() const { return _delay; }
|
||||
void AdjustDelayBy(float amount) { _delay += amount; }
|
||||
void UpdatePrevDelay(float newActiveDuration);
|
||||
void UpdateEndDelay(float newActiveDuration);
|
||||
float GetDuration() const { return _duration; }
|
||||
void LimitActiveDuration(float limit);
|
||||
float GetTime() const { return _pCutscene->_timeSinceBarrier - _delay; }
|
||||
};
|
||||
VERUS_TYPEDEFS(Command);
|
||||
|
||||
class BarrierCommand : public Command
|
||||
{
|
||||
public:
|
||||
enum class Type : int
|
||||
{
|
||||
camera,
|
||||
input,
|
||||
motion,
|
||||
sound,
|
||||
sync,
|
||||
tr,
|
||||
count
|
||||
};
|
||||
|
||||
private:
|
||||
Type _type = Type::camera;
|
||||
static PCommand Make();
|
||||
virtual bool IsBarrier() const override { return true; }
|
||||
};
|
||||
VERUS_TYPEDEFS(Event);
|
||||
VERUS_TYPEDEFS(BarrierCommand);
|
||||
|
||||
class CameraCommand : public Command, public IO::AsyncCallback, public Anim::MotionDelegate
|
||||
{
|
||||
Anim::Motion _motion;
|
||||
String _cameraName;
|
||||
|
||||
public:
|
||||
~CameraCommand();
|
||||
static PCommand Make();
|
||||
virtual void Parse(pugi::xml_node node) override;
|
||||
virtual bool Update() override;
|
||||
virtual void OnBegin() override;
|
||||
virtual void OnEnd() override;
|
||||
virtual void Async_Run(CSZ url, RcBlob blob) override;
|
||||
virtual void Motion_OnTrigger(CSZ name, int state) override;
|
||||
};
|
||||
VERUS_TYPEDEFS(CameraCommand);
|
||||
|
||||
class ConfigCommand : public Command
|
||||
{
|
||||
int _tag = 1;
|
||||
bool _callOnEnd = false;
|
||||
bool _skipHere = false;
|
||||
|
||||
public:
|
||||
static PCommand Make();
|
||||
virtual void Parse(pugi::xml_node node) override;
|
||||
virtual void OnBegin() override;
|
||||
virtual bool SkipHere() const override { return _skipHere; }
|
||||
};
|
||||
VERUS_TYPEDEFS(ConfigCommand);
|
||||
|
||||
class FadeCommand : public Command
|
||||
{
|
||||
Vector4 _from = Vector4(0);
|
||||
Vector4 _to = Vector4(0);
|
||||
Easing _easing = Easing::none;
|
||||
bool _skipHere = false;
|
||||
|
||||
public:
|
||||
static PCommand Make();
|
||||
virtual void Parse(pugi::xml_node node) override;
|
||||
virtual bool DrawOverlay() override;
|
||||
virtual bool SkipHere() const override { return _skipHere; }
|
||||
};
|
||||
VERUS_TYPEDEFS(FadeCommand);
|
||||
|
||||
class MotionCommand : public Command, public Anim::MotionDelegate
|
||||
{
|
||||
Anim::Motion _motion;
|
||||
|
||||
public:
|
||||
static PCommand Make();
|
||||
virtual bool Update() override;
|
||||
virtual void Motion_OnTrigger(CSZ name, int state) override;
|
||||
};
|
||||
VERUS_TYPEDEFS(MotionCommand);
|
||||
|
||||
class SoundCommand : public Command
|
||||
{
|
||||
Audio::SoundPwn _sound;
|
||||
Audio::SourcePtr _source;
|
||||
float _gain = 1;
|
||||
float _pitch = 1;
|
||||
|
||||
public:
|
||||
static PCommand Make();
|
||||
virtual void Parse(pugi::xml_node node) override;
|
||||
virtual bool Update();
|
||||
virtual void OnEnd() override;
|
||||
};
|
||||
VERUS_TYPEDEFS(SoundCommand);
|
||||
|
||||
private:
|
||||
Vector<Event> _vEvents;
|
||||
Scene::MainCamera _camera;
|
||||
Fade _fadeIn = Fade::none;
|
||||
Fade _fadeOut = Fade::none;
|
||||
bool _interactive = false;
|
||||
typedef PCommand(*PFNCREATOR)();
|
||||
typedef Map<String, PFNCREATOR> TMapCreators;
|
||||
|
||||
String _url;
|
||||
TMapCreators _mapCreators;
|
||||
Vector<PCommand> _vCommands;
|
||||
std::function<void(int)> _fnOnEnd;
|
||||
PCameraCommand _pCurrentCameraCommand = nullptr;
|
||||
Scene::MainCamera _camera;
|
||||
int _beginIndex = 0;
|
||||
int _endIndex = 0;
|
||||
float _timeSinceBarrier = 0;
|
||||
bool _interactive = false;
|
||||
|
||||
public:
|
||||
Cutscene();
|
||||
~Cutscene();
|
||||
|
||||
virtual Continue OnMouseMove(float x, float y) override;
|
||||
virtual Continue HandleInput() override;
|
||||
void Init();
|
||||
void Done();
|
||||
|
||||
void Next(CSZ url, bool preload = false);
|
||||
void Load(CSZ url);
|
||||
|
||||
virtual void OnBegin() override;
|
||||
virtual void OnEnd() override;
|
||||
virtual bool CanAutoPop() override;
|
||||
|
||||
// Commands:
|
||||
void RegisterCommand(CSZ type, PFNCREATOR pCreator);
|
||||
PCommand CreateCommand(CSZ type);
|
||||
void DeleteCommands();
|
||||
|
||||
// Run commands:
|
||||
void Skip();
|
||||
bool SkipBarrier();
|
||||
bool RunParallelCommands();
|
||||
|
||||
virtual Continue Update() override;
|
||||
virtual Continue DrawOverlay() override;
|
||||
virtual bool IsInputEnabled() override;
|
||||
virtual Continue OnMouseMove(float x, float y) override;
|
||||
virtual Scene::PMainCamera GetMainCamera() override;
|
||||
|
||||
void OnWindowSizeChanged();
|
||||
|
||||
void SetOnEndCallback(std::function<void(int)> fn) { _fnOnEnd = fn; }
|
||||
|
||||
void OnNewActiveDuration(float newActiveDuration);
|
||||
};
|
||||
VERUS_TYPEDEFS(Cutscene);
|
||||
}
|
||||
|
|
|
@ -13,14 +13,20 @@ namespace verus
|
|||
|
||||
virtual void OnBegin() {}
|
||||
virtual void OnEnd() {}
|
||||
virtual bool CanAutoPop() { return false; }
|
||||
|
||||
virtual Continue HandleInput() { return Continue::yes; }
|
||||
virtual Continue Update() { return Continue::yes; }
|
||||
virtual Continue Draw() { return Continue::yes; }
|
||||
virtual Continue DrawOverlay() { return Continue::yes; }
|
||||
|
||||
virtual void ApplyReport(const void* pReport) {}
|
||||
virtual Continue GetBotDomainCenter(int id, RPoint3 center) { return Continue::yes; }
|
||||
virtual Continue GetSpawnPosition(int id, RPoint3 pos) { return Continue::yes; };
|
||||
virtual bool IsInputEnabled() { return true; }
|
||||
virtual Continue OnDie(int id) { return Continue::yes; }
|
||||
virtual Continue OnMouseMove(float x, float y) { return Continue::yes; }
|
||||
virtual Continue OnTakeDamage(int id, float amount) { return Continue::yes; }
|
||||
virtual Continue UpdateMultiplayer() { return Continue::yes; }
|
||||
virtual Scene::PMainCamera GetMainCamera() { return nullptr; }
|
||||
};
|
||||
|
|
|
@ -207,7 +207,7 @@ void Spirit::Rotate(RcVector3 front, float speed)
|
|||
_yaw = Math::WrapAngle(_yaw + Math::Min(speed * dt, abs(dYaw)) * glm::sign(dYaw));
|
||||
}
|
||||
|
||||
void Spirit::LookAt(RcPoint3 point)
|
||||
void Spirit::LookAt(RcPoint3 point, bool forceTarget)
|
||||
{
|
||||
const Vector3 dir = point - GetPosition();
|
||||
_yaw = Math::WrapAngle(atan2(
|
||||
|
@ -216,6 +216,12 @@ void Spirit::LookAt(RcPoint3 point)
|
|||
Vector3 dir2D = dir;
|
||||
dir2D.setY(0);
|
||||
_pitch = -atan(dir.getY() / VMath::length(dir2D));
|
||||
|
||||
if (forceTarget)
|
||||
{
|
||||
_yaw.ForceTarget();
|
||||
_pitch.ForceTarget();
|
||||
}
|
||||
}
|
||||
|
||||
RcMatrix3 Spirit::GetPitchMatrix() const
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace verus
|
|||
|
||||
//! Rotates smoothly across multiple frames.
|
||||
void Rotate(RcVector3 front, float speed);
|
||||
void LookAt(RcPoint3 point);
|
||||
void LookAt(RcPoint3 point, bool forceTarget = false);
|
||||
|
||||
// Matrices:
|
||||
RcMatrix3 GetPitchMatrix() const;
|
||||
|
|
|
@ -31,6 +31,7 @@ void EngineInit::Make()
|
|||
|
||||
void EngineInit::Free()
|
||||
{
|
||||
// Some object must outlive others, so the order is important:
|
||||
if (_makeGUI)
|
||||
Free_GUI();
|
||||
if (_makeScene)
|
||||
|
@ -74,9 +75,7 @@ void EngineInit::Init(Input::PKeyMapperDelegate pKeyMapperDelegate, CGI::Rendere
|
|||
}
|
||||
|
||||
if (_makeCGI)
|
||||
{
|
||||
CGI::Renderer::I().Init(pRendererDelegate);
|
||||
}
|
||||
CGI::Renderer::I().Init(pRendererDelegate, _allowInitShaders);
|
||||
|
||||
// Static init:
|
||||
if (_makeEffects)
|
||||
|
@ -92,7 +91,7 @@ void EngineInit::Init(Input::PKeyMapperDelegate pKeyMapperDelegate, CGI::Rendere
|
|||
}
|
||||
|
||||
// Helpers:
|
||||
if (_makeCGI)
|
||||
if (_makeCGI && _allowInitShaders)
|
||||
CGI::DebugDraw::I().Init();
|
||||
if (_makeScene)
|
||||
Scene::Helpers::I().Init();
|
||||
|
@ -118,7 +117,17 @@ void EngineInit::Init(Input::PKeyMapperDelegate pKeyMapperDelegate, CGI::Rendere
|
|||
void EngineInit::InitCmd()
|
||||
{
|
||||
if (_makeEffects)
|
||||
{
|
||||
Effects::Ssao::I().InitCmd();
|
||||
}
|
||||
}
|
||||
|
||||
void EngineInit::ReducedFeatureSet()
|
||||
{
|
||||
_makeAudio = false;
|
||||
_makeEffects = false;
|
||||
_makeExtra = false;
|
||||
_makeGUI = false;
|
||||
_makeNet = false;
|
||||
_makePhysics = false;
|
||||
_makeScene = false;
|
||||
_allowInitShaders = false;
|
||||
}
|
||||
|
|
|
@ -18,23 +18,26 @@ namespace verus
|
|||
class EngineInit
|
||||
{
|
||||
public:
|
||||
bool _makeGlobal = true;
|
||||
bool _makeNet = true;
|
||||
bool _makeIO = true;
|
||||
bool _makeInput = true;
|
||||
bool _makeAudio = true;
|
||||
bool _makeCGI = true;
|
||||
bool _makePhysics = true;
|
||||
bool _makeEffects = true;
|
||||
bool _makeExtra = false;
|
||||
bool _makeScene = true;
|
||||
bool _makeGlobal = true;
|
||||
bool _makeGUI = true;
|
||||
bool _makeInput = true;
|
||||
bool _makeIO = true;
|
||||
bool _makeNet = true;
|
||||
bool _makePhysics = true;
|
||||
bool _makeScene = true;
|
||||
bool _allowInitShaders = true;
|
||||
|
||||
void Make();
|
||||
void Free();
|
||||
|
||||
void Init(Input::KeyMapperDelegate* pKeyMapperDelegate, CGI::RendererDelegate* pRendererDelegate);
|
||||
void InitCmd();
|
||||
|
||||
void ReducedFeatureSet();
|
||||
};
|
||||
VERUS_TYPEDEFS(EngineInit);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ void Utils::FreeEx(PBaseAllocator pAlloc)
|
|||
void Utils::InitPaths()
|
||||
{
|
||||
if (_companyFolderName.empty())
|
||||
_companyFolderName = "swiborg.com";
|
||||
_companyFolderName = "VerusEngine";
|
||||
|
||||
wchar_t pathname[MAX_PATH] = {};
|
||||
if (_modulePath.empty())
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace verus
|
|||
{
|
||||
for (const auto& x : TStoreValues::_map)
|
||||
{
|
||||
if (Continue::yes != fn(_C(x.first), _C(x.second._s)))
|
||||
if (Continue::no == fn(_C(x.first), _C(x.second._s)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,6 +193,23 @@ CSZ Math::EasingToString(Easing easing)
|
|||
return g_easings[+easing];
|
||||
}
|
||||
|
||||
Quat Math::NLerp(float t, RcQuat qA, RcQuat qB)
|
||||
{
|
||||
Quat ret;
|
||||
const auto dp = VMath::dot(qA, qB);
|
||||
if (dp < 0)
|
||||
{
|
||||
const Quat qNeg = -qB;
|
||||
ret = VMath::lerp(t, qA, qNeg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = VMath::lerp(t, qA, qB);
|
||||
}
|
||||
ret = VMath::normalize(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector3 Math::TriangleNormal(RcPoint3 a, RcPoint3 b, RcPoint3 c)
|
||||
{
|
||||
return VMath::normalize(VMath::cross(a - b, a - c));
|
||||
|
|
|
@ -116,6 +116,7 @@ namespace verus
|
|||
float ApplyEasing(Easing easing, float x);
|
||||
Easing EasingFromString(CSZ s);
|
||||
CSZ EasingToString(Easing easing);
|
||||
Quat NLerp(float t, RcQuat qA, RcQuat qB);
|
||||
|
||||
// Shapes:
|
||||
Vector3 TriangleNormal(RcPoint3 a, RcPoint3 b, RcPoint3 c);
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace verus
|
|||
{
|
||||
VERUS_FOR(i, _wheelCount)
|
||||
{
|
||||
if (Continue::yes != fn(_pRaycastVehicle->getWheelInfo(i)))
|
||||
if (Continue::no == fn(_pRaycastVehicle->getWheelInfo(i)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,6 +117,50 @@ void Camera::ExcludeWaterLine(float h)
|
|||
}
|
||||
}
|
||||
|
||||
void Camera::ApplyMotion(CSZ boneName, Anim::RMotion motion, float time)
|
||||
{
|
||||
auto pBone = motion.FindBone(boneName);
|
||||
if (!pBone)
|
||||
return;
|
||||
|
||||
Quat q;
|
||||
Vector3 euler, pos;
|
||||
int state = 0;
|
||||
pBone->ComputeRotationAt(time, euler, q);
|
||||
pBone->ComputePositionAt(time, pos);
|
||||
pBone->ComputeTriggerAt(time, state);
|
||||
Point3 at;
|
||||
Vector3 up;
|
||||
if (state & 0x2)
|
||||
{
|
||||
Vector3 scale;
|
||||
pBone->ComputeScaleAt(time, scale);
|
||||
at = scale;
|
||||
up = Vector3(0, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Matrix3 matR(q);
|
||||
at = pos + matR.getCol2();
|
||||
up = matR.getCol1();
|
||||
}
|
||||
MoveEyeTo(pos);
|
||||
MoveAtTo(at);
|
||||
SetUpDirection(up);
|
||||
Update();
|
||||
}
|
||||
|
||||
void Camera::BakeMotion(CSZ boneName, Anim::RMotion motion, int frame)
|
||||
{
|
||||
auto pBone = motion.FindBone(boneName);
|
||||
if (!pBone)
|
||||
return;
|
||||
|
||||
const glm::quat q = glm::quatLookAt(-_frontDir.GLM(), _upDir.GLM());
|
||||
pBone->InsertKeyframeRotation(frame, q);
|
||||
pBone->InsertKeyframePosition(frame, _eyePos);
|
||||
}
|
||||
|
||||
void Camera::SaveState(int slot)
|
||||
{
|
||||
StringStream ss;
|
||||
|
@ -170,12 +214,20 @@ void MainCamera::Update()
|
|||
void MainCamera::UpdateVP()
|
||||
{
|
||||
VERUS_QREF_RENDERER;
|
||||
|
||||
if (_currentFrame != renderer.GetFrameCount())
|
||||
{
|
||||
_matPrevVP = GetMatrixVP();
|
||||
_currentFrame = renderer.GetFrameCount();
|
||||
}
|
||||
|
||||
Camera::UpdateVP();
|
||||
|
||||
if (_cutMotionBlur)
|
||||
{
|
||||
_cutMotionBlur = false;
|
||||
_matPrevVP = GetMatrixVP();
|
||||
}
|
||||
}
|
||||
|
||||
void MainCamera::GetPickingRay(RPoint3 pos, RVector3 dir) const
|
||||
|
|
|
@ -91,6 +91,9 @@ namespace verus
|
|||
|
||||
void ExcludeWaterLine(float h = 0.25f);
|
||||
|
||||
void ApplyMotion(CSZ boneName, Anim::RMotion motion, float time);
|
||||
void BakeMotion(CSZ boneName, Anim::RMotion motion, int frame);
|
||||
|
||||
// State:
|
||||
virtual void SaveState(int slot);
|
||||
virtual void LoadState(int slot);
|
||||
|
@ -110,6 +113,7 @@ namespace verus
|
|||
Matrix4 _matPrevVP = Matrix4::identity(); // For motion blur.
|
||||
PCursorPosProvider _pCpp = nullptr;
|
||||
UINT64 _currentFrame = UINT64_MAX;
|
||||
bool _cutMotionBlur = false;
|
||||
|
||||
public:
|
||||
void operator=(const MainCamera& that);
|
||||
|
@ -124,6 +128,7 @@ namespace verus
|
|||
void SetCursorPosProvider(PCursorPosProvider p) { _pCpp = p; }
|
||||
|
||||
float ComputeMotionBlur(RcPoint3 pos, RcPoint3 posPrev) const;
|
||||
void CutMotionBlur() { _cutMotionBlur = true; }
|
||||
};
|
||||
VERUS_TYPEDEFS(MainCamera);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,25 @@ void CameraOrbit::Update()
|
|||
MainCamera::Update();
|
||||
}
|
||||
|
||||
void CameraOrbit::UpdateUsingEyeAt()
|
||||
{
|
||||
const Vector3 toEye = _eyePos - _atPos;
|
||||
const float distToEye = VMath::length(toEye);
|
||||
const Vector3 dirToEye = toEye / distToEye;
|
||||
|
||||
const float yaw = Math::WrapAngle(atan2(dirToEye.getX(), dirToEye.getZ()));
|
||||
const float pitch = asin(Math::Clamp<float>(-dirToEye.getY(), -1, 1));
|
||||
|
||||
_pitch = pitch;
|
||||
_pitch.ForceTarget();
|
||||
_yaw = yaw;
|
||||
_yaw.ForceTarget();
|
||||
_radius = distToEye;
|
||||
_radius.ForceTarget();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
void CameraOrbit::UpdateElastic()
|
||||
{
|
||||
if (!_elastic)
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace verus
|
|||
virtual ~CameraOrbit();
|
||||
|
||||
virtual void Update() override;
|
||||
void UpdateUsingEyeAt();
|
||||
void UpdateElastic();
|
||||
|
||||
virtual void DragController_GetParams(float& x, float& y) override;
|
||||
|
|
|
@ -181,8 +181,8 @@ void Grass::Update()
|
|||
_phase = glm::fract(_phase + dt * 2.3f);
|
||||
|
||||
const float windSpeed = atmo.GetWindSpeed();
|
||||
const float warpStrength = Math::Clamp<float>(windSpeed * (1 / 10.f), 0, 1.f);
|
||||
const float turbulence = Math::Clamp<float>(windSpeed * (1 / 14.f), 0, 0.4f);
|
||||
const float warpStrength = Math::Clamp<float>(windSpeed * (1 / 13.f), 0, 1.f);
|
||||
const float turbulence = Math::Clamp<float>(windSpeed * (1 / 17.f), 0, 0.4f);
|
||||
|
||||
_warpSpring.Update(atmo.GetWindDirection() * (warpStrength * 30.f));
|
||||
_turbulence = turbulence * turbulence;
|
||||
|
|
|
@ -568,15 +568,10 @@ void MaterialManager::Init()
|
|||
|
||||
void MaterialManager::InitCmd()
|
||||
{
|
||||
CGI::SamplerDesc strassSamplerDesc;
|
||||
strassSamplerDesc.SetFilter("a");
|
||||
strassSamplerDesc.SetAddressMode("rr");
|
||||
strassSamplerDesc._mipLodBias = -2;
|
||||
|
||||
_texDefaultAlbedo.Init("[Textures]:Default.dds", false, true);
|
||||
_texDefaultNormal.Init("[Textures]:Default.NM.dds", false, true);
|
||||
_texDetail.Init("[Textures]:Detail.FX.dds", false, true);
|
||||
_texStrass.Init("[Textures]:Strass.dds", false, true, &strassSamplerDesc);
|
||||
_texStrass.Init("[Textures]:Strass.dds", false, true);
|
||||
|
||||
_cshDefault = Mesh::GetShader()->BindDescriptorSetTextures(1,
|
||||
{
|
||||
|
|
|
@ -40,7 +40,7 @@ void Mesh::InitStatic()
|
|||
CGI::Sampler::aniso,
|
||||
CGI::Sampler::aniso,
|
||||
CGI::Sampler::aniso,
|
||||
CGI::Sampler::custom
|
||||
CGI::Sampler::lodBias
|
||||
}, CGI::ShaderStageFlags::fs);
|
||||
s_shader[SHADER_MAIN]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), settings.GetLimits()._mesh_ubPerMeshVSCapacity, {}, CGI::ShaderStageFlags::vs);
|
||||
s_shader[SHADER_MAIN]->CreateDescriptorSet(3, &s_ubSkeletonVS, sizeof(s_ubSkeletonVS), settings.GetLimits()._mesh_ubSkinningVSCapacity, {}, CGI::ShaderStageFlags::vs);
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace verus
|
|||
VERUS_FOREACH_X(TStoreModels::TMap, TStoreModels::_map, it)
|
||||
{
|
||||
auto& model = *it++;
|
||||
if (Continue::yes != fn(model.second))
|
||||
if (Continue::no == fn(model.second))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ namespace verus
|
|||
VERUS_FOREACH_X(TStoreSceneParticles::TMap, TStoreSceneParticles::_map, it)
|
||||
{
|
||||
auto& particles = *it++;
|
||||
if (Continue::yes != fn(particles.second))
|
||||
if (Continue::no == fn(particles.second))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ namespace verus
|
|||
VERUS_FOREACH_X(TStoreSites::TMap, TStoreSites::_map, it)
|
||||
{
|
||||
auto& site = *it++;
|
||||
if (Continue::yes != fn(site.second))
|
||||
if (Continue::no == fn(site.second))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ namespace verus
|
|||
MatchSelected(block) &&
|
||||
(!query._blockMesh || block.GetUrl() == query._blockMesh) &&
|
||||
(!query._blockMaterial || block.GetMaterial()->_name == query._blockMaterial))
|
||||
if (Continue::yes != fn(block))
|
||||
if (Continue::no == fn(block))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ namespace verus
|
|||
MatchName(emitter) &&
|
||||
MatchSelected(emitter) &&
|
||||
(!query._particlesUrl || emitter.GetUrl() == query._particlesUrl))
|
||||
if (Continue::yes != fn(emitter))
|
||||
if (Continue::no == fn(emitter))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ namespace verus
|
|||
if (
|
||||
MatchName(light) &&
|
||||
MatchSelected(light))
|
||||
if (Continue::yes != fn(light))
|
||||
if (Continue::no == fn(light))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ namespace verus
|
|||
if (
|
||||
MatchName(prefab) &&
|
||||
MatchSelected(prefab))
|
||||
if (Continue::yes != fn(prefab))
|
||||
if (Continue::no == fn(prefab))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ namespace verus
|
|||
if (
|
||||
MatchName(trigger) &&
|
||||
MatchSelected(trigger))
|
||||
if (Continue::yes != fn(trigger))
|
||||
if (Continue::no == fn(trigger))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
#include "LibDepth.hlsl"
|
||||
#include "Bloom.inc.hlsl"
|
||||
|
||||
ConstantBuffer<UB_BloomVS> g_ubBloomVS : register(b0, space0);
|
||||
ConstantBuffer<UB_BloomFS> g_ubBloomFS : register(b0, space1);
|
||||
ConstantBuffer<UB_BloomGodRaysFS> g_ubBloomGodRaysFS : register(b0, space2);
|
||||
ConstantBuffer<UB_BloomVS> g_ubBloomVS : register(b0, space0);
|
||||
ConstantBuffer<UB_BloomFS> g_ubBloomFS : register(b0, space1);
|
||||
ConstantBuffer<UB_BloomLightShaftsFS> g_ubBloomLightShaftsFS : register(b0, space2);
|
||||
|
||||
Texture2D g_texColor : register(t1, space1);
|
||||
SamplerState g_samColor : register(s1, space1);
|
||||
|
@ -50,24 +50,24 @@ FSO mainFS(VSO si)
|
|||
{
|
||||
FSO so;
|
||||
|
||||
#ifdef DEF_GOD_RAYS
|
||||
const float maxDist = g_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.x;
|
||||
const float sunGloss = g_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.y;
|
||||
const float wideStrength = g_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.z;
|
||||
const float sunStrength = g_ubBloomGodRaysFS._maxDist_sunGloss_wideStrength_sunStrength.w;
|
||||
#ifdef DEF_LIGHT_SHAFTS
|
||||
const float maxDist = g_ubBloomLightShaftsFS._maxDist_sunGloss_wideStrength_sunStrength.x;
|
||||
const float sunGloss = g_ubBloomLightShaftsFS._maxDist_sunGloss_wideStrength_sunStrength.y;
|
||||
const float wideStrength = g_ubBloomLightShaftsFS._maxDist_sunGloss_wideStrength_sunStrength.z;
|
||||
const float sunStrength = g_ubBloomLightShaftsFS._maxDist_sunGloss_wideStrength_sunStrength.w;
|
||||
|
||||
const float2 ndcPos = ToNdcPos(si.tc0);
|
||||
const float rawDepth = g_texDepth.SampleLevel(g_samDepth, si.tc0, 0.f).r;
|
||||
const float3 posW = DS_GetPosition(rawDepth, g_ubBloomGodRaysFS._matInvVP, ndcPos);
|
||||
const float3 posW = DS_GetPosition(rawDepth, g_ubBloomLightShaftsFS._matInvVP, ndcPos);
|
||||
|
||||
const float3 eyePos = g_ubBloomGodRaysFS._eyePos.xyz;
|
||||
const float3 eyePos = g_ubBloomLightShaftsFS._eyePos.xyz;
|
||||
const float3 toPosW = posW - eyePos;
|
||||
const float depth = length(toPosW);
|
||||
const float3 pickingRayDir = toPosW / depth;
|
||||
const float2 spec = pow(saturate(dot(g_ubBloomGodRaysFS._dirToSun.xyz, pickingRayDir)), float2(7, sunGloss));
|
||||
const float2 spec = pow(saturate(dot(g_ubBloomLightShaftsFS._dirToSun.xyz, pickingRayDir)), float2(7, sunGloss));
|
||||
const float strength = dot(spec, float2(wideStrength, sunStrength));
|
||||
|
||||
float3 godRays = 0.f;
|
||||
float3 lightShafts = 0.f;
|
||||
if (strength >= 0.0001f)
|
||||
{
|
||||
const float3 rand = Rand(si.pos.xy);
|
||||
|
@ -93,21 +93,21 @@ FSO mainFS(VSO si)
|
|||
g_samShadow,
|
||||
pos,
|
||||
pos,
|
||||
g_ubBloomGodRaysFS._matShadow,
|
||||
g_ubBloomGodRaysFS._matShadowCSM1,
|
||||
g_ubBloomGodRaysFS._matShadowCSM2,
|
||||
g_ubBloomGodRaysFS._matShadowCSM3,
|
||||
g_ubBloomGodRaysFS._matScreenCSM,
|
||||
g_ubBloomGodRaysFS._csmSplitRanges,
|
||||
g_ubBloomGodRaysFS._shadowConfig,
|
||||
g_ubBloomLightShaftsFS._matShadow,
|
||||
g_ubBloomLightShaftsFS._matShadowCSM1,
|
||||
g_ubBloomLightShaftsFS._matShadowCSM2,
|
||||
g_ubBloomLightShaftsFS._matShadowCSM3,
|
||||
g_ubBloomLightShaftsFS._matScreenCSM,
|
||||
g_ubBloomLightShaftsFS._csmSplitRanges,
|
||||
g_ubBloomLightShaftsFS._shadowConfig,
|
||||
false);
|
||||
acc += shadowMask * step(pickingRayLen, depth);
|
||||
pickingRayLen += stride;
|
||||
}
|
||||
godRays = acc * (1.f / sampleCount) * g_ubBloomGodRaysFS._sunColor.rgb * g_ubBloomFS._exposure.x * strength;
|
||||
lightShafts = acc * (1.f / sampleCount) * g_ubBloomLightShaftsFS._sunColor.rgb * g_ubBloomFS._exposure.x * strength;
|
||||
}
|
||||
|
||||
so.color.rgb = godRays;
|
||||
so.color.rgb = lightShafts;
|
||||
#else
|
||||
const float colorScale = g_ubBloomFS._colorScale_colorBias.x;
|
||||
const float colorBias = g_ubBloomFS._colorScale_colorBias.y;
|
||||
|
@ -126,4 +126,4 @@ FSO mainFS(VSO si)
|
|||
#endif
|
||||
|
||||
//@main:#
|
||||
//@main:#GodRays GOD_RAYS
|
||||
//@main:#LightShafts LIGHT_SHAFTS
|
||||
|
|
|
@ -12,7 +12,7 @@ VERUS_UBUFFER UB_BloomFS
|
|||
float4 _colorScale_colorBias;
|
||||
};
|
||||
|
||||
VERUS_UBUFFER UB_BloomGodRaysFS
|
||||
VERUS_UBUFFER UB_BloomLightShaftsFS
|
||||
{
|
||||
matrix _matInvVP;
|
||||
float4 _dirToSun;
|
||||
|
|
Loading…
Reference in New Issue