356 lines
8.7 KiB
C++
356 lines
8.7 KiB
C++
/**
|
|
* @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
|