feat: initial DX12 foundation framework
This commit is contained in:
217
Engine/Content/ContentLoader.cpp
Normal file
217
Engine/Content/ContentLoader.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* @file ContentLoader.cpp
|
||||
* @brief 关卡内容反序列化与实体创建流程实现。
|
||||
* @details
|
||||
* 主要流程为:读取二进制关卡文件 -> 解析组件块 -> 创建实体并绑定脚本/变换。
|
||||
* 同时提供运行期清理逻辑,确保测试场景退出时能回收创建的实体与资源。
|
||||
* 本实现仅在非 SHIPPING 且 Win64 条件下启用。
|
||||
*/
|
||||
#include "ContentLoader.h"
|
||||
#include "..\Components\Script.h"
|
||||
|
||||
#include "..\EngineAPI\GameEntity.h"
|
||||
#include "..\EngineAPI\TransformComponent.h"
|
||||
#include "..\EngineAPI\ScriptComponent.h"
|
||||
#include "..\Components\Entity.h"
|
||||
#include "Graphics\Renderer.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <Windows.h>
|
||||
|
||||
#if !defined(SHIPPING) && defined(_WIN64)
|
||||
|
||||
namespace XEngine::content {
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief 关卡文件中的组件类型标签。
|
||||
*/
|
||||
enum component_type
|
||||
{
|
||||
transform,
|
||||
script,
|
||||
|
||||
count
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 已创建的实体缓存,用于卸载阶段统一回收。
|
||||
*/
|
||||
utl::vector<game_entity::entity> entities;
|
||||
/**
|
||||
* @brief 解析变换组件时复用的临时结构。
|
||||
*/
|
||||
transform::init_info transform_info{};
|
||||
/**
|
||||
* @brief 解析脚本组件时复用的临时结构。
|
||||
*/
|
||||
script::init_info script_info{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 从二进制流读取变换组件数据。
|
||||
* @param data 当前读取游标,函数返回后移动到组件末尾。
|
||||
* @param info 目标实体初始化信息。
|
||||
* @return 读取成功返回 true。
|
||||
*/
|
||||
bool
|
||||
read_transform(const u8*& data, game_entity::entity_info& info)
|
||||
{
|
||||
using namespace DirectX;
|
||||
f32 rotation[3];
|
||||
|
||||
assert(!info.transform);
|
||||
memcpy(&transform_info.position[0], data, sizeof(transform_info.position)); data += sizeof(transform_info.position);
|
||||
memcpy(&rotation[0], data, sizeof(rotation)); data += sizeof(rotation);
|
||||
memcpy(&transform_info.scale[0], data, sizeof(transform_info.scale)); data += sizeof(transform_info.scale);
|
||||
|
||||
|
||||
XMFLOAT3A rot{ &rotation[0] };
|
||||
XMVECTOR quat{ XMQuaternionRotationRollPitchYawFromVector(XMLoadFloat3A(&rot)) };
|
||||
XMFLOAT4A rot_quat{};
|
||||
XMStoreFloat4A(&rot_quat, quat);
|
||||
memcpy(&transform_info.rotation[0], &rot_quat.x, sizeof(transform_info.rotation));
|
||||
|
||||
info.transform = &transform_info;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 从二进制流读取脚本组件并查找脚本工厂。
|
||||
* @param data 当前读取游标,函数返回后移动到组件末尾。
|
||||
* @param info 目标实体初始化信息。
|
||||
* @return 解析并找到脚本工厂返回 true。
|
||||
*/
|
||||
bool
|
||||
read_script(const u8*& data, game_entity::entity_info& info)
|
||||
{
|
||||
assert(!info.script);
|
||||
const u32 name_length{ *data }; data += sizeof(u32);
|
||||
if (!name_length) return false;
|
||||
|
||||
assert(name_length < 256);
|
||||
char script_name[256];
|
||||
memcpy(&script_name, data, name_length); data += name_length;
|
||||
script_name[name_length] = 0;
|
||||
script_info.script_creator = script::detail::get_script_creator(script::detail::string_hash()(script_name));
|
||||
info.script = &script_info;
|
||||
return script_info.script_creator != nullptr;
|
||||
}
|
||||
|
||||
using compoent_reader = bool(*)(const u8*&, game_entity::entity_info&);
|
||||
compoent_reader component_readers[]
|
||||
{
|
||||
read_transform,
|
||||
read_script,
|
||||
};
|
||||
|
||||
static_assert(_countof(component_readers) == component_type::count);
|
||||
|
||||
/**
|
||||
* @brief 读取完整二进制文件到内存缓冲区。
|
||||
* @param path 文件路径。
|
||||
* @param data 输出缓冲区。
|
||||
* @param size 输出字节数。
|
||||
* @return 成功返回 true。
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/**
|
||||
* @brief 加载 game.bin 并批量创建实体。
|
||||
* @return 全部实体创建成功返回 true。
|
||||
*/
|
||||
bool
|
||||
load_games()
|
||||
{
|
||||
|
||||
|
||||
|
||||
std::unique_ptr<u8[]> game_data{};
|
||||
u64 size{ 0 };
|
||||
if (!read_file("game.bin", game_data, size)) return false;
|
||||
assert(game_data.get());
|
||||
const u8* at{ game_data.get() };
|
||||
constexpr u32 su32{ sizeof(u32) };
|
||||
const u32 num_entities{ *at }; at += su32;
|
||||
if (!num_entities) return false;
|
||||
|
||||
for (u32 entity_index{ 0 }; entity_index < num_entities; ++entity_index)
|
||||
{
|
||||
game_entity::entity_info info{};
|
||||
|
||||
const u32 entity_type{ *at }; at += su32;
|
||||
const u32 num_components{ *at }; at += su32;
|
||||
if (!num_components)return false;
|
||||
|
||||
for (u32 component_index{ 0 }; component_index < num_components; ++component_index)
|
||||
{
|
||||
const u32 component_type{ *at }; at += su32;
|
||||
assert(component_type < component_type::count);
|
||||
if (!component_readers[component_type](at, info)) return false;
|
||||
}
|
||||
|
||||
assert(info.transform);
|
||||
game_entity::entity entity{ game_entity::create(info) };
|
||||
if (!entity.is_valid()) return false;
|
||||
entities.emplace_back(entity);
|
||||
}
|
||||
|
||||
assert(at == game_data.get() + size);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 回收 load_games 创建的实体对象。
|
||||
*/
|
||||
void
|
||||
unload_game()
|
||||
{
|
||||
for (auto entity : entities)
|
||||
{
|
||||
game_entity::remove(entity.get_id());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 加载引擎内置着色器二进制文件。
|
||||
* @param shaders 输出字节缓冲区。
|
||||
* @param size 输出字节大小。
|
||||
* @return 加载成功返回 true。
|
||||
*/
|
||||
//bool
|
||||
//load_engine_shaders(std::unique_ptr<u8[]>&shaders, u64& size)
|
||||
//{
|
||||
// auto path = graphics::get_engine_shaders_path();
|
||||
// return read_file(path, shaders, size);
|
||||
//}
|
||||
|
||||
}
|
||||
#endif //!defined(SHIPPING)
|
||||
35
Engine/Content/ContentLoader.h
Normal file
35
Engine/Content/ContentLoader.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @file ContentLoader.h
|
||||
* @brief 编辑器/测试构建下的关卡内容加载入口声明。
|
||||
* @details
|
||||
* 本文件定义内容系统对外暴露的高层加载接口,负责:
|
||||
* - 从磁盘加载测试关卡与实体描述;
|
||||
* - 卸载已创建的实体与运行时资源;
|
||||
* - 读取并返回引擎着色器二进制数据供渲染模块初始化。
|
||||
*/
|
||||
#pragma once
|
||||
#include "CommonHeader.h"
|
||||
|
||||
#if !defined(SHIPPING)
|
||||
namespace XEngine::content {
|
||||
/**
|
||||
* @brief 加载测试游戏内容并创建对应运行时对象。
|
||||
* @return 加载成功返回 true,否则返回 false。
|
||||
*/
|
||||
bool load_games();
|
||||
/**
|
||||
* @brief 卸载由 load_games 创建的内容与对象。
|
||||
*/
|
||||
void unload_game();
|
||||
|
||||
|
||||
/**
|
||||
* @brief 从内容目录读取引擎着色器二进制文件。
|
||||
* @param shader 输出的字节缓冲区。
|
||||
* @param size 输出的缓冲区大小(字节)。
|
||||
* @return 读取成功返回 true,否则返回 false。
|
||||
*/
|
||||
bool load_engine_shaders(std::unique_ptr<u8[]>&shader, u64 size);
|
||||
}
|
||||
|
||||
#endif //!defined(SHIPPING)
|
||||
528
Engine/Content/ContentToEngine.cpp
Normal file
528
Engine/Content/ContentToEngine.cpp
Normal file
@@ -0,0 +1,528 @@
|
||||
/**
|
||||
* @file ContentToEngine.cpp
|
||||
* @brief 内容二进制数据到渲染/资源句柄的转换实现。
|
||||
* @details
|
||||
* 本文件完成导入数据的运行时落地,包含:
|
||||
* - 网格层级(LOD)结构重排与子网格 GPU 资源创建;
|
||||
* - 着色器分组缓存与 key 索引查询;
|
||||
* - 材质/纹理/几何资源的统一创建与释放入口。
|
||||
*/
|
||||
#include "ContentToEngine.h"
|
||||
#include "Graphics\Renderer.h"
|
||||
#include "Utilities\IOStream.h"
|
||||
|
||||
namespace XEngine::content {
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief 几何层级缓冲区的视图封装。
|
||||
* @details
|
||||
* 对连续内存中的几何层级布局进行字段映射,提供阈值、LOD 偏移与 GPU ID 访问。
|
||||
*/
|
||||
class geometry_hierarchy_stream
|
||||
{
|
||||
public:
|
||||
DISABLE_COPY_AND_MOVE(geometry_hierarchy_stream);
|
||||
|
||||
geometry_hierarchy_stream(u8 *const buffer, u32 lods = u32_invalid_id)
|
||||
:_buffer{ buffer }
|
||||
{
|
||||
assert(buffer && lods);
|
||||
if (lods != u32_invalid_id)
|
||||
{
|
||||
*((u32*)buffer) = lods;
|
||||
}
|
||||
|
||||
_lod_count = *((u32*)buffer);
|
||||
_thresholds = (f32*)(&buffer[sizeof(u32)]);
|
||||
_lod_offsets = (lod_offset*)(&_thresholds[_lod_count]);
|
||||
_gpu_ids = (id::id_type*)(&_lod_offsets[_lod_count]);
|
||||
}
|
||||
|
||||
void gpu_ids(u32 lod, id::id_type*& ids, u32& id_count)
|
||||
{
|
||||
assert(lod < _lod_count);
|
||||
ids = &_gpu_ids[_lod_offsets[lod].offset];
|
||||
id_count = _lod_offsets[lod].count;
|
||||
}
|
||||
|
||||
u32 lod_from_threshold(f32 threshold)
|
||||
{
|
||||
assert(threshold > 0);
|
||||
if (_lod_count == 1) return 0;
|
||||
|
||||
for (u32 i{ _lod_count - 1 }; i > 0; --i)
|
||||
{
|
||||
if (_thresholds[i] <= threshold) return i;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 lod_count() const { return _lod_count; }
|
||||
[[nodiscard]] constexpr f32* thresholds() const { return _thresholds; }
|
||||
[[nodiscard]] constexpr lod_offset* lod_offsets() const { return _lod_offsets; }
|
||||
[[nodiscard]] constexpr id::id_type* gpu_ids() const { return _gpu_ids; }
|
||||
private:
|
||||
u8 *const _buffer;
|
||||
f32* _thresholds;
|
||||
lod_offset* _lod_offsets;
|
||||
id::id_type* _gpu_ids;
|
||||
u32 _lod_count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 支持 noexcept 移动的着色器组缓存容器。
|
||||
*/
|
||||
struct noexcept_map {
|
||||
std::unordered_map<u32, std::unique_ptr<u8[]>> map;
|
||||
noexcept_map() = default;
|
||||
noexcept_map(const noexcept_map&) = default;
|
||||
noexcept_map(noexcept_map&&) noexcept = default;
|
||||
noexcept_map& operator=(const noexcept_map&) = default;
|
||||
noexcept_map& operator=(noexcept_map&&) noexcept = default;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 单子网格资源的指针标记位。
|
||||
*/
|
||||
constexpr uintptr_t single_mesh_marker{ (uintptr_t)0x01 };
|
||||
/**
|
||||
* @brief 几何层级资源池。
|
||||
*/
|
||||
utl::free_list<u8*> geometry_hierarchies;
|
||||
/**
|
||||
* @brief 几何资源互斥锁。
|
||||
*/
|
||||
std::mutex geometry_mutex;
|
||||
|
||||
/**
|
||||
* @brief 着色器组资源池。
|
||||
*/
|
||||
utl::free_list<noexcept_map> shader_groups;
|
||||
/**
|
||||
* @brief 着色器资源互斥锁。
|
||||
*/
|
||||
std::mutex shader_mutex;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 预估并计算几何层级缓冲区所需字节数。
|
||||
* @param data 几何二进制输入数据。
|
||||
* @return 所需缓冲区大小(字节)。
|
||||
*/
|
||||
u32
|
||||
get_geometry_hierarchy_buffer_size(const void *const data)
|
||||
{
|
||||
assert(data);
|
||||
utl::blob_stream_reader blob{ (const u8*)data };
|
||||
const u32 lod_count{ blob.reader<u32>() };
|
||||
assert(lod_count);
|
||||
constexpr u32 su32{ sizeof(u32) };
|
||||
|
||||
u32 size{ su32 + (sizeof(f32) + sizeof(lod_offset)) * lod_count };
|
||||
|
||||
for (u32 lod_idx{ 0 }; lod_idx < lod_count; ++lod_idx)
|
||||
{
|
||||
// skip threshold
|
||||
blob.skip(sizeof(f32));
|
||||
// add size of gpu_ids
|
||||
size += sizeof(id::id_type) * blob.reader<u32>();
|
||||
// skip submesh data and goto next LOD
|
||||
blob.skip(blob.reader<u32>());
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建多 LOD 网格层级资源。
|
||||
* @param data 几何二进制输入数据。
|
||||
* @return 几何内容资源 ID。
|
||||
*/
|
||||
//id::id_type
|
||||
//create_mesh_hierarchy(const void *const data)
|
||||
//{
|
||||
// assert(data);
|
||||
//
|
||||
// const u32 size{ get_geometry_hierarchy_buffer_size(data) };
|
||||
// u8 *const hierarchy_buffer{ (u8 *const)malloc(size) };
|
||||
//
|
||||
// utl::blob_stream_reader blob{ (const u8*)data };
|
||||
// const u32 lod_count{ blob.reader<u32>() };
|
||||
// assert(lod_count);
|
||||
// geometry_hierarchy_stream stream{ hierarchy_buffer, lod_count };
|
||||
// u32 submesh_index{ 0 };
|
||||
// id::id_type *const gpu_ids{ stream.gpu_ids() };
|
||||
//
|
||||
// for (u32 lod_idx{ 0 }; lod_idx < lod_count; ++lod_idx)
|
||||
// {
|
||||
// stream.thresholds()[lod_idx] = blob.reader<f32>();
|
||||
// const u32 id_count{ blob.reader<u32>() };
|
||||
// assert(id_count < (1 << 16));
|
||||
// stream.lod_offsets()[lod_idx] = { (u16)submesh_index, (u16)id_count };
|
||||
// blob.skip(sizeof(u32)); // skip sizeof submeshes
|
||||
// for (u32 id_idx{ 0 }; id_idx < id_count; ++id_idx)
|
||||
// {
|
||||
// const u8* at{ blob.position() };
|
||||
// gpu_ids[submesh_index++] = graphics::add_submesh(at);
|
||||
// blob.skip((u32)(at - blob.position()));
|
||||
// assert(submesh_index < (1 << 16));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// assert([&]()
|
||||
// {
|
||||
// f32 previous_theshold{ stream.thresholds()[0] };
|
||||
// for (u32 i{ 1 }; i < lod_count; ++i)
|
||||
// {
|
||||
// if (stream.thresholds()[i] <= previous_theshold) return false;
|
||||
// previous_theshold = stream.thresholds()[i];
|
||||
// }
|
||||
// return true;
|
||||
// }());
|
||||
//
|
||||
// static_assert(alignof(void*) > 2, "We need the least significant bit for th single mesh marker.");
|
||||
// std::lock_guard lock{ geometry_mutex };
|
||||
// return geometry_hierarchies.add(hierarchy_buffer);
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief 判断几何数据是否为单 LOD 单子网格。
|
||||
* @param data 几何二进制输入数据。
|
||||
* @return 单子网格返回 true。
|
||||
*/
|
||||
bool
|
||||
is_single_mesh(const void *const data)
|
||||
{
|
||||
assert(data);
|
||||
utl::blob_stream_reader blob{ (const u8*)data };
|
||||
const u32 lod_count{ blob.reader<u32>() };
|
||||
assert(lod_count);
|
||||
if (lod_count > 1) return false;
|
||||
|
||||
|
||||
blob.skip(sizeof(f32)); // skip threhold
|
||||
const u32 submesh_count{ blob.reader<u32>() };
|
||||
assert(submesh_count);
|
||||
return submesh_count == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建单子网格资源并编码为伪指针句柄。
|
||||
* @param data 几何二进制输入数据。
|
||||
* @return 几何内容资源 ID。
|
||||
*/
|
||||
//id::id_type
|
||||
//create_single_submesh(const void *const data)
|
||||
//{
|
||||
// assert(data);
|
||||
// utl::blob_stream_reader blob{ (const u8*)data };
|
||||
// // skip lod_count, lod_threshold, submesh_count, and sizeof_submeshes
|
||||
// blob.skip(sizeof(u32) + sizeof(f32) + sizeof(u32) + sizeof(u32));
|
||||
// const u8* at{ blob.position() };
|
||||
// const id::id_type gpu_id{ graphics::add_submesh(at) };
|
||||
//
|
||||
// // create a fake pointer and put it in the geometry_hierarchies.
|
||||
// static_assert(sizeof(uintptr_t) > sizeof(id::id_type));
|
||||
// constexpr u8 shift_bits{ (sizeof(uintptr_t) - sizeof(id::id_type)) << 3 };
|
||||
// u8 *const fake_pointer{ (u8 *const)((((uintptr_t)gpu_id) << shift_bits) | single_mesh_marker) };
|
||||
// std::lock_guard lock{ geometry_mutex };
|
||||
// return geometry_hierarchies.add(fake_pointer);
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief 从单子网格伪指针解码 GPU 资源 ID。
|
||||
* @param pointer 编码后的伪指针。
|
||||
* @return GPU 子网格 ID。
|
||||
*/
|
||||
constexpr id::id_type
|
||||
gpu_id_from_fake_pointer(u8 *const pointer)
|
||||
{
|
||||
assert((uintptr_t)pointer & single_mesh_marker);
|
||||
static_assert(sizeof(uintptr_t) > sizeof(id::id_type));
|
||||
constexpr u8 shift_bits{ (sizeof(uintptr_t) - sizeof(id::id_type)) << 3 };
|
||||
return (((uintptr_t)pointer) >> shift_bits) & (uintptr_t)id::invalid_id;
|
||||
}
|
||||
//
|
||||
// data contain:
|
||||
//struct{
|
||||
// u32 lod_count,
|
||||
// struct{
|
||||
// f32 lod_threshold,
|
||||
// u32 submesh_count,
|
||||
// u32 sizeof_submeshes,
|
||||
// struct{
|
||||
// u32 element_size, u32 vertex_count,
|
||||
// u32 index_count, u32 elements_type, u32 primitive_topology
|
||||
// u8 positions[sizeof(f32) * 3 * vertex_count],
|
||||
// u8 elements[sizeof(element_size) * vertex_count],
|
||||
// u8 indices[index_size * index_count],
|
||||
// } submeshes[submesh_count]
|
||||
// }mesh_lods[lod_count]
|
||||
// } geometry;
|
||||
//
|
||||
// Output format
|
||||
//
|
||||
// struct{
|
||||
// u32 lod_count,
|
||||
// f32 thresholds[lod_count]
|
||||
// struct{
|
||||
// u16 offset,
|
||||
// u16 count
|
||||
// }lod_offsets[lod_count],
|
||||
// id::idtype gpu_ids[total_number_of_submeshes]
|
||||
//}geometry_hierarchy
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief 按输入几何形态创建对应资源。
|
||||
* @param data 几何二进制输入数据。
|
||||
* @return 几何内容资源 ID。
|
||||
*/
|
||||
//id::id_type
|
||||
//create_geometry_resource(const void *const data)
|
||||
//{
|
||||
// assert(data);
|
||||
// return is_single_mesh(data) ? create_single_submesh(data) : create_mesh_hierarchy(data);
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief 销毁几何资源并释放关联子网格。
|
||||
* @param id 几何内容资源 ID。
|
||||
*/
|
||||
//void
|
||||
//destory_geometry_resource(id::id_type id)
|
||||
//{
|
||||
// std::lock_guard lock{ geometry_mutex };
|
||||
// u8 *const pointer{ geometry_hierarchies[id] };
|
||||
// if ((uintptr_t)pointer & single_mesh_marker)
|
||||
// {
|
||||
// graphics::remove_submesh(gpu_id_from_fake_pointer(pointer));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// geometry_hierarchy_stream stream{ pointer };
|
||||
// const u32 lod_count{ stream.lod_count() };
|
||||
// u32 id_index{ 0 };
|
||||
// for (u32 lod{ 0 }; lod < lod_count; ++lod)
|
||||
// {
|
||||
// for (u32 i{ 0 }; i < stream.lod_offsets()[lod].count; ++i)
|
||||
// {
|
||||
// graphics::remove_submesh(stream.gpu_ids()[id_index++]);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// free(pointer);
|
||||
// }
|
||||
//
|
||||
// geometry_hierarchies.remove(id);
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief 创建材质资源。
|
||||
* @param data 材质初始化数据。
|
||||
* @return 材质资源 ID。
|
||||
*/
|
||||
//id::id_type
|
||||
//create_material_resource(const void *const data)
|
||||
//{
|
||||
// assert(data);
|
||||
// return graphics::add_material(*(const graphics::material_init_info *const)data);
|
||||
//}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @brief 销毁材质资源。
|
||||
* @param id 材质资源 ID。
|
||||
*/
|
||||
//void
|
||||
//destory_material_resource(id::id_type id)
|
||||
//{
|
||||
// graphics::remove_material(id);
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief 统一资源创建入口。
|
||||
* @param data 资源二进制数据。
|
||||
* @param type 资源类型。
|
||||
* @return 资源 ID。
|
||||
*/
|
||||
//id::id_type
|
||||
//create_resource(const void *const data, asset_type::type type)
|
||||
//{
|
||||
// assert(data);
|
||||
// id::id_type id{ id::invalid_id };
|
||||
//
|
||||
// switch (type)
|
||||
// {
|
||||
// case XEngine::content::asset_type::unknown: break;
|
||||
// case XEngine::content::asset_type::animation: break;
|
||||
// case XEngine::content::asset_type::audio: break;
|
||||
// case XEngine::content::asset_type::material: id = create_material_resource(data); break;
|
||||
// case XEngine::content::asset_type::mesh: id = create_geometry_resource(data); break;
|
||||
// case XEngine::content::asset_type::skeleton: break;
|
||||
// case XEngine::content::asset_type::texture: break;
|
||||
// }
|
||||
//
|
||||
// assert(id::is_valid(id));
|
||||
// return id;
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 统一资源销毁入口。
|
||||
* @param id 资源 ID。
|
||||
* @param type 资源类型。
|
||||
*/
|
||||
//void
|
||||
//destroy_resource(id::id_type id, asset_type::type type)
|
||||
//{
|
||||
// assert(id::is_valid(id));
|
||||
// switch (type)
|
||||
// {
|
||||
// case XEngine::content::asset_type::unknown: break;
|
||||
// case XEngine::content::asset_type::animation: break;
|
||||
// case XEngine::content::asset_type::audio: break;
|
||||
// case XEngine::content::asset_type::material: destory_material_resource(id); break;
|
||||
// case XEngine::content::asset_type::mesh: destory_geometry_resource(id); break;
|
||||
// case XEngine::content::asset_type::skeleton: break;
|
||||
// case XEngine::content::asset_type::texture: break;
|
||||
// default:
|
||||
// assert(false);
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
/**
|
||||
* @brief 注册着色器组并复制其二进制数据。
|
||||
* @param shaders 着色器数组。
|
||||
* @param num_shaders 着色器数量。
|
||||
* @param keys 查询键数组。
|
||||
* @return 着色器组 ID。
|
||||
*/
|
||||
id::id_type
|
||||
add_shader_group(const u8 *const * shaders, u32 num_shaders, const u32 *const keys)
|
||||
{
|
||||
assert(shaders && num_shaders && keys);
|
||||
noexcept_map group;
|
||||
for (u32 i{ 0 }; i < num_shaders; ++i)
|
||||
{
|
||||
assert(shaders[i]);
|
||||
const compiled_shader_ptr shader_ptr{ (const compiled_shader_ptr)shaders[i] };
|
||||
const u64 size{ shader_ptr->buffer_size()};
|
||||
std::unique_ptr<u8[]> shader{ std::make_unique<u8[]>(size) };
|
||||
memcpy(shader.get(), shaders[i], size);
|
||||
group.map[keys[i]] = std::move(shader);
|
||||
}
|
||||
std::lock_guard lock{ shader_mutex };
|
||||
return shader_groups.add(std::move(group));
|
||||
}
|
||||
/**
|
||||
* @brief 删除着色器组。
|
||||
* @param id 着色器组 ID。
|
||||
*/
|
||||
void
|
||||
remove_shader_group(id::id_type id)
|
||||
{
|
||||
std::lock_guard lock{ shader_mutex };
|
||||
assert(id::is_valid(id));
|
||||
|
||||
shader_groups[id].map.clear();
|
||||
shader_groups.remove(id);
|
||||
}
|
||||
/**
|
||||
* @brief 在着色器组内按键查找着色器。
|
||||
* @param id 着色器组 ID。
|
||||
* @param shader_key 查询键。
|
||||
* @return 命中时返回着色器指针。
|
||||
*/
|
||||
compiled_shader_ptr
|
||||
get_shader(id::id_type id, u32 shader_key)
|
||||
{
|
||||
std::lock_guard lock{ shader_mutex };
|
||||
assert(id::is_valid(id));
|
||||
for (const auto& [key, value] : shader_groups[id].map)
|
||||
{
|
||||
if (key == shader_key)
|
||||
{
|
||||
return (const compiled_shader_ptr)value.get();
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取几何资源包含的全部子网格 GPU ID。
|
||||
* @param geometry_content_id 几何内容资源 ID。
|
||||
* @param id_count 输出数组长度。
|
||||
* @param gpu_ids 输出数组。
|
||||
*/
|
||||
void
|
||||
get_submesh_gpu_id(id::id_type geometry_content_id, u32 id_count, id::id_type *const gpu_ids)
|
||||
{
|
||||
std::lock_guard lock{ geometry_mutex };
|
||||
u8 *const pointer{ geometry_hierarchies[geometry_content_id] };
|
||||
if ((uintptr_t)pointer & single_mesh_marker)
|
||||
{
|
||||
assert(id_count == 1);
|
||||
*gpu_ids = gpu_id_from_fake_pointer(pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry_hierarchy_stream stream{ pointer };
|
||||
|
||||
assert([&]() {
|
||||
const u32 lod_count{ stream.lod_count() };
|
||||
const lod_offset lod_offset{ stream.lod_offsets()[lod_count - 1] };
|
||||
const u32 gpu_id_count{ (u32)lod_offset.offset + (u32)lod_offset.count };
|
||||
return gpu_id_count == id_count;
|
||||
}());
|
||||
|
||||
|
||||
memcpy(gpu_ids, stream.gpu_ids(), sizeof(id::id_type) * id_count);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按阈值查询各几何实例使用的 LOD 偏移。
|
||||
* @param geometry_ids 几何资源 ID 数组。
|
||||
* @param thresholds 每个实例的阈值数组。
|
||||
* @param id_count 查询数量。
|
||||
* @param offsets 输出 LOD 偏移数组。
|
||||
*/
|
||||
void
|
||||
get_lod_offset(const id::id_type *const geometry_ids, const f32 *const thresholds, u32 id_count, utl::vector<lod_offset>& offsets)
|
||||
{
|
||||
assert(geometry_ids && thresholds && id_count);
|
||||
assert(offsets.empty());
|
||||
|
||||
std::lock_guard lock{ geometry_mutex };
|
||||
|
||||
for (u32 i{ 0 }; i < id_count; ++i)
|
||||
{
|
||||
u8 *const pointer{ geometry_hierarchies[geometry_ids[i]] };
|
||||
if ((uintptr_t)pointer & single_mesh_marker)
|
||||
{
|
||||
assert(id_count == 1);
|
||||
offsets.emplace_back(lod_offset{ 0,1 });
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry_hierarchy_stream stream{ pointer };
|
||||
const u32 lod{ stream.lod_from_threshold(thresholds[i]) };
|
||||
offsets.emplace_back(stream.lod_offsets()[lod]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
133
Engine/Content/ContentToEngine.h
Normal file
133
Engine/Content/ContentToEngine.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @file ContentToEngine.h
|
||||
* @brief 内容系统到运行时资源系统的数据桥接接口。
|
||||
* @details
|
||||
* 该文件描述资源导入后的统一输入格式与运行时句柄接口,核心能力包括:
|
||||
* - 依据 asset_type 创建/销毁网格、材质、纹理等资源;
|
||||
* - 管理变体着色器组并按 key 查询编译结果;
|
||||
* - 提供几何 LOD 偏移与 GPU 子网格 ID 的查询能力。
|
||||
*/
|
||||
#pragma once
|
||||
#include "CommonHeader.h"
|
||||
|
||||
|
||||
namespace XEngine::content {
|
||||
|
||||
/**
|
||||
* @brief 资源类型枚举容器。
|
||||
*/
|
||||
struct asset_type {
|
||||
/**
|
||||
* @brief 运行时可识别的内容资源类型。
|
||||
*/
|
||||
enum type : u32
|
||||
{
|
||||
unknown = 0,
|
||||
animation,
|
||||
audio,
|
||||
material,
|
||||
mesh,
|
||||
skeleton,
|
||||
texture,
|
||||
|
||||
count
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 指定某个 LOD 在子网格数组中的起始偏移与数量。
|
||||
*/
|
||||
struct lod_offset
|
||||
{
|
||||
u16 offset;
|
||||
u16 count;
|
||||
};
|
||||
|
||||
|
||||
typedef struct compiled_shader {
|
||||
|
||||
/**
|
||||
* @brief 着色器哈希的固定字节数。
|
||||
*/
|
||||
static constexpr u32 hash_length{ 16 };
|
||||
/**
|
||||
* @brief 获取字节码长度。
|
||||
*/
|
||||
constexpr u64 byte_code_size() const { return _byte_code_size; }
|
||||
/**
|
||||
* @brief 获取哈希数据首地址。
|
||||
*/
|
||||
constexpr const u8 *const hash() const { return &_hash[0]; }
|
||||
/**
|
||||
* @brief 获取字节码首地址。
|
||||
*/
|
||||
constexpr const u8 *const byte_code() const { return &_byte_code; }
|
||||
/**
|
||||
* @brief 获取当前对象对应的总缓冲区长度。
|
||||
*/
|
||||
constexpr const u64 buffer_size() const { return sizeof(_byte_code_size ) + hash_length + _byte_code_size; }
|
||||
/**
|
||||
* @brief 根据字节码大小计算总缓冲区长度。
|
||||
*/
|
||||
constexpr static u64 buffer_size(u64 size) { return sizeof(_byte_code_size ) + hash_length + size; }
|
||||
|
||||
private:
|
||||
u64 _byte_code_size;
|
||||
u8 _hash[hash_length];
|
||||
u8 _byte_code;
|
||||
}const *compiled_shader_ptr;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 根据二进制内容创建对应运行时资源。
|
||||
* @param data 编译后的资源二进制数据。
|
||||
* @param type 资源类型。
|
||||
* @return 新创建资源的 ID。
|
||||
*/
|
||||
id::id_type create_resource(const void *const data, asset_type::type type);
|
||||
/**
|
||||
* @brief 销毁指定资源类型下的运行时资源。
|
||||
* @param id 资源 ID。
|
||||
* @param type 资源类型。
|
||||
*/
|
||||
void destroy_resource(id::id_type id, asset_type::type type);
|
||||
|
||||
/**
|
||||
* @brief 注册一组着色器变体。
|
||||
* @param shaders 着色器二进制列表。
|
||||
* @param num_shaders 着色器数量。
|
||||
* @param keys 每个着色器对应的查询键。
|
||||
* @return 着色器组 ID。
|
||||
*/
|
||||
id::id_type add_shader_group(const u8 *const * shaders, u32 num_shaders, const u32 *const keys);
|
||||
/**
|
||||
* @brief 删除着色器组及其缓存数据。
|
||||
* @param id 着色器组 ID。
|
||||
*/
|
||||
void remove_shader_group(id::id_type id);
|
||||
/**
|
||||
* @brief 按组 ID 与键查询编译后着色器。
|
||||
* @param id 着色器组 ID。
|
||||
* @param shader_key 着色器键值。
|
||||
* @return 命中时返回着色器描述,否则返回空。
|
||||
*/
|
||||
compiled_shader_ptr get_shader(id::id_type id, u32 shader_key);
|
||||
|
||||
/**
|
||||
* @brief 根据几何内容 ID 批量获取子网格 GPU 资源 ID。
|
||||
* @param geometry_content_id 几何内容资源 ID。
|
||||
* @param id_count 输出数组长度。
|
||||
* @param gpu_ids 输出的 GPU ID 数组。
|
||||
*/
|
||||
void get_submesh_gpu_id(id::id_type geometry_content_id, u32 id_count, id::id_type *const gpu_ids);
|
||||
/**
|
||||
* @brief 按阈值批量查询几何资源对应的 LOD 偏移信息。
|
||||
* @param geometry_ids 几何资源 ID 数组。
|
||||
* @param thresholds 每个几何对应的 LOD 阈值。
|
||||
* @param id_count 查询数量。
|
||||
* @param offsets 输出的 LOD 偏移信息。
|
||||
*/
|
||||
void get_lod_offset(const id::id_type *const geometry_ids, const f32 *const thresholds, u32 id_count, utl::vector<lod_offset>& offsets);
|
||||
}
|
||||
Reference in New Issue
Block a user