try support asset loader

This commit is contained in:
ouczbs 2024-07-03 19:51:47 +08:00
parent e6d4313f90
commit 67b41a4eee
52 changed files with 518 additions and 306 deletions

View File

@ -28,6 +28,9 @@
#define USING_OVERLOAD_CLASS_FUNC(R, Class, ...) using USING_FUNC_NAME = R(Class::*)(__VA_ARGS__);
#define REGISTER_META_TABLE(Class) refl::UClass::MetaTable.emplace(type_name<Class>().View(), &refl::TypeInfo<Class>::StaticClass);
#define REFL_FRIEND(Class) friend class refl_impl::_Static<Class, refl_impl::Meta>;\
friend class refl_impl::_Meta<Class, refl_impl::Meta>;
/*
struct vec3{
USING_OVERLOAD_CTOR(vec3)

View File

View File

@ -0,0 +1,2 @@
- name: engineapi::Mesh
data: ""

View File

@ -0,0 +1,2 @@
- name: engineapi::Mesh
data: "mMaterial:\n guid: 00000000-0000-0000-0000-000000000000"

View File

@ -0,0 +1,9 @@
metadatas:
- guid: a5943c25-1ce8-44dc-ae99-4071d07ecb63
name: ""
t_hash: engineapi::Model
t_meta: ""
- guid: 77b7a000-ed3c-4271-ae30-5e91346e09f4
name: ""
t_hash: engineapi::Asset
t_meta: engineapi::Mesh

View File

@ -0,0 +1,2 @@
- name: engineapi::Mesh
data: ""

View File

@ -0,0 +1,9 @@
metadatas:
- guid: 80671c54-88f9-41c7-948a-a72cdf3727d3
name: ""
t_hash: engineapi::Model
t_meta: ""
- guid: 54e69c4b-16ea-4fb8-87d6-0e2383d093b0
name: defaultobject
t_hash: engineapi::Asset
t_meta: engineapi::Mesh

View File

@ -0,0 +1,5 @@
metadatas:
- guid: eb1c9b43-a86b-40cb-9b3d-a3296d168c70
name: ""
t_hash: engineapi::ShaderProgram
metadata: ""

View File

@ -0,0 +1,5 @@
metadatas:
- guid: 9419e2a5-ddc4-414f-aa76-d08e9b162492
name: ""
t_hash: engineapi::ShaderProgram
metadata: ""

22
engine/cpp_input.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
//#include "meta/variant.inl"
//#include "meta/tuple.inl"
//#include "meta/comparable.inl"
//#include "meta/hash.h"
//#include "zstd/span.h"
//#include "zstd/table.h"
//#include <vector>
//#include <optional>
namespace engineapi {
using namespace meta;
using zstd::span;
using std::vector;
using std::array;
using zstd::table;
using zstd::hash_table;
template<typename T>
using opt = std::optional<T>;
template<bool val>
using sfinae = std::enable_if_t<val>;
}

View File

@ -28,6 +28,9 @@ namespace engineapi {
for (auto system : SystemList) {
system->Init();
}
for (auto system : SystemList) {
system->LateInit();
}
}
void App::Shutdown()
{

View File

@ -1,6 +1,10 @@
#include "assert.h"
#include "asset_loader.h"
#include "render/asset/shader.h"
#include "render/asset/model.h"
#include "resource_manager.h"
#include "object/loader/assimp_loader.h"
#include "yaml/yaml.h"
namespace engineapi {
MetaBundle ResourceManager::GetVisitMeta(const ResourceBundle& bundle)
{
@ -9,4 +13,10 @@ namespace engineapi {
std::visit([&](auto& handle) { new_meta.Add(handle); }, elem);
return new_meta;
}
void Asset::__Init__()
{
YAML::TextArchive::Register<Guid>();
AssimpLoader::Init();
AssetLoader::Init();
}
}

View File

@ -1,11 +1,22 @@
#pragma once
#include "render/asset_struct.h"
#include "res/resource_handle.h"
#include "res/package_path.h"
#include "resource_manager.h"
namespace engineapi {
class Asset : public Resource<Asset> {
private:
static void __Init__();
friend class FileManager;
public:
using Base = Resource<Asset>;
using Base::Base;
const refl::UClass* meta;
Asset(const refl::UClass* meta): Base(), meta(meta){}
};
template<>
inline void MetaBundle::Add(RscHandle<Asset> h)
{
if (h)
{
metadatas.emplace_back(SerializedMeta{ h.guid, string(h->Name()), string(type_name<Asset>().View()), string(h->meta->name)});
}
}
}

View File

@ -0,0 +1,25 @@
#include "asset_loader.h"
#include "file_manager.h"
#include "yaml/yaml.h"
#include <fstream>
namespace engineapi {
void AssetLoader::Init() {
ResourceManager::GetSingleton().RegisterLoader<AssetLoader>(".asset");
}
ResourceBundle AssetLoader::LoadFile(PackagePath handle, const MetaBundle& meta)
{
return ResourceBundle();
}
void AssetLoader::SaveFile(PackagePath handle, const ResourceBundle& bundle)
{
YAML::Node result;
for (auto& elem : bundle.GetAll<Asset>()) {
RscHandle<Asset> handle = elem.AsHandle<Asset>();
YAML::Node meta;
meta["name"] = string(handle->meta->name);
meta["data"] = YAML::Text_Serialize(refl::Any{handle.res, handle->meta});
result.push_back(meta);
}
FileManager::SaveTextFile(handle, YAML::Dump(result));
}
}

View File

@ -0,0 +1,10 @@
#pragma once
#include "asset.h"
namespace engineapi {
class AssetLoader :public IFileLoader{
public:
static void Init();
ResourceBundle LoadFile(PackagePath handle, const MetaBundle& meta) override;
void SaveFile(PackagePath handle, const ResourceBundle& bundle) override;
};
}

View File

@ -7,12 +7,13 @@ namespace engineapi {
{
std::filesystem::path path = std::filesystem::current_path();
Mount("engine", path.string());
Asset::__Init__();
}
void FileManager::Shutdown()
{
}
string FileManager::real_path(const PackagePath& pack_path)
string FileManager::RealPath(const PackagePath& pack_path)
{
string_view name = pack_path.ParsePackage();
string_view pre_path = FindMountPath(name);
@ -40,7 +41,7 @@ namespace engineapi {
file.exceptions(ifstream::failbit | ifstream::badbit);
try
{
string path = real_path(pack_path);
string path = RealPath(pack_path);
file.open(path);
stringstream stream;
stream << file.rdbuf();
@ -54,7 +55,7 @@ namespace engineapi {
}
result<vector<char>,FileFlag> FileManager::LoadBinaryFile(const PackagePath& pack_path)
{
string path = real_path(pack_path);
string path = RealPath(pack_path);
// ate:在文件末尾开始读取,从文件末尾开始读取的优点是我们可以使用读取位置来确定文件的大小并分配缓冲区
ifstream file(path, std::ios::ate | std::ios::binary);
if (!file.is_open()) {
@ -74,7 +75,7 @@ namespace engineapi {
}
result<json, FileFlag> FileManager::LoadJsonFile(const PackagePath& pack_path)
{
string path = real_path(pack_path);
string path = RealPath(pack_path);
std::ifstream f(path);
if (!f.is_open())
{
@ -96,7 +97,7 @@ namespace engineapi {
}
void FileManager::SaveTextFile(const PackagePath& pack_path,const string& value)
{
string path = real_path(pack_path);
string path = RealPath(pack_path);
std::ofstream of(path);
of.write(value.data(), value.size());
}

View File

@ -63,9 +63,10 @@ namespace engineapi
private:
inline static table<NameID, std::pair<string, string>> MountMap;
inline static table<NameID, FileControlBlock> FileMap;
//外界不应该使用绝对路径
static string real_path(const PackagePath& pack_path);
public:
//外界不应该使用绝对路径
static string RealPath(const PackagePath& pack_path);
static FileFlag LoadErrorFlag(const PackagePath& pack_path);
static result<string, FileFlag> LoadTextFile(const PackagePath& pack_path);

View File

@ -13,9 +13,9 @@ namespace engineapi
UPROPERTY({})
string t_hash{};
UPROPERTY({})
string metadata;
string t_meta;
bool operator==(const SerializedMeta& other)const{
return guid == other.guid && name == other.name && t_hash == other.t_hash && metadata == other.metadata;
return guid == other.guid && name == other.name && t_hash == other.t_hash && t_meta == other.t_meta;
}
};
struct ResourceBundle;
@ -29,6 +29,8 @@ namespace engineapi
template<typename T>
const SerializedMeta* FetchMeta() const;
template<typename T>
const SerializedMeta* FetchMeta(const string_view& asset_name) const;
template<typename T>
void Add(RscHandle<T>);
bool operator==(const MetaBundle& other)const;
bool operator!=(const MetaBundle& other)const;

View File

@ -4,10 +4,21 @@ namespace engineapi
template<typename T>
inline const SerializedMeta* MetaBundle::FetchMeta() const
{
string_view name = type_name<T>().View();
string_view name = type_name<typename T::BaseResource>().View();
for (auto& elem : metadatas)
{
if (string_view(elem.t_hash) == name)
if (elem.t_hash == name)
return &elem;
}
return nullptr;
}
template<typename T>
inline const SerializedMeta* MetaBundle::FetchMeta(const string_view& asset_name) const
{
string_view name = type_name<typename T::BaseResource>().View();
for (auto& elem : metadatas)
{
if (elem.t_hash == name && asset_name == elem.name)
return &elem;
}
return nullptr;
@ -17,7 +28,7 @@ namespace engineapi
{
if (h)
{
metadatas.emplace_back(SerializedMeta{ h.guid, string{h->Name()}, string{type_name<T>().View()}});
metadatas.emplace_back(SerializedMeta{ h.guid, string(h->Name()), string(type_name<T>().View()) });
}
}
}

View File

@ -17,5 +17,9 @@ namespace engineapi {
{
return PackagePath{ FileManager::FindPathView(path) };
}
string PackagePath::RealPath() const
{
return FileManager::RealPath(*this);
}
}

View File

@ -23,6 +23,7 @@ namespace engineapi
PackagePath() {};
PackagePath(const char* path) : path(path) {}
PackagePath(const string_view& path) : path(path) {}
PackagePath(const string& path) : path(path) {}
PackagePath(const string&& path) : path(path) {}
size_t size() const{
return path.size();
@ -54,5 +55,6 @@ namespace engineapi
}
PackagePath ToSuffixPath(const string_view& suffix)const;
PackagePath SafePath()const;
string RealPath()const;
};
}

View File

@ -3,7 +3,6 @@
namespace engineapi
{
struct GenericResourceHandle;
struct ResourceBundle
{
ResourceBundle() = default;
@ -13,6 +12,7 @@ namespace engineapi
template<typename T> void Add(RscHandle<T> handle);
template<typename T> RscHandle<T> Get() const; // get a resource from the bundle
span<const GenericResourceHandle> GetAll() const; // gets absolutely all resources
template<typename T> span<const GenericResourceHandle> GetAll() const; // get all resources of one type
private:
struct sub_array { short index = 0, count = 0; };

View File

@ -1,5 +1,4 @@
#pragma once
#include "resource_bundle.h"
namespace engineapi
{
template<typename Res>
@ -31,9 +30,13 @@ namespace engineapi
}
template<typename T>
inline RscHandle<T> engineapi::ResourceBundle::Get() const
inline RscHandle<T> ResourceBundle::Get() const
{
auto& subarray = subarrays[ResourceID<T>];
return subarray.count > 0 ? handles[subarray.index].template AsHandle<T>() : RscHandle<T>();
}
template<typename T> span<const GenericResourceHandle> ResourceBundle::GetAll() const {
auto& subarray = subarrays[ResourceID<T>];
return span<const GenericResourceHandle>{handles.data() + subarray.index, handles.data() + subarray.index + subarray.count};
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "type.h"
namespace engineapi {
class Guid;
template<typename Res>
struct RscHandle;
template<typename Res>
@ -8,7 +9,7 @@ namespace engineapi {
{
public:
using BaseResource = Res;
Guid GetGuid()const;
RscHandle<Res> GetHandle() const { return mHandle; }
Resource() = default;
@ -21,6 +22,7 @@ namespace engineapi {
};
using Resources = std::tuple<
class ShaderProgram
, class Model
, class Asset
>;
template<typename Resource>

View File

@ -4,18 +4,21 @@
namespace engineapi
{
struct RscHandleBase {
UPROPERTY({})
Guid guid;
void* res;
};
template<typename Res>
struct RscHandle
struct RscHandle : public RscHandleBase
{
Guid guid{};
void* res{};
constexpr size_t RscID()const { return ResourceID<Res>; }
constexpr RscHandle() noexcept = default;
template<typename T>
constexpr RscHandle(const RscHandle<T>& other) noexcept : guid{ other.guid }, res(other.res) {};
constexpr RscHandle(const Guid& guid, Res* res) noexcept : guid{ guid }, res(res) { ((Resource<Res>*)res)->mHandle = *this; }
constexpr RscHandle(const RscHandle<T>& other) noexcept : RscHandleBase(other.guid, other.res) {};
constexpr RscHandle(const Guid& guid, Res* res) noexcept : RscHandleBase(guid, res) { ((Resource<Res>*)res)->mHandle = *this; }
void Init();
void Clear(){ res = nullptr; };
void Clear() { res = nullptr; };
Res* operator->() { if (!res && guid) Init(); return (Res*)res; }
Res& operator*() { if (!res && guid) Init(); return *(Res*)res; }
operator bool() { if (!res && guid) Init(); return res; }
@ -23,34 +26,6 @@ namespace engineapi
Res& operator*()const { return *(Res*)res; }
operator bool() const { return res; }
};
struct GenericResourceHandle
: variant_wrap_t<tuple_to_variant_t<Resources>, RscHandle>
{
private:
using Base = variant_wrap_t<tuple_to_variant_t<Resources>, RscHandle>;
public:
using Base::Base;
using Base::operator=;
template<typename T>
GenericResourceHandle(RscHandle<T> handle) : Base(RscHandle<typename T::BaseResource>{handle}) {}
GenericResourceHandle(string_view type_name, Guid guid);
template<typename T> RscHandle<T> AsHandle() const {
return std::get<ResourceID<T>>(*this);
}
Guid guid() const;
size_t resource_id() const;
};
}
// hashtable support
namespace std
{
template<typename Res>
struct hash <engineapi::RscHandle<Res>>
{
size_t operator()(const engineapi::RscHandle<Res>& res) const noexcept
{
return std::hash<engineapi::Guid>()(res.guid);
}
};
}
#include "resource_handle.inl"
#include "resource_handle_gen.inl"

View File

@ -0,0 +1,43 @@
#pragma once
namespace engineapi{
template<typename Res>
inline Guid Resource<Res>::GetGuid() const
{
return GetHandle().guid;
}
struct GenericResourceHandle
: variant_wrap_t<tuple_to_variant_t<Resources>, RscHandle>
{
private:
using Base = variant_wrap_t<tuple_to_variant_t<Resources>, RscHandle>;
public:
using Base::Base;
using Base::operator=;
template<typename T>
GenericResourceHandle(RscHandle<T> handle) : Base(RscHandle<typename T::BaseResource>{handle}) {}
GenericResourceHandle(string_view type_name, Guid guid);
template<typename T> RscHandle<T> AsHandle() const {
return std::get<ResourceID<T>>(*this);
}
Guid guid() const;
size_t resource_id() const;
};
}
// hashtable support
namespace std
{
template<typename Res>
struct hash <engineapi::RscHandle<Res>>
{
size_t operator()(const engineapi::RscHandle<Res>& res) const noexcept
{
return std::hash<engineapi::Guid>()(res.guid);
}
};
}
namespace refl {
template<typename T>
struct real_type<engineapi::RscHandle<T>> {
using type = engineapi::RscHandleBase;
};
}

View File

@ -7,6 +7,11 @@ namespace engineapi {
mResourceTable = detail::ResourceHelper::GenResourceTables();
LoadFileFlag();
}
void ResourceManager::LateInit()
{
SaveFileFlag();
SaveDirtyFiles();
}
void ResourceManager::Shutdown()
{
constexpr static auto release_tables = detail::ResourceHelper::ReleaseTableResources();
@ -30,23 +35,26 @@ namespace engineapi {
return it->second.bundle;
}
}
auto& res = mFileTable[path.path];
Name ext = path.GetExtension();
IFileLoader* loader = GetLoader(ext);
MetaBundle meta = GetMeta(path);
ResourceBundle bundle = loader->LoadFile(path, meta);
MetaBundle new_meta = GetVisitMeta(bundle);
bool is_dirty_meta = meta != new_meta;
mFileTable[path.path] = {bundle, path.SafePath(), false, is_dirty_meta};
auto& res = mFileTable[path.path];
for (auto& elem : bundle.GetAll()) {
std::visit([&](auto& handle) {
using T = std::decay_t<decltype(*handle)>;
GetControlBlock<T>(handle)->file = &res;
}, elem);
}
if (is_dirty_meta) {
if (is_dirty_meta || res.is_dirty) {
mDirtyBlocks.push_back(&res);
}
res.path = path.SafePath();
res.bundle = bundle;
res.is_meta_dirty = is_dirty_meta;
res.bundle = bundle;
return res.bundle;
}
@ -74,7 +82,7 @@ namespace engineapi {
}
else {
string text = YAML::Text_Serialize(bundle);
FileManager::SaveTextFile(path, text);
FileManager::SaveTextFile(path + ".meta", text);
}
}
void ResourceManager::SaveDirtyFiles()

View File

@ -37,6 +37,7 @@ namespace engineapi {
vector<FileControlBlock*> mDirtyBlocks;
public:
void Init() override;
void LateInit()override;
void Shutdown() override;
public:
@ -47,8 +48,9 @@ namespace engineapi {
auto& GetTable() {
return *reinterpret_cast<ResourceStorage<Res>*> (mResourceTable[ResourceID<Res>].get());
}
template<typename Res>
template<typename Res>
ResourceControlBlock<Res>* GetControlBlock(RscHandle<Res> handle);
FileControlBlock& GetFileBlock(PackagePath path);
template<typename Res, typename ... Args>
[[nodiscard]] RscHandle<Res> LoaderEmplaceResource(Args&& ... args) {

View File

@ -1,4 +1,3 @@
#include "resource_manager.h"
#pragma once
namespace engineapi {
class IFileLoader
@ -97,6 +96,9 @@ namespace engineapi {
auto& table = GetTable<Res>();
return &table[handle.guid];
}
inline ResourceManager::FileControlBlock& ResourceManager::GetFileBlock(PackagePath path) {
return mFileTable[NameID(path.path)];
}
template<typename Res>
inline void RscHandle<Res>::Init()
{

View File

@ -0,0 +1,149 @@
#include "zlog.h"
#include "assimp_loader.h"
#include "asset/file_manager.h"
#include "asset/resource_manager.h"
#include "assimp/Importer.hpp"
#include "assimp/scene.h"
#include "assimp/postprocess.h"
#include <fstream>
namespace engineapi {
void AssimpLoader::Init()
{
ResourceManager::GetSingleton().RegisterLoader<AssimpLoader>(".obj");
ResourceManager::GetSingleton().RegisterLoader<AssimpLoader>(".ply");
}
ResourceBundle AssimpLoader::LoadFile(PackagePath handle, const MetaBundle& meta)
{
auto m = meta.FetchMeta<Model>();
auto asset = m ? ResourceManager::GetSingleton().LoaderEmplaceResource<Model>(m->guid)
: ResourceManager::GetSingleton().LoaderEmplaceResource<Model>();
uint32_t flag = FileManager::FindPathFlag(handle);
if (flag & FileFlag::File_Http) {
return {};
}
LoadModel(handle, *asset, meta);
ResourceBundle bundle{ asset };
for (auto& mesh : asset->GetMeshs()) {
bundle.Add(mesh);
}
PackagePath asset_handle(handle + ".asset");
std::ifstream file(asset_handle.RealPath());
if (!file.good()) {
auto& block = ResourceManager::GetSingleton().GetFileBlock(handle);
block.is_dirty = true;
}
return bundle;
}
void AssimpLoader::SaveFile(PackagePath handle, const ResourceBundle& bundle)
{
auto loader = ResourceManager::GetSingleton().GetLoader(".asset");
if(loader)
loader->SaveFile(handle + ".asset", bundle);
}
void AssimpLoader::LoadModel(PackagePath handle, Model& model, const MetaBundle& meta)
{
// 用ASSIMP加载模型文件
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(handle.RealPath(), aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace
| aiProcess_FixInfacingNormals | aiProcess_FlipWindingOrder | aiProcess_LimitBoneWeights);
// 检查异常
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
zlog::error("ASSIMP: {}", importer.GetErrorString());
return;
}
ProcessNode(model, meta, scene->mRootNode, scene);
}
void AssimpLoader::ProcessNode(Model& model, const MetaBundle& meta, const aiNode* pNode, const aiScene* pScene)
{
// 处理Mesh数据
auto& meshs = model.GetMeshs();
for (unsigned int i = 0; i < pNode->mNumMeshes; i++)
{
// aiNode仅包含索引来获取aiScene中的实际对象
// aiScene包含所有数据aiNode只是为了让数据组织起来(比如记录节点之间的关系)
aiMesh* mesh = pScene->mMeshes[pNode->mMeshes[i]];
auto m = meta.FetchMeta<Mesh>(mesh->mName.C_Str());
meshs.push_back(ProcessMesh(m, mesh));
}
// 加载骨骼数据
//pBoneNode->name = pNode->mName.C_Str();
//pBoneNode->transform = aiMatrix4x4ToMatrix4(pNode->mTransformation);
// 递归处理子节点
for (unsigned int i = 0; i < pNode->mNumChildren; i++)
{
//pBoneNode->children.push_back(new BoneNode());
ProcessNode(model, meta, pNode->mChildren[i], pScene);
}
}
RscHandle<Mesh> AssimpLoader::ProcessMesh(const SerializedMeta* m, const aiMesh* mesh)
{
// data to fill
vector<BoneVertex> vertices;
vector<uint32_t> indices;
// Walk through each of the mesh's vertices
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
BoneVertex vertex;
Vector3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to Vector3 class so we transfer the data to this placeholder Vector3 first.
// positions
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
// normals
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;
// texture coordinates
if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
{
Vector2 vec;
// a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
// use models where a vertex can have multiple texture coordinates so we always take the first set (0).
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;
}
else
{
vertex.TexCoords = Vector2(0.0f, 0.0f);
}
// tangent and bitangent
if (mesh->HasTangentsAndBitangents())
{
vector.x = mesh->mTangents[i].x;
vector.y = mesh->mTangents[i].y;
vector.z = mesh->mTangents[i].z;
vertex.Tangent = vector;
}
else
{
vertex.Tangent = Vector3(0.0f, 0.0f, 0.0f);
}
vertices.push_back(vertex);
}
// now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
const aiFace& face = mesh->mFaces[i];
// retrieve all indices of the face and store them in the indices vector
for (unsigned int j = 0; j < face.mNumIndices; j++)
{
indices.push_back(face.mIndices[j]);
}
}
auto asset = m ? ResourceManager::GetSingleton().LoaderEmplaceResource<Mesh>(m->guid, vertices, indices)
: ResourceManager::GetSingleton().LoaderEmplaceResource<Mesh>(vertices, indices);
asset->Name(mesh->mName.C_Str());
return asset;
}
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "render/asset/model.h"
#include "asset/resource_manager.h"
class aiNode;
class aiMesh;
class aiScene;
namespace engineapi {
class AssimpLoader : public IFileLoader
{
inline static table<Guid, void*> ShaderTable;
public:
static void Init();
ResourceBundle LoadFile(PackagePath handle, const MetaBundle& meta) override;
void SaveFile(PackagePath handle, const ResourceBundle& bundle) override;
void LoadModel(PackagePath handle, Model& model, const MetaBundle& meta);
void ProcessNode(Model& model, const MetaBundle& meta, const aiNode* pNode, const aiScene* pScene);
RscHandle<Mesh> ProcessMesh(const SerializedMeta* m, const aiMesh* mesh);
};
}

View File

@ -1,4 +1,5 @@
#include "actor.h"
#include "asset/resource_manager.h"
#include "data/property/actor_property.h"
namespace engineapi {
ActorMesh::ActorMesh(Model& model, ActorProperty& property)
@ -9,9 +10,8 @@ namespace engineapi {
}
ActorMesh* ActorMesh::New(ActorProperty& property)
{
//Model* model = AssetManager::GetSingletonPtr()->LoadAsset<Model>(property.path, property.flags);
//return new ActorMesh(*model, property);
return nullptr;
auto res = ResourceManager::GetSingleton().Load<Model>(property.path);
return new ActorMesh(*res, property);
}
ActorMesh* ActorMesh::New(uint32_t id)
{

View File

@ -8,6 +8,6 @@ namespace engineapi {
}
void StaticMesh::LoadMesh()
{
mPtr.BeginLoad();
}
}

View File

@ -12,18 +12,19 @@ namespace engineapi {
mCamera = new Camera();
int flags = 1;
auto shader = ResourceManager::GetSingleton().LoaderEmplaceResource<Shader>();
shader->mVertexName = type_name<BoneVertex>().View();
shader->Name(type_name<BoneVertex>().View());
shader->mVert = ResourceManager::GetSingleton().Load<ShaderProgram>("/engine/assets/shader/simple.vert");
shader->mFrag = ResourceManager::GetSingleton().Load<ShaderProgram>("/engine/assets/shader/simple.frag");
RenderAPI::GetSingleton().LoadShader(&*shader);
Material* material = new Material("/engine/assets/shader/simple.shader", flags);
RenderAPI::GetSingleton().LoadShader(*shader);
//Material* material = new Material("/engine/assets/shader/simple.shader", flags);
{
ActorProperty property;
property.id = 1;
property.flags = flags;
property.path = "/engine/assets/models/cube.obj";
actor1 = ActorMesh::New(property);
actor1->Ptr().SetMaterial(material);
actor1->LoadMesh();
//actor1->Ptr().SetMaterial(material);
}
{
ActorProperty property;
@ -31,7 +32,7 @@ namespace engineapi {
property.flags = flags;
property.path = "/engine/assets/models/box.ply";
actor2 = ActorMesh::New(property);
actor2->Ptr().SetMaterial(material);
//actor2->Ptr().SetMaterial(material);
}
}
Scene::~Scene()
@ -43,11 +44,10 @@ namespace engineapi {
void Scene::Render()
{
RenderAPI::GetSingletonPtr()->Render(*mCamera);
auto meshs = actor1->Ptr().GetMeshs();
for (auto it : meshs) {
RenderAPI::GetSingletonPtr()->DrawStaticMesh(it);
}
//RenderAPI::GetSingletonPtr()->DrawStaticMesh(actor2);
//auto meshs = actor1->Ptr().GetMeshs();
//for (auto it : meshs) {
//RenderAPI::GetSingletonPtr()->DrawStaticMesh(*it);
//}
}
void Scene::AddGameObject(GameObject* gameObject)
{

View File

@ -2,9 +2,9 @@
#include "shader.h"
#include "../renderapi.h"
namespace engineapi {
Material::Material(string_view name, uint32_t flags)
Material::Material() : Asset(&refl::TypeInfo<Material>::StaticClass)
{
//mShader = new Shader(name, flags);
}
Material::~Material()
{

View File

@ -1,15 +1,18 @@
#pragma once
#include "asset/asset.h"
#include "shader.h"
namespace engineapi {
class Shader;
class Material : public Asset {
protected:
uint32_t mId{0};
Shader* mShader;
REFL_FRIEND(Material)
UPROPERTY()
RscHandle<Shader> mShader;
public:
Material(string_view name, uint32_t flags);
Material();
~Material();
RscHandle<Shader> GetShader() {
return mShader;
}
};
};
};
#include "material_gen.inl"

View File

@ -3,6 +3,6 @@
namespace engineapi {
void Mesh::BeginLoad()
{
RenderAPI::GetSingletonPtr()->SetStaticMesh(this);
RenderAPI::GetSingletonPtr()->SetStaticMesh(*this);
}
}

View File

@ -1,30 +1,28 @@
#pragma once
#include "material.h"
#include "vertex.h"
#include "refl/std/parray.h"
#include "asset/asset.h"
#include "../meta/vertex.h"
namespace engineapi {
using refl::parray;
class Texture;
class Material;
class Mesh : public Asset {
class Mesh : public Asset{
protected:
uint32_t VAO = 0;
REFL_FRIEND(Mesh)
UPROPERTY()
RscHandle<Material> mMaterial;
parray<Vertex> mVertices;
vector<uint32_t> mIndices;
public:
template<typename T>
requires std::is_base_of_v<Vertex, T>
Mesh(vector<T>& vertices, vector<uint32_t>& indices)
: mVertices(vertices)
, mIndices(indices)
{
BeginLoad();
}
Mesh(vector<T>& vertices, vector<uint32_t>& indices);
void BeginLoad();
public:
uint32_t& GetVAO() {
return VAO;
Guid GetShaderGuid() {
return mMaterial->GetShader().guid;
}
RscHandle<Material> GetMaterial() {
return mMaterial;
}
parray<Vertex>& GetVertices() {
return mVertices;
@ -33,4 +31,14 @@ namespace engineapi {
return mIndices;
}
};
};
};
#include "mesh_gen.inl"
namespace engineapi {
template<typename T>
requires std::is_base_of_v<Vertex, T>
inline Mesh::Mesh(vector<T>& vertices, vector<uint32_t>& indices)
: Asset(&refl::TypeInfo<Mesh>::StaticClass), mVertices(vertices), mIndices(indices)
{
auto cls = &refl::TypeInfo<Mesh>::StaticClass;
}
}

View File

@ -1,109 +1,10 @@
#include "model.h"
#include "zlog.h"
#include "assimp/Importer.hpp"
#include "assimp/scene.h"
#include "assimp/postprocess.h"
namespace engineapi {
void Model::BeginLoad()
{
string mName = "";
// 用ASSIMP加载模型文件
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(mName, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace
| aiProcess_FixInfacingNormals | aiProcess_FlipWindingOrder | aiProcess_LimitBoneWeights);
// 检查异常
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
zlog::error("ASSIMP: {}", importer.GetErrorString());
return;
for (auto mesh : mMeshes) {
mesh->BeginLoad();
}
ProcessNode(scene->mRootNode, scene);
}
void Model::ProcessNode(const aiNode* pNode, const aiScene* pScene)
{
// 处理Mesh数据
for (unsigned int i = 0; i < pNode->mNumMeshes; i++)
{
// aiNode仅包含索引来获取aiScene中的实际对象
// aiScene包含所有数据aiNode只是为了让数据组织起来(比如记录节点之间的关系)
aiMesh* mesh = pScene->mMeshes[pNode->mMeshes[i]];
mMeshes.push_back(ProcessMesh(mesh));
}
// 加载骨骼数据
//pBoneNode->name = pNode->mName.C_Str();
//pBoneNode->transform = aiMatrix4x4ToMatrix4(pNode->mTransformation);
// 递归处理子节点
for (unsigned int i = 0; i < pNode->mNumChildren; i++)
{
//pBoneNode->children.push_back(new BoneNode());
ProcessNode(pNode->mChildren[i], pScene);
}
}
Mesh* Model::ProcessMesh(const aiMesh* mesh) {
// data to fill
vector<BoneVertex> vertices;
vector<uint32_t> indices;
// Walk through each of the mesh's vertices
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
BoneVertex vertex;
Vector3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to Vector3 class so we transfer the data to this placeholder Vector3 first.
// positions
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
// normals
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;
// texture coordinates
if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
{
Vector2 vec;
// a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
// use models where a vertex can have multiple texture coordinates so we always take the first set (0).
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;
}
else
{
vertex.TexCoords = Vector2(0.0f, 0.0f);
}
// tangent and bitangent
if (mesh->HasTangentsAndBitangents())
{
vector.x = mesh->mTangents[i].x;
vector.y = mesh->mTangents[i].y;
vector.z = mesh->mTangents[i].z;
vertex.Tangent = vector;
}
else
{
vertex.Tangent = Vector3(0.0f, 0.0f, 0.0f);
}
vertices.push_back(vertex);
}
// now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
const aiFace& face = mesh->mFaces[i];
// retrieve all indices of the face and store them in the indices vector
for (unsigned int j = 0; j < face.mNumIndices; j++)
{
indices.push_back(face.mIndices[j]);
}
}
return new Mesh(vertices, indices);
}
void Model::Use()
{

View File

@ -1,26 +1,14 @@
#pragma once
#include "asset/asset.h"
#include "mesh.h"
#include "material.h"
class aiNode;
class aiMesh;
class aiScene;
namespace engineapi {
class Model : public Asset {
class Model : public Resource<Model> {
protected:
vector<Mesh*> mMeshes;
Material* mMaterial;
vector<RscHandle<Mesh>> mMeshes;
public:
using Asset::Asset;
void BeginLoad();
void ProcessNode(const aiNode* pNode, const aiScene* pScene);
Mesh* ProcessMesh(const aiMesh* mesh);
vector<Mesh*>& GetMeshs() {
vector<RscHandle<Mesh>>& GetMeshs() {
return mMeshes;
}
void SetMaterial(Material* material) {
mMaterial = material;
}
void Use();
};
};

View File

@ -1,8 +1,6 @@
#include "shader.h"
#include "asset/file_manager.h"
#include "../renderapi.h"
namespace engineapi {
Shader::Shader()
Shader::Shader() : Asset(&refl::TypeInfo<Shader>::StaticClass)
{
}

View File

@ -5,10 +5,12 @@ namespace engineapi {
class ShaderProgram : public Resource<ShaderProgram> {};
class Shader : public Asset {
private:
REFL_FRIEND(Shader)
uint32_t mId;
ShaderInfo mInfo;
string mVertexName;
UPROPERTY()
RscHandle<ShaderProgram> mVert;
UPROPERTY()
RscHandle<ShaderProgram> mFrag;
friend class Scene;
public:
@ -20,9 +22,6 @@ namespace engineapi {
ShaderInfo& GetInfo() {
return mInfo;
}
string_view GetVertexName() {
return mVertexName;
}
template<typename T = ShaderProgram>
RscHandle<T> GetVertHandle() {
return mVert;
@ -32,4 +31,5 @@ namespace engineapi {
return mFrag;
}
};
};
};
#include "shader_gen.inl"

View File

@ -0,0 +1,7 @@
#include "texture.h"
namespace engineapi {
Texture::Texture() : Asset(&refl::TypeInfo<Texture>::StaticClass)
{
}
}

View File

@ -3,6 +3,6 @@
namespace engineapi {
class Texture : public Asset {
Texture();
};
};

View File

@ -1,6 +1,5 @@
#pragma once
#include "../asset/material.h"
#include "../asset/mesh.h"
#include "../asset/texture.h"
#include "../render_context.h"
namespace engineapi {

View File

@ -31,10 +31,10 @@ namespace engineapi
virtual void BeginFrame() = 0;
virtual void Render(Camera& camera);
virtual void EndFrame() = 0;
virtual void SetStaticMesh(Mesh* mesh) = 0;
virtual void DrawStaticMesh(Mesh* mesh) = 0;
virtual void SetStaticMesh(Mesh& mesh) = 0;
virtual void DrawStaticMesh(Mesh& mesh) = 0;
virtual void LoadShader(Shader* shader) = 0;
virtual void LoadShader(Shader& shader) = 0;
virtual void SwitchContext() = 0;

View File

@ -2,7 +2,7 @@
#include "vulkanapi/tool/glsl_to_spirv.h"
#include "vulkanapi/vulkanapi.h"
#include "asset/file_manager.h"
#include "render/meta/vertex.h"
#include "render/asset/vertex.h"
#include "vkmeta_vertex_gen.inl"
#include <spirv_cross/spirv_reflect.hpp>
using namespace engineapi;
@ -56,7 +56,7 @@ namespace vulkanapi {
auto spirv = GlslToSpirv::spirv(glsl, shader_enum, handle.GetFileName());
if (spirv) {
program->Load(*spirv);
LoadShaderInfo(program->GetHandle().guid, *spirv);
LoadShaderInfo(program->GetGuid(), *spirv);
}
}
}

View File

@ -64,13 +64,13 @@ namespace vulkanapi {
{
swapchain->Present(context);
}
void RenderVulkanAPI::SetStaticMesh(Mesh* mesh)
void RenderVulkanAPI::SetStaticMesh(Mesh& mesh)
{
auto Indices = mesh->GetIndices();
auto Vertices = mesh->GetVertices();
auto meshBuffer = GetNextVAO(mesh->GetVAO());
meshBuffer->indexCount = Indices.size();
meshBuffer->vertexCount = Vertices.size();
auto Indices = mesh.GetIndices();
auto Vertices = mesh.GetVertices();
VulkanVAO& meshBuffer = VAOTable[mesh.GetGuid()];
meshBuffer.indexCount = Indices.size();
meshBuffer.vertexCount = Vertices.size();
// ----------------------------------------------- Vertex Buffer -----------------------------------------------
VkDeviceSize vertexBufferSize = Vertices.capicty();
@ -84,7 +84,7 @@ namespace vulkanapi {
VkBufferUsageFlags vertexFlags = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;//加入光线追踪
VmaAllocationCreateInfo vertexVmaCreateInfo = {};
VkBufferCreateInfo vertexCreateInfo = Buffer::MakeDeviceInfo(vertexVmaCreateInfo, vertexBufferSize, vertexFlags);
meshBuffer->vertexBuffer = Buffer::CreateBuffer(vertexCreateInfo, vertexVmaCreateInfo, meshBuffer->vertexBufferAlloc);
meshBuffer.vertexBuffer = Buffer::CreateBuffer(vertexCreateInfo, vertexVmaCreateInfo, meshBuffer.vertexBufferAlloc);
// ----------------------------------------------- Index Buffer -----------------------------------------------
VkDeviceSize indexBufferSize = sizeof(uint32_t) * Indices.size();
@ -96,11 +96,11 @@ namespace vulkanapi {
VmaAllocationCreateInfo indexVmaCreateInfo = {};
VkBufferCreateInfo indexCreateInfo = Buffer::MakeDeviceInfo(indexVmaCreateInfo, indexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
meshBuffer->indexBuffer = Buffer::CreateBuffer(indexCreateInfo, indexVmaCreateInfo, meshBuffer->vertexBufferAlloc);
meshBuffer.indexBuffer = Buffer::CreateBuffer(indexCreateInfo, indexVmaCreateInfo, meshBuffer.vertexBufferAlloc);
auto fn = [=](CommandBuffer& cmd) {
cmd.CmdCopyBuffer(vertexStagingBuffer, meshBuffer->vertexBuffer, vertexBufferSize);
cmd.CmdCopyBuffer(indexStagingBuffer, meshBuffer->indexBuffer, indexBufferSize);
cmd.CmdCopyBuffer(vertexStagingBuffer, meshBuffer.vertexBuffer, vertexBufferSize);
cmd.CmdCopyBuffer(indexStagingBuffer, meshBuffer.indexBuffer, indexBufferSize);
};
auto callback = [=]() {
// 销毁StagingBuffer
@ -115,16 +115,16 @@ namespace vulkanapi {
Backend::TransferWorker->ImmediatelyExecute(fn, callback);
}
}
void RenderVulkanAPI::DrawStaticMesh(Mesh* mesh)
void RenderVulkanAPI::DrawStaticMesh(Mesh& mesh)
{
auto vulkanVAO = VAOList[mesh->GetVAO()];
auto pipeline = PiPelineList[0];
VulkanVAO& vulkanVAO = VAOTable[mesh.GetGuid()];
VulkanPipeline& pipeline = PipelineTable[mesh.GetShaderGuid()];
uint32_t frame = context.frame;
context.Pass->SetViewPort(mViewPortInfo.width, mViewPortInfo.height, mViewPortInfo.xOffset, mViewPortInfo.yOffset);
Backend::RenderWorker->Draw([=](CommandBuffer& cmd) {
VkCommandBuffer ptr = cmd.Ptr();
context.Pass->BeginPass(cmd, frame);
VkBuffer vertexBuffers[] = { vulkanVAO->vertexBuffer };
VkBuffer vertexBuffers[] = { vulkanVAO.vertexBuffer };
VkDeviceSize offsets[] = { 0 };
VkViewport viewport = {};
viewport.x = static_cast<float>(mViewPortInfo.xOffset);
@ -141,22 +141,22 @@ namespace vulkanapi {
vkCmdSetScissor(ptr, 0, 1, &scissor);
vkCmdBindVertexBuffers(ptr, 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(ptr, vulkanVAO->indexBuffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdBindPipeline(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline);
vkCmdBindDescriptorSets(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipelineLayout, 0, 1, &pipeline->descriptorSet, 0, VK_NULL_HANDLE);
vkCmdBindIndexBuffer(ptr, vulkanVAO.indexBuffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdBindPipeline(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline);
vkCmdBindDescriptorSets(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipelineLayout, 0, 1, &pipeline.descriptorSet, 0, VK_NULL_HANDLE);
vkCmdDrawIndexed(ptr, 3, 1, 0, 0, 0);
context.Pass->EndPass(cmd);
});
Backend::RenderWorker->Flush();
}
void RenderVulkanAPI::LoadShader(Shader* shader)
void RenderVulkanAPI::LoadShader(Shader& shader)
{
vector<VkPipelineShaderStageCreateInfo> shaderStages;
std::map<VkShaderStageFlagBits, VkShaderModule> shaderModules;
auto device = backend.GetDevice();
auto vertModule = shader->GetVertHandle<vkShaderProgram>()->Ptr();
auto vertModule = shader.GetVertHandle<vkShaderProgram>()->Ptr();
shaderModules.insert(make_pair(VK_SHADER_STAGE_VERTEX_BIT, vertModule));
auto fragModule = shader->GetVertHandle<vkShaderProgram>()->Ptr();
auto fragModule = shader.GetFragHandle<vkShaderProgram>()->Ptr();
shaderModules.insert(make_pair(VK_SHADER_STAGE_FRAGMENT_BIT, fragModule));
for (auto& shaderModule : shaderModules)
{
@ -167,7 +167,7 @@ namespace vulkanapi {
shaderStageInfo.pName = "main";
shaderStages.push_back(shaderStageInfo);
}
auto it = refl::UClass::MetaTable.find(shader->GetVertexName());
auto it = refl::UClass::MetaTable.find(shader.Name());
auto meta = it->second->vtable.GetMeta("vkMeta");
// 设置顶点输入格式
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
@ -277,7 +277,7 @@ namespace vulkanapi {
depthStencilInfo.front = {};
depthStencilInfo.back = {};
auto descriptorSetLayout = VulkanContext::CreateDescriptorSetLayout(shader->GetInfo());
auto descriptorSetLayout = VulkanContext::CreateDescriptorSetLayout(shader.GetInfo());
auto pipelineLayout = VulkanContext::CreatePipelineLayout({ descriptorSetLayout }, {});
VkGraphicsPipelineCreateInfo pipelineInfo{};
@ -302,48 +302,16 @@ namespace vulkanapi {
if (vkCreateGraphicsPipelines(device.Ptr(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeLine) != VK_SUCCESS)
throw std::runtime_error("failed to create graphics pipeline!");
//for (auto& shaderModule : shaderModules)
//vkDestroyShaderModule(device.Ptr(), shaderModule.second, nullptr);
for (auto& shaderModule : shaderModules)
vkDestroyShaderModule(device.Ptr(), shaderModule.second, nullptr);
auto vulkan_pipeline = GetNextPipeline(shader->GetID());
vulkan_pipeline->name = "";//shader->GetName();
vulkan_pipeline->pipeline = pipeLine;
vulkan_pipeline->inUse = true;
vulkan_pipeline->pipelineLayout = pipelineLayout;
vulkan_pipeline->descriptorSetLayout = descriptorSetLayout;
vulkan_pipeline->descriptorSet = backend.GetPool().Allocate(descriptorSetLayout);
VulkanPipeline& vulkan_pipeline = PipelineTable[shader.GetGuid()];
vulkan_pipeline.name = shader.Name();
vulkan_pipeline.pipeline = pipeLine;
vulkan_pipeline.inUse = true;
vulkan_pipeline.pipelineLayout = pipelineLayout;
vulkan_pipeline.descriptorSetLayout = descriptorSetLayout;
vulkan_pipeline.descriptorSet = backend.GetPool().Allocate(descriptorSetLayout);
}
VulkanVAO* RenderVulkanAPI::GetNextVAO(uint32_t& index)
{
uint32_t length = (uint32_t)VAOList.size();
for (uint32_t i = 0; i < length; i++)
{
if (!VAOList[i]->inUse) {
index = i;
return VAOList[i];
}
}
index = length;
auto vao = new VulkanVAO();
VAOList.push_back(vao);
return vao;
}
VulkanPipeline* RenderVulkanAPI::GetNextPipeline(uint32_t& index)
{
uint32_t length = (uint32_t)PiPelineList.size();
for (uint32_t i = 0; i < length; i++)
{
if (!PiPelineList[i]->inUse) {
index = i;
return PiPelineList[i];
}
}
index = length;
auto info = new VulkanPipeline();
PiPelineList.push_back(info);
return info;
}
}

View File

@ -4,8 +4,10 @@
#include "render/renderapi.h"
#include "vulkan_struct.h"
#include "vulkan_context.h"
#include "asset/res/guid.h"
namespace vulkanapi
{
using engineapi::Guid;
class RenderTarget;
class Swapchain;
class RenderVulkanAPI : public RenderAPI
@ -15,10 +17,9 @@ namespace vulkanapi
VulkanContext context;
Swapchain* swapchain{nullptr};
vector<RenderTarget*> TargetList;
vector<VulkanVAO*> VAOList;
vector<RenderPass*> PassList;
vector<VulkanPipeline*> PiPelineList;
hash_table<Guid, void*> ShaderInfoList;
hash_table<Guid, VulkanPipeline> PipelineTable;
hash_table<Guid, VulkanVAO> VAOTable;
public:
RenderVulkanAPI();
~RenderVulkanAPI()override;
@ -36,13 +37,10 @@ namespace vulkanapi
void BeginFrame()override;
void EndFrame()override;
void SetStaticMesh(Mesh* mesh)override;
void DrawStaticMesh(Mesh* mesh)override;
void SetStaticMesh(Mesh& mesh)override;
void DrawStaticMesh(Mesh& mesh)override;
void LoadShader(Shader* shader)override;
public:
VulkanVAO* GetNextVAO(uint32_t& index);
VulkanPipeline* GetNextPipeline(uint32_t& index);
void LoadShader(Shader& shader)override;
public:
static RenderVulkanAPI* GetSingletonPtr() {
return (RenderVulkanAPI*)RenderAPI::GetSingletonPtr();

View File

@ -7,9 +7,8 @@ target("zengine")
set_rundir(".")
add_rules("volk.env", "glsl.env")
add_rules("c++.codegen",{
files = {"src/engine/render/meta/*.h",
"src/engine/asset/res/guid.h",
"src/engine/asset/res/meta_bundle.h",}
files = {"src/engine/render/asset/*.h",
"src/engine/asset/res/*.h"}
})
add_deps("zlog","zlib")
add_defines("VULKAN_API")