feat: initial DX12 foundation framework
This commit is contained in:
194
EngineTest/EngineTest.vcxproj
Normal file
194
EngineTest/EngineTest.vcxproj
Normal file
@@ -0,0 +1,194 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="DebugEditor|x64">
|
||||
<Configuration>DebugEditor</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="ReleaseEditor|x64">
|
||||
<Configuration>ReleaseEditor</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{d1fb8bbd-6836-431b-a43d-f6ea248b8965}</ProjectGuid>
|
||||
<RootNamespace>EngineTest</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>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugEditor|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseEditor|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</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" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugEditor|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</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" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseEditor|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugEditor|x64'">
|
||||
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseEditor|x64'">
|
||||
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Engine\Common;$(SolutionDir)Engine</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>xcopy /Y /D "$(SolutionDir)packages\dxCompiler\dxcompiler.dll" "$(OutDir)"</Command>
|
||||
</PreBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugEditor|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Engine\Common;$(SolutionDir)Engine</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>xcopy /Y /D "$(SolutionDir)packages\dxCompiler\dxcompiler.dll" "$(OutDir)"</Command>
|
||||
</PreBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Engine\Common;$(SolutionDir)Engine</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>xcopy /Y /D "$(SolutionDir)packages\dxCompiler\dxcompiler.dll" "$(OutDir)"</Command>
|
||||
</PreBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseEditor|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Engine\Common;$(SolutionDir)Engine</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>xcopy /Y /D "$(SolutionDir)packages\dxCompiler\dxcompiler.dll" "$(OutDir)"</Command>
|
||||
</PreBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="TestRenderer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Test.h" />
|
||||
<ClInclude Include="TestEntityComponent.h" />
|
||||
<ClInclude Include="TestRenderer.h" />
|
||||
<ClInclude Include="TestWindow.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
13
EngineTest/EngineTest.vcxproj.filters
Normal file
13
EngineTest/EngineTest.vcxproj.filters
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="TestRenderer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Test.h" />
|
||||
<ClInclude Include="TestEntityComponent.h" />
|
||||
<ClInclude Include="TestWindow.h" />
|
||||
<ClInclude Include="TestRenderer.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
84
EngineTest/Lights.cpp
Normal file
84
EngineTest/Lights.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @file Lights.cpp
|
||||
* @brief 渲染测试场景灯光创建与销毁逻辑。
|
||||
*/
|
||||
#include "EngineAPI/GameEntity.h"
|
||||
#include "EngineAPI/Light.h"
|
||||
#include "EngineAPI/TransformComponent.h"
|
||||
#include "Graphics_Beta/Renderer.h"
|
||||
#include "Test.h"
|
||||
|
||||
#if TEST_RENDERER
|
||||
|
||||
using namespace XEngine;
|
||||
|
||||
game_entity::entity create_one_game_entity(math::v3 position, math::v3 rotation, const char* script_name);
|
||||
void remove_game_entity(game_entity::entity_id id);
|
||||
|
||||
const u64 left_set{ 0 };
|
||||
const u64 right_set{ 1 };
|
||||
|
||||
utl::vector<graphics::light> lights;
|
||||
|
||||
constexpr math::v3
|
||||
rgb_to_color(u8 r, u8 g, u8 b) { return { r / 255.f, g / 255.f, b / 255.f }; }
|
||||
|
||||
void
|
||||
generate_lights()
|
||||
{
|
||||
// LEFT_SET
|
||||
graphics::light_init_info info{};
|
||||
info.entity_id = create_one_game_entity({}, {}, nullptr).get_id();
|
||||
info.type = graphics::light::directioinal;
|
||||
info.light_set_key = left_set;
|
||||
info.intensity = 1.f;
|
||||
info.color = rgb_to_color(174, 174, 174);
|
||||
|
||||
lights.emplace_back(graphics::create_light(info));
|
||||
|
||||
info.entity_id = create_one_game_entity({}, { math::pi * 0.5f,0,0 }, nullptr).get_id();
|
||||
info.color = rgb_to_color(17, 27, 28);
|
||||
lights.emplace_back(graphics::create_light(info));
|
||||
|
||||
|
||||
info.entity_id = create_one_game_entity({}, { -math::pi * 0.5f,0,0 }, nullptr).get_id();
|
||||
info.color = rgb_to_color(63, 47, 38);
|
||||
lights.emplace_back(graphics::create_light(info));
|
||||
|
||||
|
||||
//// RIGHT_SET
|
||||
//info.entity_id = create_one_game_entity({}, {}, nullptr).get_id();
|
||||
//info.type = graphics::light::directioinal;
|
||||
//info.light_set_key = right_set;
|
||||
//info.intensity = 1.f;
|
||||
//info.color = rgb_to_color(174, 174, 174);
|
||||
|
||||
//lights.emplace_back(graphics::create_light(info));
|
||||
|
||||
//info.entity_id = create_one_game_entity({}, { math::pi * 0.5f,0,0 }, nullptr).get_id();
|
||||
//info.color = rgb_to_color(17, 27, 28);
|
||||
//lights.emplace_back(graphics::create_light(info));
|
||||
|
||||
|
||||
//info.entity_id = create_one_game_entity({}, { -math::pi * 0.5f,0,0 }, nullptr).get_id();
|
||||
//info.color = rgb_to_color(63, 47, 38);
|
||||
//lights.emplace_back(graphics::create_light(info));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
remove_lights()
|
||||
{
|
||||
for (auto& light : lights)
|
||||
{
|
||||
const game_entity::entity_id id{ light.entity_id() };
|
||||
graphics::remove_light(light.get_id(), light.get_light_set_key());
|
||||
remove_game_entity(id);
|
||||
}
|
||||
|
||||
lights.clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
85
EngineTest/Main.cpp
Normal file
85
EngineTest/Main.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file Main.cpp
|
||||
* @brief 测试程序入口与主循环。
|
||||
*/
|
||||
#include "Test.h"
|
||||
|
||||
#pragma comment(lib, "engine.lib")
|
||||
|
||||
#if TEST_ENTITY_COMPONENTS
|
||||
#include "TestEntityComponent.h"
|
||||
#elif TEST_WINDOW_COMPONENTS
|
||||
#include "TestWindow.h"
|
||||
#elif TEST_RENDERER
|
||||
#include "TestRenderer.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <Windows.h>
|
||||
#include <filesystem>
|
||||
|
||||
// TODO: duplicate
|
||||
std::filesystem::path
|
||||
set_current_directory_to_executable_path()
|
||||
{
|
||||
wchar_t path[MAX_PATH]{};
|
||||
const u32 length{ GetModuleFileName(0, &path[0], MAX_PATH) };
|
||||
if (!length || GetLastError() == ERROR_INSUFFICIENT_BUFFER) return {};
|
||||
std::filesystem::path p{ path };
|
||||
std::filesystem::current_path(p.parent_path());
|
||||
return std::filesystem::current_path();
|
||||
}
|
||||
|
||||
|
||||
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
|
||||
#if _DEBUG
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
#endif
|
||||
|
||||
set_current_directory_to_executable_path();
|
||||
|
||||
engine_test test{};
|
||||
|
||||
|
||||
if (test.initialize())
|
||||
{
|
||||
MSG msg{};
|
||||
bool is_running{ true };
|
||||
while (is_running)
|
||||
{
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
is_running &= (msg.message != WM_QUIT);
|
||||
}
|
||||
|
||||
test.run();
|
||||
}
|
||||
}
|
||||
test.shutdown();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
int main()
|
||||
{
|
||||
#if _DEBUG
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
#endif
|
||||
engine_test test{};
|
||||
|
||||
if (test.initialize())
|
||||
{
|
||||
test.run();
|
||||
}
|
||||
|
||||
test.shutdown();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
141
EngineTest/RenderItem.cpp
Normal file
141
EngineTest/RenderItem.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @file RenderItem.cpp
|
||||
* @brief 渲染项创建与销毁测试逻辑。
|
||||
*/
|
||||
#include "CommonHeader.h"
|
||||
#include <filesystem>
|
||||
#include "Content/ContentToEngine.h"
|
||||
#include "ShaderComponents.h"
|
||||
#include "Components/Entity.h"
|
||||
#include "Graphics_Beta/Renderer.h"
|
||||
#include "../ContentTools/Geometry.h"
|
||||
#include "Test.h"
|
||||
#if TEST_RENDERER
|
||||
using namespace XEngine;
|
||||
bool read_file(std::filesystem::path, std::unique_ptr<u8[]>&, u64&);
|
||||
|
||||
namespace {
|
||||
id::id_type model_id{ id::invalid_id };
|
||||
id::id_type vs_id{ id::invalid_id };
|
||||
id::id_type ps_id{ id::invalid_id };
|
||||
id::id_type mtl_id{ id::invalid_id };
|
||||
|
||||
std::unordered_map<id::id_type, id::id_type> render_item_entity_map;
|
||||
|
||||
void
|
||||
load_model()
|
||||
{
|
||||
std::unique_ptr<u8[]> model;
|
||||
u64 size{ 0 };
|
||||
read_file("..\\..\\enginetest\\model.model", model, size);
|
||||
model_id = content::create_resource(model.get(), content::asset_type::mesh);
|
||||
assert(id::is_valid(model_id));
|
||||
}
|
||||
|
||||
void
|
||||
load_shaders()
|
||||
{
|
||||
shader_file_info info{};
|
||||
info.file_name = "TestShader.hlsl";
|
||||
info.function = "TestShaderVS";
|
||||
info.type = shader_type::vertex;
|
||||
|
||||
const char* shader_path{ "..\\..\\enginetest\\" };
|
||||
|
||||
std::wstring defines[]{ L"ELEMENTS_TYPE=1", L"ELEMENTS_TYPE=3" };
|
||||
utl::vector<u32> keys;
|
||||
keys.emplace_back(tools::elements::element_type::static_normal);
|
||||
keys.emplace_back(tools::elements::element_type::static_normal_texture);
|
||||
|
||||
utl::vector<std::wstring> extra_args{};
|
||||
utl::vector<std::unique_ptr<u8[]>> vertex_shaders;
|
||||
utl::vector<u8*> vertex_shaders_pointers;
|
||||
for (u32 i{ 0 }; i < _countof(defines); ++i)
|
||||
{
|
||||
extra_args.clear();
|
||||
extra_args.emplace_back(L"-D");
|
||||
extra_args.emplace_back(defines[i]);
|
||||
vertex_shaders.emplace_back(std::move(compile_shader(info, shader_path, extra_args)));
|
||||
assert(vertex_shaders.back().get());
|
||||
vertex_shaders_pointers.emplace_back(vertex_shaders.back().get());
|
||||
}
|
||||
|
||||
|
||||
extra_args.clear();
|
||||
info.function = "TestShaderPS";
|
||||
info.type = shader_type::pixel;
|
||||
|
||||
auto pixel_shader = compile_shader(info, shader_path, extra_args);
|
||||
assert(pixel_shader.get());
|
||||
|
||||
|
||||
vs_id = content::add_shader_group(vertex_shaders_pointers.data(), (u32)vertex_shaders_pointers.size(), keys.data());
|
||||
|
||||
const u8* pixel_shaders[]{ pixel_shader.get() };
|
||||
ps_id = content::add_shader_group(&pixel_shaders[0], 1, &u32_invalid_id);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
create_material()
|
||||
{
|
||||
graphics::material_init_info info{};
|
||||
info.shader_ids[graphics::shader_type::vertex] = vs_id;
|
||||
info.shader_ids[graphics::shader_type::pixel] = ps_id;
|
||||
info.type = graphics::material_type::opaque;
|
||||
mtl_id = content::create_resource(&info, content::asset_type::material);
|
||||
|
||||
}
|
||||
}//namespace
|
||||
|
||||
id::id_type
|
||||
create_render_item(id::id_type entity_id)
|
||||
{
|
||||
auto _1 = std::thread{ [] {load_model(); } };
|
||||
auto _2 = std::thread{ [] {load_shaders(); } };
|
||||
|
||||
_1.join();
|
||||
_2.join();
|
||||
|
||||
create_material();
|
||||
id::id_type materials[]{ mtl_id };
|
||||
|
||||
id::id_type item_id{ graphics::add_render_item(entity_id, model_id, _countof(materials), &materials[0]) };
|
||||
|
||||
render_item_entity_map[item_id] = entity_id;
|
||||
|
||||
return item_id;
|
||||
}
|
||||
|
||||
void
|
||||
destroy_render_item(id::id_type item_id)
|
||||
{
|
||||
if (id::is_valid(item_id))
|
||||
{
|
||||
graphics::remove_render_item(item_id);
|
||||
auto pair = render_item_entity_map.find(item_id);
|
||||
if (pair != render_item_entity_map.end())
|
||||
{
|
||||
game_entity::remove(game_entity::entity_id{ pair->second });
|
||||
}
|
||||
}
|
||||
|
||||
if (id::is_valid(mtl_id))
|
||||
{
|
||||
content::destroy_resource(mtl_id, content::asset_type::material);
|
||||
}
|
||||
|
||||
if (id::is_valid(vs_id))
|
||||
{
|
||||
content::remove_shader_group(vs_id);
|
||||
}
|
||||
if (id::is_valid(ps_id))
|
||||
{
|
||||
content::remove_shader_group(ps_id);
|
||||
}
|
||||
if (id::is_valid(model_id))
|
||||
{
|
||||
content::destroy_resource(model_id, content::asset_type::mesh);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
326
EngineTest/ShaderComponents.cpp
Normal file
326
EngineTest/ShaderComponents.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/**
|
||||
* @file ShaderComponents.cpp
|
||||
* @brief 测试工程着色器编译与缓存实现。
|
||||
*/
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <d3d12shader.h>
|
||||
#include "CommonHeader.h"
|
||||
#include "Graphics_Beta\Direct3D12\D3D12Shaders.h"
|
||||
#include "Graphics_Beta\Direct3D12\D3D12CommonHeaders.h"
|
||||
#include "Graphics_Beta\Direct3D12\D3D12Core.h"
|
||||
#include "ShaderComponents.h"
|
||||
|
||||
#include "Content/ContentToEngine.h"
|
||||
#include "Utilities/IOStream.h"
|
||||
#include <dxcapi.h>
|
||||
|
||||
|
||||
using namespace XEngine;
|
||||
using namespace XEngine::graphics::d3d12::shaders;
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
namespace {
|
||||
constexpr const char* shaders_source_path{ "../../Engine/Graphics_Beta/Direct3D12/Shaders/" };
|
||||
|
||||
struct engine_shader_info
|
||||
{
|
||||
engine_shader::id id;
|
||||
shader_file_info info;
|
||||
};
|
||||
|
||||
constexpr engine_shader_info engine_shader_files[]
|
||||
{
|
||||
engine_shader::fullscreen_triangle_vs,{"FullScreenTriangle.hlsl", "FullScreenTriangleVS",shader_type::vertex},
|
||||
engine_shader::fill_color_ps,{"FillColor.hlsl", "FillColorPS", shader_type::pixel},
|
||||
engine_shader::post_process_ps,{"PostProcess.hlsl", "PostProcessPS", shader_type::pixel},
|
||||
};
|
||||
|
||||
static_assert(_countof(engine_shader_files) == engine_shader::count);
|
||||
|
||||
struct dxc_compiled_shader
|
||||
{
|
||||
ComPtr<IDxcBlob> byte_code;
|
||||
ComPtr<IDxcBlobUtf8> disassembly;
|
||||
DxcShaderHash hash;
|
||||
};
|
||||
std::wstring
|
||||
to_wstring(const char* c)
|
||||
{
|
||||
std::string s{ c };
|
||||
return { s.begin(), s.end() };
|
||||
}
|
||||
|
||||
class shader_compiler
|
||||
{
|
||||
public:
|
||||
shader_compiler()
|
||||
{
|
||||
HRESULT hr{ S_OK };
|
||||
DXCall(hr = DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&_compiler)));
|
||||
if (FAILED(hr)) return;
|
||||
DXCall(hr = DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&_utils)));
|
||||
if (FAILED(hr)) return;
|
||||
DXCall(hr = _utils->CreateDefaultIncludeHandler(&_include_handler));
|
||||
if (FAILED(hr)) return;
|
||||
|
||||
}
|
||||
|
||||
DISABLE_COPY_AND_MOVE(shader_compiler);
|
||||
|
||||
dxc_compiled_shader compile(shader_file_info info, std::filesystem::path full_path, XEngine::utl::vector<std::wstring>& extra_args)
|
||||
{
|
||||
assert(_compiler && _utils && _include_handler);
|
||||
HRESULT hr{ S_OK };
|
||||
|
||||
ComPtr<IDxcBlobEncoding> source_blob{ nullptr };
|
||||
DXCall(hr = _utils->LoadFile(full_path.c_str(), nullptr, &source_blob));
|
||||
if (FAILED(hr)) return {};
|
||||
assert(source_blob && source_blob->GetBufferSize());
|
||||
|
||||
|
||||
OutputDebugStringA("Compiling ");
|
||||
OutputDebugStringA(info.file_name);
|
||||
|
||||
return compile(source_blob.Get(), get_args(info, extra_args));
|
||||
}
|
||||
|
||||
dxc_compiled_shader compile(IDxcBlobEncoding* source_blob, XEngine::utl::vector<std::wstring> compiler_args)
|
||||
{
|
||||
DxcBuffer buffer{};
|
||||
buffer.Encoding = DXC_CP_ACP;
|
||||
buffer.Ptr = source_blob->GetBufferPointer();
|
||||
buffer.Size = source_blob->GetBufferSize();
|
||||
|
||||
utl::vector<LPCWSTR> args;
|
||||
for (const auto& arg : compiler_args)
|
||||
{
|
||||
args.emplace_back(arg.c_str());
|
||||
}
|
||||
|
||||
HRESULT hr{ S_OK };
|
||||
ComPtr<IDxcResult> results{ nullptr };
|
||||
DXCall(hr = _compiler->Compile(&buffer, args.data(), args.size(), _include_handler.Get(), IID_PPV_ARGS(&results)));
|
||||
if (FAILED(hr)) return {};
|
||||
|
||||
ComPtr<IDxcBlobUtf8> errors{ nullptr };
|
||||
DXCall(hr = results->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&errors), nullptr));
|
||||
if (FAILED(hr)) return {};
|
||||
|
||||
if (errors && errors->GetStringLength())
|
||||
{
|
||||
OutputDebugStringA("\nShader compilation error : \n");
|
||||
OutputDebugStringA(errors->GetStringPointer());
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputDebugStringA(" [ Succeeded ] ");
|
||||
}
|
||||
OutputDebugStringA("\n");
|
||||
|
||||
HRESULT status{ S_OK };
|
||||
DXCall(hr = results->GetStatus(&status));
|
||||
if (FAILED(hr) || FAILED(status)) return {};
|
||||
|
||||
ComPtr<IDxcBlob> hash{ nullptr };
|
||||
DXCall(hr = results->GetOutput(DXC_OUT_SHADER_HASH, IID_PPV_ARGS(&hash), nullptr));
|
||||
if (FAILED(hr)) return {};
|
||||
DxcShaderHash *const hash_buffer{ (DxcShaderHash *const)hash->GetBufferPointer() };
|
||||
assert(!(hash_buffer->Flags & DXC_HASHFLAG_INCLUDES_SOURCE));
|
||||
OutputDebugStringA(" [ Shader Hash: ] ");
|
||||
for (u32 i{ 0 }; i < _countof(hash_buffer->HashDigest); ++i)
|
||||
{
|
||||
char hash_bytes[3]{};
|
||||
sprintf_s(hash_bytes, "%02x", (u32)hash_buffer->HashDigest[i]);
|
||||
OutputDebugStringA(hash_bytes);
|
||||
OutputDebugStringA(" ");
|
||||
}
|
||||
OutputDebugStringA("\n");
|
||||
|
||||
ComPtr<IDxcBlob> shader{ nullptr };
|
||||
DXCall(hr = results->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&shader), nullptr));
|
||||
if (FAILED(hr)) return {};
|
||||
buffer.Ptr = shader->GetBufferPointer();
|
||||
buffer.Size = shader->GetBufferSize();
|
||||
|
||||
ComPtr<IDxcResult> disasm_results{ nullptr };
|
||||
DXCall(hr = _compiler->Disassemble(&buffer, IID_PPV_ARGS(&disasm_results)));
|
||||
|
||||
ComPtr<IDxcBlobUtf8> disassembly{ nullptr };
|
||||
DXCall(hr = disasm_results->GetOutput(DXC_OUT_DISASSEMBLY, IID_PPV_ARGS(&disassembly), nullptr));
|
||||
|
||||
dxc_compiled_shader result{ shader.Detach(), disassembly.Detach() };
|
||||
memcpy(&result.hash.HashDigest[0], &hash_buffer->HashDigest[0], _countof(hash_buffer->HashDigest));
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
|
||||
utl::vector<std::wstring>
|
||||
get_args(const shader_file_info& info, utl::vector<std::wstring>& extra_args)
|
||||
{
|
||||
|
||||
utl::vector<std::wstring> args{};
|
||||
args.emplace_back(to_wstring(info.file_name));
|
||||
|
||||
args.emplace_back(L"-E");
|
||||
args.emplace_back(to_wstring(info.function));
|
||||
args.emplace_back(L"-T");
|
||||
args.emplace_back(to_wstring(_profile_strings[(u32)info.type]));
|
||||
args.emplace_back(L"-I");
|
||||
args.emplace_back(to_wstring(shaders_source_path));
|
||||
args.emplace_back(L"-enable-16bit-types");
|
||||
args.emplace_back(DXC_ARG_ALL_RESOURCES_BOUND);
|
||||
|
||||
#if _DEBUG
|
||||
args.emplace_back(DXC_ARG_DEBUG);
|
||||
args.emplace_back(DXC_ARG_SKIP_OPTIMIZATIONS);
|
||||
#else
|
||||
args.emplace_back(DXC_ARG_OPTIMIZATION_LEVEL3);
|
||||
#endif // _DEBUG
|
||||
args.emplace_back(DXC_ARG_WARNINGS_ARE_ERRORS);
|
||||
args.emplace_back(L"-Qstrip_reflect");
|
||||
args.emplace_back(L"-Qstrip_debug");
|
||||
|
||||
|
||||
for (const auto& arg : extra_args)
|
||||
{
|
||||
args.emplace_back(arg.c_str());
|
||||
}
|
||||
|
||||
return args;
|
||||
|
||||
}
|
||||
|
||||
constexpr static const char* _profile_strings[]{ "vs_6_6", "hs_6_6", "ds_6_6", "gs_6_6", "ps_6_6", "cs_6_6", "as_6_6", "ms_6_6" };
|
||||
static_assert(_countof(_profile_strings) == shader_type::count);
|
||||
|
||||
ComPtr<IDxcCompiler3> _compiler{ nullptr };
|
||||
ComPtr<IDxcUtils> _utils{ nullptr };
|
||||
ComPtr<IDxcIncludeHandler> _include_handler{ nullptr };
|
||||
};
|
||||
|
||||
decltype(auto)
|
||||
get_engine_shaders_path()
|
||||
{
|
||||
return std::filesystem::absolute(graphics::get_engine_shaders_path(graphics::graphics_platform::direct3d12));
|
||||
}
|
||||
|
||||
bool
|
||||
compiled_shaders_are_up_to_date()
|
||||
{
|
||||
auto engine_shaders_path = get_engine_shaders_path();
|
||||
if (!std::filesystem::exists(engine_shaders_path))return false;
|
||||
auto shaders_compilation_time = std::filesystem::last_write_time(engine_shaders_path);
|
||||
|
||||
std::filesystem::path full_path{};
|
||||
|
||||
for (u32 i{ 0 }; i < engine_shader::count; ++i) {
|
||||
auto& info = engine_shader_files[i];
|
||||
|
||||
full_path = shaders_source_path;
|
||||
full_path += info.info.file_name;
|
||||
if (!std::filesystem::exists(full_path)) return false;
|
||||
|
||||
auto shader_file_time = std::filesystem::last_write_time(full_path);
|
||||
if (shader_file_time > shaders_compilation_time)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
save_compiled_shaders(utl::vector<dxc_compiled_shader>& shaders)
|
||||
{
|
||||
auto engine_shaders_path = get_engine_shaders_path();
|
||||
std::filesystem::create_directories(engine_shaders_path.parent_path());
|
||||
std::ofstream file(engine_shaders_path, std::ios::out | std::ios::binary);
|
||||
if (!file || !std::filesystem::exists(engine_shaders_path))
|
||||
{
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& shader : shaders)
|
||||
{
|
||||
const D3D12_SHADER_BYTECODE byte_code{ shader.byte_code->GetBufferPointer(), shader.byte_code->GetBufferSize() };
|
||||
file.write((char*)&byte_code.BytecodeLength, sizeof(byte_code.BytecodeLength));
|
||||
file.write((char*)&shader.hash.HashDigest[0], _countof(shader.hash.HashDigest));
|
||||
file.write((char*)byte_code.pShaderBytecode, byte_code.BytecodeLength);
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<u8[]>
|
||||
compile_shader(shader_file_info info, const char* file_path, utl::vector<std::wstring>& extra_args)
|
||||
{
|
||||
std::filesystem::path full_path{ file_path };
|
||||
full_path += info.file_name;
|
||||
if (!std::filesystem::exists(full_path)) return {};
|
||||
|
||||
|
||||
shader_compiler compiler{};
|
||||
dxc_compiled_shader compiled_shader{ compiler.compile(info, full_path, extra_args) };
|
||||
|
||||
if (compiled_shader.byte_code != nullptr && compiled_shader.byte_code->GetBufferPointer() && compiled_shader.byte_code->GetBufferSize())
|
||||
{
|
||||
static_assert(content::compiled_shader::hash_length == _countof(DxcShaderHash::HashDigest));
|
||||
const u64 buffer_size{ sizeof(u64) + content::compiled_shader::hash_length + compiled_shader.byte_code->GetBufferSize() };
|
||||
std::unique_ptr<u8[]> buffer{ std::make_unique<u8[]>(buffer_size) };
|
||||
utl::blob_stream_writer blob{ buffer.get(), buffer_size };
|
||||
blob.write(compiled_shader.byte_code->GetBufferSize());
|
||||
blob.write(compiled_shader.hash.HashDigest, content::compiled_shader::hash_length);
|
||||
blob.write((u8*)compiled_shader.byte_code->GetBufferPointer(), compiled_shader.byte_code->GetBufferSize());
|
||||
|
||||
assert(blob.offset() == buffer_size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
compile_shaders()
|
||||
{
|
||||
if (compiled_shaders_are_up_to_date()) return true;
|
||||
|
||||
shader_compiler compiler{};
|
||||
utl::vector<dxc_compiled_shader> shaders;
|
||||
std::filesystem::path full_path{};
|
||||
|
||||
|
||||
for (u32 i{ 0 }; i < engine_shader::count; ++i)
|
||||
{
|
||||
auto& file = engine_shader_files[i];
|
||||
|
||||
full_path = shaders_source_path;
|
||||
full_path += file.info.file_name;
|
||||
if (!std::filesystem::exists(full_path)) return false;
|
||||
utl::vector<std::wstring> extra_args{};
|
||||
|
||||
dxc_compiled_shader compiled_shader{ compiler.compile(file.info, full_path, extra_args) };
|
||||
if (compiled_shader.byte_code != nullptr && compiled_shader.byte_code->GetBufferPointer() && compiled_shader.byte_code->GetBufferSize())
|
||||
{
|
||||
shaders.emplace_back(std::move(compiled_shader));
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return save_compiled_shaders(shaders);
|
||||
}
|
||||
35
EngineTest/ShaderComponents.h
Normal file
35
EngineTest/ShaderComponents.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @file ShaderComponents.h
|
||||
* @brief 测试工程着色器编译接口定义。
|
||||
*/
|
||||
#pragma once
|
||||
#include "CommonHeader.h"
|
||||
#pragma comment(lib, "dxcompiler.lib")
|
||||
|
||||
struct shader_type {
|
||||
enum type :u32 {
|
||||
vertex = 0,
|
||||
hull,
|
||||
domain,
|
||||
geometry,
|
||||
pixel,
|
||||
compute,
|
||||
amplification,
|
||||
mesh,
|
||||
|
||||
count
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct shader_file_info
|
||||
{
|
||||
const char* file_name;
|
||||
const char* function;
|
||||
shader_type::type type;
|
||||
};
|
||||
|
||||
std::unique_ptr<u8[]> compile_shader(shader_file_info info, const char* file_path, XEngine::utl::vector<std::wstring>& extra_args);
|
||||
bool compile_shaders();
|
||||
72
EngineTest/Test.h
Normal file
72
EngineTest/Test.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file Test.h
|
||||
* @brief 测试基类与计时工具定义。
|
||||
*/
|
||||
#pragma once
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include "Id.h"
|
||||
|
||||
|
||||
#define TEST_ENTITY_COMPONENTS 0
|
||||
#define TEST_WINDOW_COMPONENTS 0
|
||||
#define TEST_RENDERER 1
|
||||
|
||||
class Test
|
||||
{
|
||||
public:
|
||||
virtual bool initialize() = 0;
|
||||
virtual void run() = 0;
|
||||
virtual bool shutdown() = 0;
|
||||
};
|
||||
|
||||
#if _WIN64
|
||||
#include <Windows.h>
|
||||
class time_it
|
||||
{
|
||||
public:
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
using time_stamp = std::chrono::steady_clock::time_point;
|
||||
|
||||
constexpr float dt_avg() const { return _dt_avg * 1e-3f; }
|
||||
void begin()
|
||||
{
|
||||
_start = clock::now();
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
|
||||
auto dt = clock::now() - _start;
|
||||
_msg_avg += ((float)std::chrono::duration_cast<std::chrono::milliseconds>(dt).count() - _msg_avg) / (float)_counter;
|
||||
++_counter;
|
||||
_dt_avg = _msg_avg;
|
||||
|
||||
if (std::chrono::duration_cast<std::chrono::seconds>(clock::now() - _seconds).count() >= 1)
|
||||
{
|
||||
OutputDebugStringA("Avg. frame (ms): ");
|
||||
OutputDebugStringA(std::to_string(_msg_avg).c_str());
|
||||
OutputDebugStringA((" " + std::to_string(_counter)).c_str());
|
||||
OutputDebugStringA(" fps");
|
||||
OutputDebugStringA("\n");
|
||||
_msg_avg = 0.f;
|
||||
_counter = 1;
|
||||
_seconds = clock::now();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
float _dt_avg{ 16.7f };
|
||||
float _msg_avg{ 0.f };
|
||||
int _counter{ 1 };
|
||||
time_stamp _start;
|
||||
time_stamp _seconds{ clock::now() };
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
98
EngineTest/TestEntityComponent.h
Normal file
98
EngineTest/TestEntityComponent.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file TestEntityComponent.h
|
||||
* @brief 实体与组件系统测试用例定义。
|
||||
*/
|
||||
#pragma once
|
||||
#include "Test.h"
|
||||
#include "..\Engine\Components\Entity.h"
|
||||
#include "..\Engine\Components\Transform.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
using namespace XEngine;
|
||||
|
||||
class engine_test : public Test
|
||||
{
|
||||
public:
|
||||
bool initialize() override
|
||||
{
|
||||
srand((u32)time(nullptr));
|
||||
return true;
|
||||
}
|
||||
void run() override
|
||||
{
|
||||
//do {
|
||||
for (u32 i{ 0 }; i < 10; ++i)
|
||||
{
|
||||
create_random();
|
||||
remove_random();
|
||||
_num_entities = (u32)_entities.size();
|
||||
}
|
||||
print_results();
|
||||
//} while (getchar() != 'q');
|
||||
}
|
||||
bool shutdown() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
utl::vector<game_entity::entity> _entities;
|
||||
|
||||
u32 _added{ 0 };
|
||||
u32 _removed{ 0 };
|
||||
u32 _num_entities{ 0 };
|
||||
|
||||
|
||||
|
||||
void create_random()
|
||||
{
|
||||
u32 count = rand() % 20;
|
||||
if (_entities.empty()) count = 10;
|
||||
transform::init_info transform_info{};
|
||||
game_entity::entity_info entity_info
|
||||
{
|
||||
&transform_info,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
++_added;
|
||||
game_entity::entity entity{ game_entity::create(entity_info) };
|
||||
assert(entity.is_valid() && id::is_valid(entity.get_id()));
|
||||
_entities.push_back(entity);
|
||||
assert(game_entity::is_alive(entity.get_id()));
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void print_results()
|
||||
{
|
||||
std::cout << "Entities created:" << _added << std::endl;
|
||||
std::cout << "Entities deleted:" << _removed << std::endl;
|
||||
}
|
||||
|
||||
void remove_random()
|
||||
{
|
||||
u32 count = rand() % 20;
|
||||
if (_entities.size() < 1000)return;
|
||||
while (count > 0)
|
||||
{
|
||||
++_removed;
|
||||
const u32 index{ (u32)rand() % (u32)_entities.size() };
|
||||
auto entity = _entities[index];
|
||||
assert(entity.is_valid() && id::is_valid(entity.get_id()));
|
||||
if (entity.is_valid())
|
||||
{
|
||||
game_entity::remove(entity.get_id());
|
||||
_entities.erase(_entities.begin() + index);
|
||||
assert(!game_entity::is_alive(entity.get_id()));
|
||||
}
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
355
EngineTest/TestRenderer_Beta.cpp
Normal file
355
EngineTest/TestRenderer_Beta.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* @file TestRenderer.cpp
|
||||
* @brief 渲染功能综合测试实现。
|
||||
*/
|
||||
|
||||
#include "TestRenderer.h"
|
||||
#include "Platform/Platform.h"
|
||||
#include "Platform/PlatformTypes.h"
|
||||
#include "Graphics_Beta/Renderer.h"
|
||||
#include "ShaderComponents.h"
|
||||
#include "Content/ContentToEngine.h"
|
||||
#include "Graphics_Beta/Direct3D12/D3D12Core.h"
|
||||
#include "Components/Script.h"
|
||||
#include "Components/Entity.h"
|
||||
#include "Components/Transform.h"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
#if TEST_RENDERER
|
||||
using namespace XEngine;
|
||||
|
||||
class rotator_script;
|
||||
REGISTER_SCRIPT(rotator_script);
|
||||
class rotator_script :public script::entity_script
|
||||
{
|
||||
public:
|
||||
constexpr explicit rotator_script(game_entity::entity entity)
|
||||
: script::entity_script{ entity }{}
|
||||
void begin_play() override {}
|
||||
void update(float dt) override
|
||||
{
|
||||
_angle += 0.25f * dt * math::two_pi;
|
||||
if (_angle > math::two_pi) _angle -= math::two_pi;
|
||||
math::v3a rot{ 0.f, _angle, 0.f };
|
||||
DirectX::XMVECTOR quat{ DirectX::XMQuaternionRotationRollPitchYawFromVector(DirectX::XMLoadFloat3A(&rot)) };
|
||||
math::v4 rot_quat{};
|
||||
DirectX::XMStoreFloat4(&rot_quat, quat);
|
||||
set_rotation(rot_quat);
|
||||
}
|
||||
|
||||
private:
|
||||
f32 _angle{ 0.f };
|
||||
};
|
||||
|
||||
// Multithreading test worker spawn code ///////////////////
|
||||
|
||||
#define ENABLE_TEST_WORKERS 0
|
||||
|
||||
constexpr u32 num_threads{ 8 };
|
||||
bool wshutdown{ false };
|
||||
std::thread workers[num_threads];
|
||||
|
||||
utl::vector<u8> buffer(1024 * 1024, 0);
|
||||
|
||||
void buffer_test_worker()
|
||||
{
|
||||
while (!wshutdown)
|
||||
{
|
||||
auto* resource = graphics::d3d12::d3dx::create_buffer(buffer.data(), (u32)buffer.size());
|
||||
|
||||
graphics::d3d12::core::deferred_release(resource);
|
||||
}
|
||||
}
|
||||
|
||||
template<class FnPtr, class... Args>
|
||||
void init_test_workers(FnPtr&& fnPtr, Args&&... args)
|
||||
{
|
||||
#if ENABLE_TEST_WORKERS
|
||||
wshutdown = false;
|
||||
for (auto& w : workers)
|
||||
w = std::thread(std::forward<FnPtr>(fnPtr), std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
void joint_test_workers()
|
||||
{
|
||||
#if ENABLE_TEST_WORKERS
|
||||
wshutdown = true;
|
||||
for (auto&w : workers) w.join();
|
||||
#endif
|
||||
}
|
||||
//////////////////////
|
||||
struct camera_surface {
|
||||
game_entity::entity entity{};
|
||||
graphics::camera camera{};
|
||||
graphics::render_surface surface{};
|
||||
};
|
||||
id::id_type item_id{ id::invalid_id };
|
||||
id::id_type model_id{ id::invalid_id };
|
||||
|
||||
camera_surface _surfaces[3]{};
|
||||
time_it timer{};
|
||||
|
||||
bool resized{ false };
|
||||
bool is_restarting{ false };
|
||||
void destroy_camera_surface(camera_surface& surface);
|
||||
game_entity::entity create_one_game_entity(math::v3 position, math::v3 rotation, const char* script_name);
|
||||
bool test_initialize();
|
||||
void test_shutdown();
|
||||
id::id_type create_render_item(id::id_type entity_id);
|
||||
void destroy_render_item(id::id_type item_id);
|
||||
|
||||
void generate_lights();
|
||||
void remove_lights();
|
||||
|
||||
LRESULT win_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
bool toggle_fullscreen{ false };
|
||||
switch (msg)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
{
|
||||
bool all_closed{ true };
|
||||
for (u32 i{ 0 }; i < _countof(_surfaces); ++i)
|
||||
{
|
||||
if (_surfaces[i].surface.window.is_valid())
|
||||
{
|
||||
|
||||
if (_surfaces[i].surface.window.is_closed())
|
||||
{
|
||||
destroy_camera_surface(_surfaces[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
all_closed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (all_closed && !is_restarting)
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case WM_SIZE:
|
||||
resized = (wparam != SIZE_MINIMIZED);
|
||||
break;
|
||||
case WM_SYSCHAR:
|
||||
toggle_fullscreen = (wparam == VK_RETURN && (HIWORD(lparam) & KF_ALTDOWN));
|
||||
break;
|
||||
case WM_KEYDOWN:
|
||||
if (wparam == VK_ESCAPE)
|
||||
{
|
||||
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
else if (wparam == VK_F11)
|
||||
{
|
||||
is_restarting = true;
|
||||
test_shutdown();
|
||||
test_initialize();
|
||||
}
|
||||
}
|
||||
|
||||
if ((resized & (GetAsyncKeyState(VK_LBUTTON) >= 0)) || toggle_fullscreen)
|
||||
{
|
||||
platform::window win{ platform::window_id{(id::id_type)GetWindowLongPtr(hwnd, GWLP_USERDATA)} };
|
||||
for (u32 i{ 0 }; i < _countof(_surfaces); ++i)
|
||||
{
|
||||
if (win.get_id() == _surfaces[i].surface.window.get_id())
|
||||
{
|
||||
if (toggle_fullscreen)
|
||||
{
|
||||
win.set_fullscreen(!win.is_fullscreen());
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_surfaces[i].surface.surface.resize(win.width(), win.height());
|
||||
_surfaces[i].camera.aspect_ratio((f32)win.width() / win.height());
|
||||
resized = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
void
|
||||
create_camera_surface(camera_surface& surface, platform::window_init_info info)
|
||||
{
|
||||
surface.surface.window = platform::create_window(&info);
|
||||
surface.surface.surface = graphics::create_surface(surface.surface.window);
|
||||
surface.entity = create_one_game_entity({ 0.0f,0.f,6.0f }, { 0.f, 3.14f, 0.f }, nullptr);
|
||||
surface.camera = graphics::create_camera(graphics::perspective_camera_init_info{ surface.entity.get_id() });
|
||||
surface.camera.aspect_ratio((f32)surface.surface.window.width() / surface.surface.window.height());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
destroy_camera_surface(camera_surface& surface)
|
||||
{
|
||||
camera_surface temp{ surface };
|
||||
surface = {};
|
||||
if (temp.surface.surface.is_valid()) graphics::remove_surface(temp.surface.surface.get_id());
|
||||
if (temp.surface.window.is_valid()) platform::remove_window(temp.surface.window.get_id());
|
||||
if (temp.camera.is_valid()) graphics::remove_camera(temp.camera.get_id());
|
||||
if (temp.entity.is_valid()) game_entity::remove(temp.entity.get_id());
|
||||
}
|
||||
|
||||
game_entity::entity
|
||||
create_one_game_entity(math::v3 position, math::v3 rotation, const char* script_name)
|
||||
{
|
||||
transform::init_info transform_info{};
|
||||
DirectX::XMVECTOR quat{ DirectX::XMQuaternionRotationRollPitchYawFromVector(DirectX::XMLoadFloat3(&rotation)) };
|
||||
math::v4a rot_quat;
|
||||
DirectX::XMStoreFloat4A(&rot_quat, quat);
|
||||
memcpy(&transform_info.rotation[0], &rot_quat.x, sizeof(transform_info.rotation));
|
||||
memcpy(&transform_info.position[0], &position.x, sizeof(transform_info.position));
|
||||
|
||||
script::init_info script_info{};
|
||||
if (script_name)
|
||||
{
|
||||
script_info.script_creator = script::detail::get_script_creator(script::detail::string_hash()(script_name));
|
||||
assert(script_info.script_creator);
|
||||
}
|
||||
|
||||
|
||||
game_entity::entity_info entity_info{};
|
||||
entity_info.transform = &transform_info;
|
||||
entity_info.script = &script_info;
|
||||
|
||||
game_entity::entity ntt{ game_entity::create(entity_info) };
|
||||
assert(ntt.is_valid());
|
||||
return ntt;
|
||||
}
|
||||
|
||||
void
|
||||
remove_game_entity(game_entity::entity_id id)
|
||||
{
|
||||
game_entity::remove(id);
|
||||
}
|
||||
|
||||
bool
|
||||
read_file(std::filesystem::path path, std::unique_ptr<u8[]>&data, u64& size)
|
||||
{
|
||||
if (!std::filesystem::exists(path)) return false;
|
||||
|
||||
size = std::filesystem::file_size(path);
|
||||
assert(size);
|
||||
if (!size) return false;
|
||||
data = std::make_unique<u8[]>(size);
|
||||
std::ifstream file{ path, std::ios::in | std::ios::binary };
|
||||
if (!file || !file.read((char*)data.get(), size))
|
||||
{
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
test_initialize()
|
||||
{
|
||||
while (!compile_shaders())
|
||||
{
|
||||
if (MessageBox(nullptr, L"Failed to compile engine shaders.", L"sahder Compilation Error", MB_RETRYCANCEL) != IDRETRY)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!graphics::initialize(graphics::graphics_platform::direct3d12))
|
||||
return false;
|
||||
|
||||
platform::window_init_info info[]
|
||||
{
|
||||
{&win_proc, nullptr, L"Test Window 1", 200, 100,400,400},
|
||||
{&win_proc, nullptr, L"Test Window 2", 700, 100,400,400},
|
||||
{&win_proc, nullptr, L"Test Window 3", 1200,100,400,400},/*
|
||||
{&win_proc, nullptr, L"Test Window 4", 200, 600,400,400},
|
||||
{&win_proc, nullptr, L"Test Window 5", 700, 600,400,400},
|
||||
{&win_proc, nullptr, L"Test Window 6", 1200,600,400,400},*/
|
||||
};
|
||||
static_assert(_countof(info) == _countof(_surfaces));
|
||||
for (u32 i{ 0 }; i < _countof(_surfaces); ++i)
|
||||
create_camera_surface(_surfaces[i], info[i]);
|
||||
|
||||
|
||||
//load test model
|
||||
std::unique_ptr<u8[]> model;
|
||||
u64 size{ 0 };
|
||||
if (!read_file("..\\..\\enginetest\\model.model", model, size)) return false;
|
||||
model_id = content::create_resource(model.get(), content::asset_type::mesh);
|
||||
if (!id::is_valid(model_id))return false;
|
||||
init_test_workers(buffer_test_worker);
|
||||
|
||||
item_id = create_render_item(create_one_game_entity({ }, { }, nullptr).get_id());
|
||||
|
||||
generate_lights();
|
||||
|
||||
is_restarting = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
test_shutdown()
|
||||
{
|
||||
remove_lights();
|
||||
destroy_render_item(item_id);
|
||||
joint_test_workers();
|
||||
|
||||
if (id::is_valid(model_id))
|
||||
{
|
||||
content::destroy_resource(model_id, content::asset_type::mesh);
|
||||
}
|
||||
for (u32 i{ 0 }; i < _countof(_surfaces); ++i)
|
||||
destroy_camera_surface(_surfaces[i]);
|
||||
|
||||
graphics::shutdown();
|
||||
}
|
||||
|
||||
bool
|
||||
engine_test::initialize()
|
||||
{
|
||||
return test_initialize();
|
||||
}
|
||||
|
||||
void
|
||||
engine_test::run()
|
||||
{
|
||||
timer.begin();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
script::update(timer.dt_avg());
|
||||
for (u32 i{ 0 }; i < _countof(_surfaces); ++i)
|
||||
{
|
||||
if (_surfaces[i].surface.surface.is_valid())
|
||||
{
|
||||
f32 threshold{ 10 };
|
||||
|
||||
graphics::frame_info info{};
|
||||
info.render_item_ids = &item_id;
|
||||
info.render_item_count = 1;
|
||||
info.thresholds = &threshold;
|
||||
info.light_set_key = 0;
|
||||
info.average_frame_time = timer.dt_avg();
|
||||
info.camera_id = _surfaces[i].camera.get_id();
|
||||
|
||||
_surfaces[i].surface.surface.render(info);
|
||||
}
|
||||
}
|
||||
timer.end();
|
||||
}
|
||||
bool
|
||||
engine_test::shutdown()
|
||||
{
|
||||
test_shutdown();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
154
EngineTest/TestShader.hlsl
Normal file
154
EngineTest/TestShader.hlsl
Normal file
@@ -0,0 +1,154 @@
|
||||
//#include "../Engine/Graphics/Direct3D12/Shaders/Common.hlsli"
|
||||
#include "D:\AllWX\AllC\XEngine\Engine\Graphics\Direct3D12\Shaders\Common.hlsli"
|
||||
|
||||
struct VertexOut
|
||||
{
|
||||
float4 HomogeneousPosition : SV_Position;
|
||||
float3 WorldPosition : POSITIONT;
|
||||
float3 WorldNormal : NORMAL;
|
||||
float3 WorldTangent : TANGENT;
|
||||
float2 uv : TEXTURE;
|
||||
};
|
||||
|
||||
struct PixelOut
|
||||
{
|
||||
float4 Color : SV_TARGET0;
|
||||
};
|
||||
|
||||
#define ElementsTypeStaticNormal 0x01
|
||||
#define ElementsTypeStaticNormalTexture 0x03
|
||||
#define ElementsTypeStaticColor 0x04
|
||||
#define ElementsTypeSkeletal 0x08
|
||||
#define ElementsTypeSkeletalColor ElementsTypeSkeletal | ElementsTypeStaticColor
|
||||
#define ElementsTypeSkeletalNormal ElementsTypeSkeletal | ElementsTypeStaticNormal
|
||||
#define ElementsTypeSkeletalNormalColor ElementsTypeSkeletalNormal | ElementsTypeSkeletalColor
|
||||
#define ElementsTypeSkeletalNormalTexture ElementsTypeSkeletal | ElementsTypeStaticNormalTexture
|
||||
#define ElementsTypeSkeletalNormalTextureColor ElementsTypeSkeletalNormalTexture | ElementsTypeStaticColor
|
||||
|
||||
struct VertexElement
|
||||
{
|
||||
#if ELEMENTS_TYPE == ElementsTypeStaticNormal
|
||||
uint ColorTSign;
|
||||
uint16_t2 Normal;
|
||||
#elif ELEMENTS_TYPE == ElementsTypeStaticNormalTexture
|
||||
uint ColorTSign;
|
||||
uint16_t2 Normal;
|
||||
uint16_t2 Tangent;
|
||||
float2 UV;
|
||||
#elif ELEMENTS_TYPE == ElementsTypeStaticColor
|
||||
#elif ELEMENTS_TYPE == ElementsTypeSkeletal
|
||||
#elif ELEMENTS_TYPE == ElementsTypeSkeletalColor
|
||||
#elif ELEMENTS_TYPE == ElementsTypeSkeletalNormal
|
||||
#elif ELEMENTS_TYPE == ElementsTypeSkeletalNormalColor
|
||||
#elif ELEMENTS_TYPE == ElementsTypeSkeletalNormalTexture
|
||||
#elif ELEMENTS_TYPE == ElementsTypeSkeletalNormalTextureColor
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
const static float InvIntervals = 2.f / ((1 << 16) - 1);
|
||||
|
||||
ConstantBuffer<GlobalShaderData> GlobalData : register(b0, space0);
|
||||
ConstantBuffer<PerObjectData> PerObjectBuffer : register(b1, space0);
|
||||
StructuredBuffer<float3> VertexPositions : register(t0, space0);
|
||||
StructuredBuffer<VertexElement> Elements : register(t1, space0);
|
||||
|
||||
StructuredBuffer<DirectionalLightParameters> DirectionLights : register(t3, space0);
|
||||
|
||||
VertexOut TestShaderVS(in uint VertexIdx : SV_VertexID)
|
||||
{
|
||||
VertexOut vsOut;
|
||||
float4x4 IdentityMatrix =
|
||||
{
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
float4 position = float4(VertexPositions[VertexIdx], 1.f);
|
||||
float4 worldPosition = mul(PerObjectBuffer.World, position);
|
||||
|
||||
#if ELEMENTS_TYPE == ElementsTypeStaticNormal
|
||||
VertexElement element = Elements[VertexIdx];
|
||||
float2 nXY = element.Normal * InvIntervals - 1.f;
|
||||
uint signs = (element.ColorTSign >> 24) & 0xff;
|
||||
|
||||
float nSign = float(signs & 0x02) - 1;
|
||||
float3 normal = float3(nXY.x, nXY.y, sqrt(saturate(1.f - dot(normal.xy, normal.xy))) * nSign);
|
||||
|
||||
vsOut.HomogeneousPosition = mul(PerObjectBuffer.WorldViewProjection, position);
|
||||
vsOut.WorldPosition = worldPosition.xyz;
|
||||
vsOut.WorldNormal = 0;
|
||||
vsOut.WorldTangent = 0.f;
|
||||
vsOut.uv = 0.f;
|
||||
#elif ELEMENTS_TYPE == ElementsTypeStaticNormalTexture
|
||||
VertexElement element = Elements[VertexIdx];
|
||||
float2 nXY = element.Normal * InvIntervals - 1.f;
|
||||
uint signs = (element.ColorTSign >> 24) & 0xff;
|
||||
|
||||
float nSign = float(signs & 0x02) - 1;
|
||||
float3 normal = float3(nXY.x, nXY.y, sqrt(saturate(1.f - dot(normal.xy, normal.xy))) * nSign);
|
||||
|
||||
vsOut.HomogeneousPosition = mul(PerObjectBuffer.WorldViewProjection, position);
|
||||
vsOut.WorldPosition = worldPosition.xyz;
|
||||
vsOut.WorldNormal = mul(float4(normal, 0.f), PerObjectBuffer.InvWorld).xyz;
|
||||
vsOut.WorldNormal = mul(PerObjectBuffer.World, float4(normal, 0.f)).xyz;
|
||||
//vsOut.WorldNormal = sqrt(saturate(1.f - dot(normal.xy, normal.xy))) * nSign;
|
||||
vsOut.WorldTangent = 0.f;
|
||||
vsOut.uv = 0.f;
|
||||
#else
|
||||
#undef ELEMENTS_TYPE
|
||||
vsOut.HomogeneousPosition = mul(PerObjectBuffer.WorldViewProjection, position);
|
||||
vsOut.WorldPosition = worldPosition.xyz;
|
||||
vsOut.WorldNormal = 0.f;
|
||||
vsOut.WorldTangent = 0.f;
|
||||
vsOut.uv = 0.f;
|
||||
#endif
|
||||
|
||||
return vsOut;
|
||||
}
|
||||
|
||||
[earlydepthstencil]
|
||||
PixelOut TestShaderPS(in VertexOut psIn)
|
||||
{
|
||||
PixelOut psOut;
|
||||
psOut.Color = float4(psIn.WorldNormal, 1);
|
||||
float4x4 IdentityMatrix =
|
||||
{
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
float3 normal = normalize(psIn.WorldNormal);
|
||||
float3 viewDir = normalize(GlobalData.CameraPosition - psIn.WorldPosition);
|
||||
|
||||
float3 color = 0;
|
||||
|
||||
for (uint i = 0; i < GlobalData.NumIdrectionalLights; ++i)
|
||||
{
|
||||
DirectionalLightParameters light = DirectionLights[i];
|
||||
|
||||
float3 lr = normalize(light.Direction);
|
||||
float3 lightDirection = mul(IdentityMatrix, float4(lr, 0)).xyz;
|
||||
|
||||
//float3 lightDirection = normalize(float3(0, 1, 0));
|
||||
float diffuse = max(dot(normal, -lightDirection), 0.f);
|
||||
float3 h = (viewDir + lightDirection);
|
||||
float specular = pow(max(dot(normal, h), 0.f), 16) * 0.5f;
|
||||
|
||||
|
||||
//float3 lightColor = float3(1, 1, 1);
|
||||
float3 lightColor = light.Color * light.Intensity;
|
||||
//color = dot(normal, -lr);
|
||||
color = normal;
|
||||
}
|
||||
|
||||
|
||||
float3 ambient = 10 / 255.f;
|
||||
psOut.Color = saturate(float4(color + ambient, 1.f));
|
||||
|
||||
return psOut;
|
||||
}
|
||||
78
EngineTest/TestWindow.h
Normal file
78
EngineTest/TestWindow.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @file TestWindow.h
|
||||
* @brief 窗口系统测试用例实现。
|
||||
*/
|
||||
#pragma once
|
||||
#include "Test.h"
|
||||
#include "..\Platform\Platform.h"
|
||||
#include "..\Platform\PlatformTypes.h"
|
||||
|
||||
using namespace XEngine;
|
||||
|
||||
platform::window _windows[4];
|
||||
|
||||
LRESULT win_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
{
|
||||
bool all_closed{ true };
|
||||
for (u32 i{ 0 }; i < _countof(_windows); ++i)
|
||||
{
|
||||
if (!_windows[i].is_closed())
|
||||
{
|
||||
all_closed = false;
|
||||
}
|
||||
}
|
||||
if (all_closed)
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case WM_SYSCHAR:
|
||||
if (wparam == VK_RETURN && (HIWORD(lparam) & KF_ALTDOWN))
|
||||
{
|
||||
platform::window win{ platform::window_id{(id::id_type)GetWindowLongPtr(hwnd, GWLP_USERDATA)} };
|
||||
win.set_fullscreen(!win.is_fullscreen());
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
class engine_test :public Test
|
||||
{
|
||||
public:
|
||||
bool initialize() override
|
||||
{
|
||||
platform::window_init_info info[]
|
||||
{
|
||||
{&win_proc, nullptr, L"Test Window 1", 100,100,400,800},
|
||||
{&win_proc, nullptr, L"Test Window 2", 150,200,400,700},
|
||||
{&win_proc, nullptr, L"Test Window 3", 200,300,400,600},
|
||||
{&win_proc, nullptr, L"Test Window 4", 150,400,400,500},
|
||||
};
|
||||
static_assert(_countof(info) == _countof(_windows));
|
||||
for (u32 i{ 0 }; i < _countof(_windows); ++i)
|
||||
_windows[i] = platform::create_window(&info[i]);
|
||||
return true;
|
||||
}
|
||||
void run() override
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
bool shutdown() override
|
||||
{
|
||||
for (u32 i{ 0 }; i < _countof(_windows); ++i)
|
||||
platform::remove_window(_windows[i].get_id());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
BIN
EngineTest/model.model
Normal file
BIN
EngineTest/model.model
Normal file
Binary file not shown.
Reference in New Issue
Block a user