Implementing basic asset serialization
This commit is contained in:
+14
-31
@@ -1,64 +1,47 @@
|
||||
#include "Asset.h"
|
||||
#include "AssetRegistry.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
Asset::Asset()
|
||||
: fullPath("")
|
||||
: folderPath("")
|
||||
, name("")
|
||||
, parentDir("")
|
||||
, extension("")
|
||||
, status(Status::Uninitialized)
|
||||
, byteSize(0)
|
||||
{
|
||||
}
|
||||
Asset::Asset(const std::filesystem::path& path)
|
||||
Asset::Asset(std::string_view _folderPath, std::string_view _name)
|
||||
: status(Status::Uninitialized)
|
||||
, folderPath(_folderPath)
|
||||
, name(_name)
|
||||
{
|
||||
if(path.is_absolute())
|
||||
if (folderPath.empty())
|
||||
{
|
||||
fullPath = path;
|
||||
assetId = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
fullPath = AssetRegistry::getRootFolder();
|
||||
fullPath.append(path.generic_string());
|
||||
assetId = folderPath + "/" + name;
|
||||
}
|
||||
|
||||
fullPath.make_preferred();
|
||||
parentDir = fullPath.parent_path();
|
||||
name = fullPath.stem();
|
||||
extension = fullPath.extension();
|
||||
}
|
||||
|
||||
Asset::Asset(const std::string &directory, const std::string &fileName)
|
||||
: Asset(std::filesystem::path(directory + fileName))
|
||||
{
|
||||
}
|
||||
|
||||
Asset::~Asset()
|
||||
{
|
||||
}
|
||||
|
||||
std::ifstream Asset::getReadStream() const
|
||||
std::string Asset::getFolderPath() const
|
||||
{
|
||||
return std::ifstream(fullPath, std::ios::binary);
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
std::ofstream Asset::getWriteStream() const
|
||||
std::string Asset::getName() const
|
||||
{
|
||||
return std::ofstream(fullPath, std::ios::binary);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string Asset::getFileName() const
|
||||
std::string Asset::getAssetIdentifier() const
|
||||
{
|
||||
return name.generic_string();
|
||||
return assetId;
|
||||
}
|
||||
std::string Asset::getFullPath() const
|
||||
{
|
||||
return fullPath.generic_string();
|
||||
}
|
||||
std::string Asset::getExtension() const
|
||||
{
|
||||
return extension.generic_string();
|
||||
}
|
||||
+16
-23
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "MinimalEngine.h"
|
||||
#include "Serialization/ArchiveBuffer.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
@@ -14,39 +15,31 @@ public:
|
||||
Ready
|
||||
};
|
||||
Asset();
|
||||
Asset(const std::string& directory, const std::string& name);
|
||||
Asset(const std::filesystem::path& path);
|
||||
Asset(std::string_view folderPath, std::string_view name);
|
||||
virtual ~Asset();
|
||||
|
||||
virtual void save(Gfx::PGraphics graphics) = 0;
|
||||
virtual void load(Gfx::PGraphics graphics) = 0;
|
||||
virtual void save(ArchiveBuffer& buffer) const = 0;
|
||||
virtual void load(ArchiveBuffer& buffer) = 0;
|
||||
|
||||
// returns the name of the file, without extension
|
||||
std::string getFileName() const;
|
||||
// returns the full absolute path, from root to extension
|
||||
std::string getFullPath() const;
|
||||
// returns the file extension, without preceding dot
|
||||
std::string getExtension() const;
|
||||
inline Status getStatus()
|
||||
// returns the assets name
|
||||
std::string getName() const;
|
||||
// returns the (virtual) folder path
|
||||
std::string getFolderPath() const;
|
||||
// returns the identifier with which it can be found from the asset registry
|
||||
std::string getAssetIdentifier() const;
|
||||
|
||||
constexpr Status getStatus()
|
||||
{
|
||||
std::scoped_lock lck(lock);
|
||||
return status;
|
||||
}
|
||||
inline void setStatus(Status _status)
|
||||
constexpr void setStatus(Status _status)
|
||||
{
|
||||
std::scoped_lock lck(lock);
|
||||
status = _status;
|
||||
}
|
||||
protected:
|
||||
std::mutex lock;
|
||||
std::ifstream getReadStream() const;
|
||||
std::ofstream getWriteStream() const;
|
||||
private:
|
||||
// Path relative to the project root
|
||||
std::filesystem::path fullPath;
|
||||
std::filesystem::path name;
|
||||
std::filesystem::path parentDir;
|
||||
std::filesystem::path extension;
|
||||
std::string folderPath;
|
||||
std::string name;
|
||||
std::string assetId;
|
||||
Status status;
|
||||
uint32 byteSize;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "FontAsset.h"
|
||||
#include "TextureAsset.h"
|
||||
#include "MaterialAsset.h"
|
||||
#include "MaterialInstanceAsset.h"
|
||||
#include "FontLoader.h"
|
||||
#include "TextureLoader.h"
|
||||
#include "MaterialLoader.h"
|
||||
@@ -15,12 +16,12 @@
|
||||
#include <iostream>
|
||||
|
||||
using namespace Seele;
|
||||
using json = nlohmann::json;
|
||||
|
||||
extern AssetRegistry* instance;
|
||||
|
||||
AssetRegistry::~AssetRegistry()
|
||||
{
|
||||
delete assetRoot;
|
||||
}
|
||||
|
||||
void AssetRegistry::init(const std::string& rootFolder, Gfx::PGraphics graphics)
|
||||
@@ -30,28 +31,47 @@ void AssetRegistry::init(const std::string& rootFolder, Gfx::PGraphics graphics)
|
||||
|
||||
void AssetRegistry::importMesh(MeshImportArgs args)
|
||||
{
|
||||
if (get().getOrCreateFolder(args.importPath)->meshes.contains(args.filePath.stem().string()))
|
||||
{
|
||||
// skip importing duplicates
|
||||
return;
|
||||
}
|
||||
get().meshLoader->importAsset(args);
|
||||
}
|
||||
|
||||
void AssetRegistry::importTexture(TextureImportArgs args)
|
||||
{
|
||||
if (get().getOrCreateFolder(args.importPath)->textures.contains(args.filePath.stem().string()))
|
||||
{
|
||||
// skip importing duplicates
|
||||
return;
|
||||
}
|
||||
get().textureLoader->importAsset(args);
|
||||
}
|
||||
|
||||
void AssetRegistry::importFont(FontImportArgs args)
|
||||
{
|
||||
if (get().getOrCreateFolder(args.importPath)->fonts.contains(args.filePath.stem().string()))
|
||||
{
|
||||
// skip importing duplicates
|
||||
return;
|
||||
}
|
||||
get().fontLoader->importAsset(args);
|
||||
}
|
||||
|
||||
void AssetRegistry::importMaterial(MaterialImportArgs args)
|
||||
{
|
||||
if (get().getOrCreateFolder(args.importPath)->materials.contains(args.filePath.stem().string()))
|
||||
{
|
||||
// skip importing duplicates
|
||||
return;
|
||||
}
|
||||
get().materialLoader->importAsset(args);
|
||||
}
|
||||
|
||||
|
||||
PMeshAsset AssetRegistry::findMesh(const std::string &filePath)
|
||||
{
|
||||
AssetFolder& folder = get().assetRoot;
|
||||
AssetFolder* folder = get().assetRoot;
|
||||
std::string fileName = filePath;
|
||||
size_t slashLoc = filePath.rfind("/");
|
||||
if(slashLoc != -1)
|
||||
@@ -59,30 +79,25 @@ PMeshAsset AssetRegistry::findMesh(const std::string &filePath)
|
||||
folder = get().getOrCreateFolder(filePath.substr(0, slashLoc));
|
||||
fileName = filePath.substr(slashLoc+1, filePath.size());
|
||||
}
|
||||
auto it = folder.meshes.find(fileName);
|
||||
assert(it != folder.meshes.end());
|
||||
return it->second;
|
||||
return folder->meshes.at(fileName);
|
||||
}
|
||||
|
||||
PTextureAsset AssetRegistry::findTexture(const std::string &filePath)
|
||||
{
|
||||
AssetFolder* folder = get().assetRoot;
|
||||
std::string fileName = filePath;
|
||||
size_t slashLoc = filePath.rfind("/");
|
||||
if(slashLoc != -1)
|
||||
if (slashLoc != -1)
|
||||
{
|
||||
AssetFolder& folder = get().getOrCreateFolder(filePath.substr(0, slashLoc));
|
||||
fileName = filePath.substr(slashLoc+1, filePath.size());
|
||||
return folder.textures[fileName];
|
||||
}
|
||||
else
|
||||
{
|
||||
return get().assetRoot.textures[fileName];
|
||||
folder = get().getOrCreateFolder(filePath.substr(0, slashLoc));
|
||||
fileName = filePath.substr(slashLoc + 1, filePath.size());
|
||||
}
|
||||
return folder->textures.at(fileName);
|
||||
}
|
||||
|
||||
PFontAsset AssetRegistry::findFont(const std::string& filePath)
|
||||
{
|
||||
AssetFolder& folder = get().assetRoot;
|
||||
AssetFolder* folder = get().assetRoot;
|
||||
std::string fileName = filePath;
|
||||
size_t slashLoc = filePath.rfind("/");
|
||||
if(slashLoc != -1)
|
||||
@@ -90,20 +105,20 @@ PFontAsset AssetRegistry::findFont(const std::string& filePath)
|
||||
folder = get().getOrCreateFolder(filePath.substr(0, slashLoc));
|
||||
fileName = filePath.substr(slashLoc+1, filePath.size());
|
||||
}
|
||||
return folder.fonts[fileName];
|
||||
return folder->fonts.at(fileName);
|
||||
}
|
||||
|
||||
PMaterialAsset AssetRegistry::findMaterial(const std::string &filePath)
|
||||
{
|
||||
AssetFolder& folder = get().assetRoot;
|
||||
AssetFolder* folder = get().assetRoot;
|
||||
std::string fileName = filePath;
|
||||
size_t slashLoc = filePath.rfind("/");
|
||||
if(slashLoc != -1)
|
||||
if (slashLoc != -1)
|
||||
{
|
||||
folder = get().getOrCreateFolder(filePath.substr(0, slashLoc));
|
||||
fileName = filePath.substr(slashLoc+1, filePath.size());
|
||||
fileName = filePath.substr(slashLoc + 1, filePath.size());
|
||||
}
|
||||
return folder.materials[fileName];
|
||||
return folder->materials.at(fileName);
|
||||
}
|
||||
|
||||
std::ofstream AssetRegistry::createWriteStream(const std::string& relativePath, std::ios_base::openmode openmode)
|
||||
@@ -125,57 +140,256 @@ AssetRegistry::AssetRegistry()
|
||||
{
|
||||
}
|
||||
|
||||
void AssetRegistry::loadRegistry()
|
||||
{
|
||||
get().loadRegistryInternal();
|
||||
}
|
||||
|
||||
void AssetRegistry::saveRegistry()
|
||||
{
|
||||
get().saveRegistryInternal();
|
||||
}
|
||||
|
||||
void AssetRegistry::initialize(const std::filesystem::path &_rootFolder, Gfx::PGraphics _graphics)
|
||||
{
|
||||
this->graphics = _graphics;
|
||||
this->rootFolder = _rootFolder;
|
||||
this->assetRoot = new AssetFolder("");
|
||||
this->fontLoader = new FontLoader(graphics);
|
||||
this->meshLoader = new MeshLoader(graphics);
|
||||
this->textureLoader = new TextureLoader(graphics);
|
||||
this->materialLoader = new MaterialLoader(graphics);
|
||||
loadRegistryInternal();
|
||||
}
|
||||
|
||||
std::string AssetRegistry::getRootFolder()
|
||||
void AssetRegistry::loadRegistryInternal()
|
||||
{
|
||||
return get().rootFolder.generic_string();
|
||||
peekFolder(assetRoot);
|
||||
loadFolder(assetRoot);
|
||||
}
|
||||
|
||||
void AssetRegistry::registerMesh(PMeshAsset mesh, const std::string& importPath)
|
||||
|
||||
void AssetRegistry::peekFolder(AssetFolder* folder)
|
||||
{
|
||||
AssetFolder& folder = getOrCreateFolder(importPath);
|
||||
folder.meshes[mesh->getFileName()] = mesh;
|
||||
for (const auto& entry : std::filesystem::directory_iterator(rootFolder / folder->folderPath))
|
||||
{
|
||||
const auto& stem = entry.path().stem().string();
|
||||
if (entry.is_directory())
|
||||
{
|
||||
if (folder->folderPath.empty())
|
||||
{
|
||||
folder->children[stem] = new AssetFolder(stem);
|
||||
}
|
||||
else
|
||||
{
|
||||
folder->children[stem] = new AssetFolder(folder->folderPath + "/" + stem);
|
||||
}
|
||||
peekFolder(folder->children[stem]);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto stream = std::ifstream(entry.path(), std::ios::binary);
|
||||
|
||||
ArchiveBuffer buffer(graphics);
|
||||
buffer.readFromStream(stream);
|
||||
|
||||
// Read asset type
|
||||
uint64 identifier;
|
||||
Serialization::load(buffer, identifier);
|
||||
|
||||
// Read name
|
||||
std::string name;
|
||||
Serialization::load(buffer, name);
|
||||
|
||||
// Read folder
|
||||
std::string folderPath;
|
||||
Serialization::load(buffer, folderPath);
|
||||
|
||||
PAsset asset;
|
||||
switch (identifier)
|
||||
{
|
||||
case TextureAsset::IDENTIFIER:
|
||||
asset = new TextureAsset(folderPath, name);
|
||||
folder->textures[asset->getName()] = asset;
|
||||
break;
|
||||
case MeshAsset::IDENTIFIER:
|
||||
asset = new MeshAsset(folderPath, name);
|
||||
folder->meshes[asset->getName()] = asset;
|
||||
break;
|
||||
case MaterialAsset::IDENTIFIER:
|
||||
asset = new MaterialAsset(folderPath, name);
|
||||
folder->materials[asset->getName()] = asset;
|
||||
break;
|
||||
case MaterialInstanceAsset::IDENTIFIER:
|
||||
asset = new MaterialInstanceAsset(folderPath, name);
|
||||
// TODO
|
||||
break;
|
||||
case FontAsset::IDENTIFIER:
|
||||
asset = new FontAsset(folderPath, name);
|
||||
folder->fonts[asset->getName()] = asset;
|
||||
break;
|
||||
default:
|
||||
throw new std::logic_error("Unknown Identifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetRegistry::registerTexture(PTextureAsset texture, const std::string& importPath)
|
||||
|
||||
void AssetRegistry::loadFolder(AssetFolder* folder)
|
||||
{
|
||||
AssetFolder& folder = getOrCreateFolder(importPath);
|
||||
folder.textures[texture->getFileName()] = texture;
|
||||
for (const auto& entry : std::filesystem::directory_iterator(rootFolder / folder->folderPath))
|
||||
{
|
||||
const auto& path = entry.path();
|
||||
if (entry.is_directory())
|
||||
{
|
||||
auto relative = path.stem().string();
|
||||
loadFolder(folder->children[relative]);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto stream = std::ifstream(path, std::ios::binary);
|
||||
|
||||
ArchiveBuffer buffer(graphics);
|
||||
buffer.readFromStream(stream);
|
||||
|
||||
// Read asset type
|
||||
uint64 identifier;
|
||||
Serialization::load(buffer, identifier);
|
||||
|
||||
// Read name
|
||||
std::string name;
|
||||
Serialization::load(buffer, name);
|
||||
|
||||
// Read folder
|
||||
std::string folderPath;
|
||||
Serialization::load(buffer, folderPath);
|
||||
|
||||
PAsset asset;
|
||||
switch (identifier)
|
||||
{
|
||||
case TextureAsset::IDENTIFIER:
|
||||
asset = folder->textures.at(name);
|
||||
break;
|
||||
case MeshAsset::IDENTIFIER:
|
||||
asset = folder->meshes.at(name);
|
||||
break;
|
||||
case MaterialAsset::IDENTIFIER:
|
||||
asset = folder->materials.at(name);
|
||||
break;
|
||||
case MaterialInstanceAsset::IDENTIFIER:
|
||||
//asset = new MaterialInstanceAsset(path);
|
||||
// TODO
|
||||
break;
|
||||
case FontAsset::IDENTIFIER:
|
||||
asset = folder->fonts.at(name);
|
||||
break;
|
||||
default:
|
||||
throw new std::logic_error("Unknown Identifier");
|
||||
}
|
||||
asset->load(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetRegistry::registerFont(PFontAsset font, const std::string& importPath)
|
||||
{
|
||||
AssetFolder& folder = getOrCreateFolder(importPath);
|
||||
folder.fonts[font->getFileName()] = font;
|
||||
void AssetRegistry::saveRegistryInternal()
|
||||
{
|
||||
saveFolder("", assetRoot);
|
||||
}
|
||||
|
||||
void AssetRegistry::registerMaterial(PMaterialAsset material, const std::string& importPath)
|
||||
void AssetRegistry::saveFolder(const std::filesystem::path& folderPath, AssetFolder* folder)
|
||||
{
|
||||
AssetFolder& folder = getOrCreateFolder(importPath);
|
||||
folder.materials[material->getFileName()] = material;
|
||||
std::filesystem::create_directory(rootFolder / folderPath);
|
||||
for (const auto& [name, texture] : folder->textures)
|
||||
{
|
||||
saveAsset(texture, TextureAsset::IDENTIFIER, folderPath, name);
|
||||
}
|
||||
for (const auto& [name, mesh] : folder->meshes)
|
||||
{
|
||||
saveAsset(mesh, MeshAsset::IDENTIFIER, folderPath, name);
|
||||
}
|
||||
for (const auto& [name, material] : folder->materials)
|
||||
{
|
||||
saveAsset(material, MaterialAsset::IDENTIFIER, folderPath, name);
|
||||
}
|
||||
for (const auto& [name, font] : folder->fonts)
|
||||
{
|
||||
saveAsset(font, FontAsset::IDENTIFIER, folderPath, name);
|
||||
}
|
||||
for (auto& [name, child] : folder->children)
|
||||
{
|
||||
saveFolder(folderPath / name, child);
|
||||
}
|
||||
}
|
||||
|
||||
AssetRegistry::AssetFolder& AssetRegistry::getOrCreateFolder(std::string fullPath)
|
||||
void AssetRegistry::saveAsset(PAsset asset, uint64 identifier, const std::filesystem::path& folderPath, std::string name)
|
||||
{
|
||||
AssetFolder& result = assetRoot;
|
||||
if (name.empty())
|
||||
return;
|
||||
|
||||
std::string path = (folderPath / name).string().append(".asset");
|
||||
auto assetStream = createWriteStream(std::move(path), std::ios::binary);
|
||||
ArchiveBuffer assetBuffer(graphics);
|
||||
// write identifier
|
||||
Serialization::save(assetBuffer, identifier);
|
||||
// write name
|
||||
Serialization::save(assetBuffer, name);
|
||||
// write folder
|
||||
Serialization::save(assetBuffer, folderPath.string());
|
||||
// write asset data
|
||||
asset->save(assetBuffer);
|
||||
assetBuffer.writeToStream(assetStream);
|
||||
|
||||
}
|
||||
|
||||
std::filesystem::path AssetRegistry::getRootFolder()
|
||||
{
|
||||
return get().rootFolder;
|
||||
}
|
||||
|
||||
void AssetRegistry::registerMesh(PMeshAsset mesh)
|
||||
{
|
||||
AssetFolder* folder = getOrCreateFolder(mesh->getFolderPath());
|
||||
folder->meshes[mesh->getName()] = mesh;
|
||||
}
|
||||
|
||||
void AssetRegistry::registerTexture(PTextureAsset texture)
|
||||
{
|
||||
AssetFolder* folder = getOrCreateFolder(texture->getFolderPath());
|
||||
folder->textures[texture->getName()] = texture;
|
||||
}
|
||||
|
||||
void AssetRegistry::registerFont(PFontAsset font)
|
||||
{
|
||||
AssetFolder* folder = getOrCreateFolder(font->getFolderPath());
|
||||
folder->fonts[font->getName()] = font;
|
||||
}
|
||||
|
||||
void AssetRegistry::registerMaterial(PMaterialAsset material)
|
||||
{
|
||||
AssetFolder* folder = getOrCreateFolder(material->getFolderPath());
|
||||
folder->materials[material->getName()] = material;
|
||||
}
|
||||
|
||||
AssetRegistry::AssetFolder* AssetRegistry::getOrCreateFolder(std::string fullPath)
|
||||
{
|
||||
AssetFolder* result = assetRoot;
|
||||
std::string temp = fullPath;
|
||||
while(!fullPath.empty())
|
||||
{
|
||||
size_t slashLoc = fullPath.find("/");
|
||||
if(slashLoc == -1)
|
||||
{
|
||||
return result.children[fullPath];
|
||||
if (!result->children.contains(fullPath))
|
||||
{
|
||||
result->children[fullPath] = new AssetFolder(fullPath);
|
||||
}
|
||||
return result->children[fullPath];
|
||||
}
|
||||
std::string folderName = fullPath.substr(0, slashLoc);
|
||||
result = result.children[folderName];
|
||||
if (!result->children.contains(folderName))
|
||||
{
|
||||
result->children[folderName] = new AssetFolder(temp);
|
||||
}
|
||||
result = result->children[folderName];
|
||||
fullPath = fullPath.substr(slashLoc+1, fullPath.size());
|
||||
}
|
||||
return result;
|
||||
@@ -194,3 +408,15 @@ std::ifstream AssetRegistry::internalCreateReadStream(const std::string& relativ
|
||||
fullPath.append(relativePath);
|
||||
return std::ifstream(fullPath.string(), openmode);
|
||||
}
|
||||
|
||||
AssetRegistry::AssetFolder::AssetFolder(std::string_view folderPath)
|
||||
: folderPath(folderPath)
|
||||
{}
|
||||
|
||||
AssetRegistry::AssetFolder::~AssetFolder()
|
||||
{
|
||||
for (const auto& [_, child] : children)
|
||||
{
|
||||
delete child;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include "MinimalEngine.h"
|
||||
#include "Asset.h"
|
||||
#include "Containers/Map.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
~AssetRegistry();
|
||||
static void init(const std::string& rootFolder, Gfx::PGraphics graphics);
|
||||
|
||||
static std::string getRootFolder();
|
||||
static std::filesystem::path getRootFolder();
|
||||
|
||||
static PMeshAsset findMesh(const std::string& filePath);
|
||||
static PTextureAsset findTexture(const std::string& filePath);
|
||||
@@ -37,35 +37,47 @@ public:
|
||||
static void importFont(struct FontImportArgs args);
|
||||
static void importMaterial(struct MaterialImportArgs args);
|
||||
static void set(AssetRegistry registry);
|
||||
|
||||
static void loadRegistry();
|
||||
static void saveRegistry();
|
||||
|
||||
AssetRegistry();
|
||||
private:
|
||||
struct AssetFolder
|
||||
{
|
||||
std::map<std::string, AssetFolder> children;
|
||||
std::string folderPath;
|
||||
Map<std::string, AssetFolder*> children;
|
||||
//Todo: Seele::Map doesn't really work with strings for some reason, so just use std::map for now
|
||||
std::map<std::string, PTextureAsset> textures;
|
||||
std::map<std::string, PFontAsset> fonts;
|
||||
std::map<std::string, PMeshAsset> meshes;
|
||||
std::map<std::string, PMaterialAsset> materials;
|
||||
Map<std::string, PTextureAsset> textures;
|
||||
Map<std::string, PFontAsset> fonts;
|
||||
Map<std::string, PMeshAsset> meshes;
|
||||
Map<std::string, PMaterialAsset> materials;
|
||||
AssetFolder(std::string_view folderPath);
|
||||
~AssetFolder();
|
||||
};
|
||||
|
||||
static AssetRegistry& get();
|
||||
|
||||
void initialize(const std::filesystem::path& rootFolder, Gfx::PGraphics graphics);
|
||||
void loadRegistryInternal();
|
||||
void peekFolder(AssetFolder* folder);
|
||||
void loadFolder(AssetFolder* folder);
|
||||
void saveRegistryInternal();
|
||||
void saveFolder(const std::filesystem::path& folderPath, AssetFolder* folder);
|
||||
void saveAsset(PAsset asset, uint64 identifier, const std::filesystem::path& folderPath, std::string name);
|
||||
|
||||
void registerMesh(PMeshAsset mesh);
|
||||
void registerTexture(PTextureAsset texture);
|
||||
void registerFont(PFontAsset font);
|
||||
void registerMaterial(PMaterialAsset material);
|
||||
|
||||
void registerMesh(PMeshAsset mesh, const std::string& importPath);
|
||||
void registerTexture(PTextureAsset texture, const std::string& importPath);
|
||||
void registerFont(PFontAsset font, const std::string& importPath);
|
||||
void registerMaterial(PMaterialAsset material, const std::string& importPath);
|
||||
|
||||
AssetFolder& getOrCreateFolder(std::string foldername);
|
||||
AssetFolder* getOrCreateFolder(std::string foldername);
|
||||
|
||||
std::ofstream internalCreateWriteStream(const std::string& relativePath, std::ios_base::openmode openmode = std::ios::out);
|
||||
std::ifstream internalCreateReadStream(const std::string& relaitvePath, std::ios_base::openmode openmode = std::ios::in);
|
||||
|
||||
std::filesystem::path rootFolder;
|
||||
AssetFolder assetRoot;
|
||||
AssetFolder* assetRoot;
|
||||
Gfx::PGraphics graphics;
|
||||
UPTextureLoader textureLoader;
|
||||
UPFontLoader fontLoader;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "FontAsset.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "Graphics/Vulkan/VulkanGraphicsEnums.h"
|
||||
#include <ktx.h>
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
@@ -7,13 +9,8 @@ FontAsset::FontAsset()
|
||||
{
|
||||
}
|
||||
|
||||
FontAsset::FontAsset(const std::string& directory, const std::string& name)
|
||||
: Asset(directory, name)
|
||||
{
|
||||
}
|
||||
|
||||
FontAsset::FontAsset(const std::filesystem::path& fullPath)
|
||||
: Asset(fullPath)
|
||||
FontAsset::FontAsset(std::string_view folderPath, std::string_view name)
|
||||
: Asset(folderPath, name)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -22,11 +19,108 @@ FontAsset::~FontAsset()
|
||||
|
||||
}
|
||||
|
||||
void FontAsset::save(Gfx::PGraphics graphics)
|
||||
void FontAsset::save(ArchiveBuffer& buffer) const
|
||||
{
|
||||
uint64 numGlyphs = glyphs.size();
|
||||
buffer.writeBytes(&numGlyphs, sizeof(uint64));
|
||||
for (auto& [index, glyph] : glyphs)
|
||||
{
|
||||
Serialization::save(buffer, index);
|
||||
|
||||
Array<uint8> textureData;
|
||||
ktxTexture2* kTexture;
|
||||
ktxTextureCreateInfo createInfo = {
|
||||
.vkFormat = (uint32_t)glyph.texture->getFormat(),
|
||||
.baseWidth = glyph.texture->getSizeX(),
|
||||
.baseHeight = glyph.texture->getSizeY(),
|
||||
.baseDepth = glyph.texture->getSizeZ(),
|
||||
.numDimensions = glyph.texture->getSizeZ() > 1 ? 3u : glyph.texture->getSizeY() > 1 ? 2u : 1u,
|
||||
.numLevels = glyph.texture->getMipLevels(),
|
||||
.numFaces = glyph.texture->getNumFaces(),
|
||||
.isArray = false,
|
||||
.generateMipmaps = false,
|
||||
};
|
||||
ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE, &kTexture);
|
||||
|
||||
for (uint32 depth = 0; depth < glyph.texture->getSizeZ(); ++depth)
|
||||
{
|
||||
for (uint32 face = 0; face < glyph.texture->getNumFaces(); ++face)
|
||||
{
|
||||
// technically, downloading cant be const, because we have to allocate temporary buffers and change layouts
|
||||
// but practically the texture stays the same
|
||||
glyph.texture->download(0, depth, face, textureData);
|
||||
ktxTexture_SetImageFromMemory(ktxTexture(kTexture), 0, depth, face, textureData.data(), textureData.size());
|
||||
}
|
||||
}
|
||||
char writer[100];
|
||||
snprintf(writer, sizeof(writer), "%s version %s", "SeeleEngine", "0.0.1");
|
||||
ktxHashList_AddKVPair(&kTexture->kvDataHead, KTX_WRITER_KEY,
|
||||
(ktx_uint32_t)strlen(writer) + 1,
|
||||
writer);
|
||||
|
||||
ktxTexture2_TranscodeBasis(kTexture, KTX_TTF_ASTC_4x4_RGBA, 0);
|
||||
|
||||
ktx_uint8_t* texData;
|
||||
ktx_size_t texSize;
|
||||
ktxTexture_WriteToMemory(ktxTexture(kTexture), &texData, &texSize);
|
||||
|
||||
buffer.writeBytes(texData, texSize);
|
||||
free(texData);
|
||||
|
||||
Serialization::save(buffer, glyph.size);
|
||||
Serialization::save(buffer, glyph.bearing);
|
||||
Serialization::save(buffer, glyph.advance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FontAsset::load(Gfx::PGraphics graphics)
|
||||
void FontAsset::load(ArchiveBuffer& buffer)
|
||||
{
|
||||
uint64 numGlyphs = glyphs.size();
|
||||
buffer.readBytes(&numGlyphs, sizeof(uint64));
|
||||
for (uint64 x = 0; x < numGlyphs; ++x)
|
||||
{
|
||||
uint32 index;
|
||||
Serialization::load(buffer, index);
|
||||
|
||||
Glyph& glyph = glyphs[index];
|
||||
|
||||
uint64 texSize;
|
||||
buffer.readBytes(&texSize, sizeof(uint64));
|
||||
Array<uint8> rawTex;
|
||||
rawTex.resize(texSize);
|
||||
buffer.readBytes(rawTex.data(), rawTex.size());
|
||||
|
||||
ktxTexture2* kTexture;
|
||||
ktxTexture2_CreateFromMemory(rawTex.data(),
|
||||
rawTex.size(),
|
||||
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
||||
&kTexture);
|
||||
|
||||
ktxTexture2_TranscodeBasis(kTexture, KTX_TTF_BC7_RGBA, 0);
|
||||
|
||||
TextureCreateInfo createInfo = {
|
||||
.resourceData = {
|
||||
.size = ktxTexture_GetDataSize(ktxTexture(kTexture)),
|
||||
.data = ktxTexture_GetData(ktxTexture(kTexture)),
|
||||
.owner = Gfx::QueueType::GRAPHICS,
|
||||
},
|
||||
.width = kTexture->baseWidth,
|
||||
.height = kTexture->baseHeight,
|
||||
.depth = kTexture->baseDepth,
|
||||
.bArray = kTexture->isArray,
|
||||
.arrayLayers = kTexture->isArray ? kTexture->numLayers : kTexture->numFaces,
|
||||
.mipLevels = kTexture->numLevels,
|
||||
.format = Vulkan::cast((VkFormat)kTexture->vkFormat),
|
||||
.usage = Gfx::SE_IMAGE_USAGE_SAMPLED_BIT,
|
||||
};
|
||||
|
||||
glyph.texture = buffer.getGraphics()->createTexture2D(createInfo);
|
||||
|
||||
ktxTexture_Destroy(ktxTexture(kTexture));
|
||||
|
||||
Serialization::load(buffer, glyph.size);
|
||||
Serialization::load(buffer, glyph.bearing);
|
||||
Serialization::load(buffer, glyph.advance);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include "Asset.h"
|
||||
#include "Containers/Map.h"
|
||||
#include "Math/Math.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
@@ -7,12 +9,12 @@ DECLARE_NAME_REF(Gfx, Texture2D)
|
||||
class FontAsset : public Asset
|
||||
{
|
||||
public:
|
||||
static constexpr uint64 IDENTIFIER = 0x10;
|
||||
FontAsset();
|
||||
FontAsset(const std::string& directory, const std::string& name);
|
||||
FontAsset(const std::filesystem::path& fullPath);
|
||||
FontAsset(std::string_view folderPath, std::string_view name);
|
||||
virtual ~FontAsset();
|
||||
virtual void save(Gfx::PGraphics graphics) override;
|
||||
virtual void load(Gfx::PGraphics graphics) override;
|
||||
virtual void save(ArchiveBuffer& buffer) const override;
|
||||
virtual void load(ArchiveBuffer& buffer) override;
|
||||
|
||||
struct Glyph
|
||||
{
|
||||
|
||||
@@ -22,11 +22,9 @@ void FontLoader::importAsset(FontImportArgs args)
|
||||
{
|
||||
std::filesystem::path assetPath = args.filePath.filename();
|
||||
assetPath.replace_extension("asset");
|
||||
PFontAsset asset = new FontAsset(assetPath.generic_string());
|
||||
std::error_code code;
|
||||
std::filesystem::copy_file(args.filePath, asset->getFullPath(), code);
|
||||
PFontAsset asset = new FontAsset(args.importPath, assetPath.stem().string());
|
||||
asset->setStatus(Asset::Status::Loading);
|
||||
AssetRegistry::get().registerFont(asset, args.importPath);
|
||||
AssetRegistry::get().registerFont(asset);
|
||||
import(args, asset);
|
||||
}
|
||||
|
||||
@@ -39,7 +37,7 @@ void FontLoader::import(FontImportArgs args, PFontAsset asset)
|
||||
FT_Error error = FT_Init_FreeType(&ft);
|
||||
assert(!error);
|
||||
FT_Face face;
|
||||
error = FT_New_Face(ft, asset->getFullPath().c_str(), 0, &face);
|
||||
error = FT_New_Face(ft, args.filePath.string().c_str(), 0, &face);
|
||||
assert(!error);
|
||||
FT_Set_Pixel_Sizes(face, 0, 48);
|
||||
for(uint32 c = 0; c < 256; ++c)
|
||||
@@ -59,7 +57,7 @@ void FontLoader::import(FontImportArgs args, PFontAsset asset)
|
||||
imageData.height = face->glyph->bitmap.rows;
|
||||
imageData.resourceData.data = face->glyph->bitmap.buffer;
|
||||
imageData.resourceData.size = imageData.width * imageData.height;
|
||||
if(imageData.width == 0 || imageData.width == 0)
|
||||
if(imageData.width == 0 || imageData.height == 0)
|
||||
{
|
||||
glyph.size.x = 1;
|
||||
glyph.size.y = 1;
|
||||
|
||||
@@ -8,13 +8,8 @@ MaterialAsset::MaterialAsset()
|
||||
{
|
||||
}
|
||||
|
||||
MaterialAsset::MaterialAsset(const std::string& directory, const std::string& name)
|
||||
: Asset(directory, name)
|
||||
{
|
||||
}
|
||||
|
||||
MaterialAsset::MaterialAsset(const std::filesystem::path& fullPath)
|
||||
: Asset(fullPath)
|
||||
MaterialAsset::MaterialAsset(std::string_view folderPath, std::string_view name)
|
||||
: Asset(folderPath, name)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -22,13 +17,14 @@ MaterialAsset::~MaterialAsset()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void MaterialAsset::save(Gfx::PGraphics graphics)
|
||||
void MaterialAsset::save(ArchiveBuffer& buffer) const
|
||||
{
|
||||
material->save(buffer);
|
||||
}
|
||||
|
||||
void MaterialAsset::load(Gfx::PGraphics graphics)
|
||||
void MaterialAsset::load(ArchiveBuffer& buffer)
|
||||
{
|
||||
|
||||
material = new Material();
|
||||
material->load(buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ DECLARE_REF(Material)
|
||||
class MaterialAsset : public Asset
|
||||
{
|
||||
public:
|
||||
static constexpr uint64 IDENTIFIER = 0x4;
|
||||
MaterialAsset();
|
||||
MaterialAsset(const std::string &directory, const std::string &name);
|
||||
MaterialAsset(const std::filesystem::path &fullPath);
|
||||
MaterialAsset(std::string_view folderPath, std::string_view name);
|
||||
virtual ~MaterialAsset();
|
||||
virtual void save(Gfx::PGraphics graphics) override;
|
||||
virtual void load(Gfx::PGraphics graphics) override;
|
||||
virtual void save(ArchiveBuffer& buffer) const override;
|
||||
virtual void load(ArchiveBuffer& buffer) override;
|
||||
PMaterial getMaterial() const { return material; }
|
||||
private:
|
||||
PMaterial material;
|
||||
|
||||
@@ -9,13 +9,8 @@ MaterialInstanceAsset::MaterialInstanceAsset()
|
||||
{
|
||||
}
|
||||
|
||||
MaterialInstanceAsset::MaterialInstanceAsset(const std::string& directory, const std::string& name)
|
||||
: Asset(directory, name)
|
||||
{
|
||||
}
|
||||
|
||||
MaterialInstanceAsset::MaterialInstanceAsset(const std::filesystem::path& fullPath)
|
||||
: Asset(fullPath)
|
||||
MaterialInstanceAsset::MaterialInstanceAsset(std::string_view folderPath, std::string_view name)
|
||||
: Asset(folderPath, name)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -24,10 +19,10 @@ MaterialInstanceAsset::~MaterialInstanceAsset()
|
||||
}
|
||||
|
||||
|
||||
void MaterialInstanceAsset::save(Gfx::PGraphics graphics)
|
||||
void MaterialInstanceAsset::save(ArchiveBuffer& buffer) const
|
||||
{
|
||||
}
|
||||
|
||||
void MaterialInstanceAsset::load(Gfx::PGraphics graphics)
|
||||
void MaterialInstanceAsset::load(ArchiveBuffer& buffer)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ namespace Seele
|
||||
class MaterialInstanceAsset : public Asset
|
||||
{
|
||||
public:
|
||||
static constexpr uint64 IDENTIFIER = 0x8;
|
||||
MaterialInstanceAsset();
|
||||
MaterialInstanceAsset(const std::string &directory, const std::string &name);
|
||||
MaterialInstanceAsset(const std::filesystem::path &fullPath);
|
||||
MaterialInstanceAsset(std::string_view folderPath, std::string_view name);
|
||||
virtual ~MaterialInstanceAsset();
|
||||
virtual void save(Gfx::PGraphics graphics) override;
|
||||
virtual void load(Gfx::PGraphics graphics) override;
|
||||
virtual void save(ArchiveBuffer& buffer) const override;
|
||||
virtual void load(ArchiveBuffer& buffer) override;
|
||||
private:
|
||||
PMaterialInstance material;
|
||||
};
|
||||
|
||||
@@ -29,9 +29,9 @@ void MaterialLoader::importAsset(MaterialImportArgs args)
|
||||
{
|
||||
std::filesystem::path assetPath = args.filePath.filename();
|
||||
assetPath.replace_extension("asset");
|
||||
PMaterialAsset asset = new MaterialAsset(assetPath.generic_string());
|
||||
PMaterialAsset asset = new MaterialAsset(args.importPath, assetPath.stem().string());
|
||||
asset->setStatus(Asset::Status::Loading);
|
||||
AssetRegistry::get().registerMaterial(asset, args.importPath);
|
||||
AssetRegistry::get().registerMaterial(asset);
|
||||
import(args, asset);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "MeshAsset.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "Graphics/Mesh.h"
|
||||
#include "AssetRegistry.h"
|
||||
#include "Graphics/VertexShaderInput.h"
|
||||
#include "Material/MaterialInterface.h"
|
||||
#include "Graphics/StaticMeshVertexInput.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
@@ -10,34 +12,64 @@ MeshAsset::MeshAsset()
|
||||
{
|
||||
}
|
||||
|
||||
MeshAsset::MeshAsset(const std::string& directory, const std::string& name)
|
||||
: Asset(directory, name)
|
||||
{
|
||||
}
|
||||
MeshAsset::MeshAsset(const std::filesystem::path& fullPath)
|
||||
: Asset(fullPath)
|
||||
MeshAsset::MeshAsset(std::string_view folderPath, std::string_view name)
|
||||
: Asset(folderPath, name)
|
||||
{
|
||||
}
|
||||
|
||||
MeshAsset::~MeshAsset()
|
||||
{
|
||||
|
||||
}
|
||||
void MeshAsset::save(Gfx::PGraphics graphics)
|
||||
|
||||
void MeshAsset::save(ArchiveBuffer& buffer) const
|
||||
{
|
||||
uint64 numMeshes = meshes.size();
|
||||
Serialization::save(buffer, numMeshes);
|
||||
for (auto mesh : meshes)
|
||||
{
|
||||
mesh->vertexInput->save(buffer);
|
||||
Array<uint8> rawIndices;
|
||||
mesh->indexBuffer->download(rawIndices);
|
||||
Serialization::save(buffer, rawIndices);
|
||||
Serialization::save(buffer, mesh->indexBuffer->getIndexType());
|
||||
Serialization::save(buffer, mesh->referencedMaterial->getAssetIdentifier());
|
||||
}
|
||||
}
|
||||
void MeshAsset::load(Gfx::PGraphics graphics)
|
||||
|
||||
void MeshAsset::load(ArchiveBuffer& buffer)
|
||||
{
|
||||
uint64 numMeshes = 0;
|
||||
Serialization::load(buffer, numMeshes);
|
||||
meshes.resize(numMeshes);
|
||||
for (auto& mesh : meshes)
|
||||
{
|
||||
PVertexShaderInput vertexInput = new StaticMeshVertexInput("");
|
||||
vertexInput->load(buffer);
|
||||
Array<uint8> rawIndices;
|
||||
Serialization::load(buffer, rawIndices);
|
||||
Gfx::SeIndexType indexType;
|
||||
Serialization::load(buffer, indexType);
|
||||
IndexBufferCreateInfo createInfo = {
|
||||
.resourceData = {
|
||||
.size = rawIndices.size(),
|
||||
.data = rawIndices.data(),
|
||||
},
|
||||
.indexType = indexType,
|
||||
};
|
||||
Gfx::PIndexBuffer indexBuffer = buffer.getGraphics()->createIndexBuffer(createInfo);
|
||||
mesh = new Mesh(vertexInput, indexBuffer);
|
||||
std::string matname;
|
||||
Serialization::load(buffer, matname);
|
||||
mesh->referencedMaterial = AssetRegistry::findMaterial(matname);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshAsset::addMesh(PMesh mesh)
|
||||
{
|
||||
std::scoped_lock lck(lock);
|
||||
meshes.add(mesh);
|
||||
referencedMaterials.add(mesh->referencedMaterial);
|
||||
}
|
||||
|
||||
const Array<PMesh> MeshAsset::getMeshes()
|
||||
{
|
||||
std::scoped_lock lck(lock);
|
||||
return meshes;
|
||||
}
|
||||
@@ -9,16 +9,15 @@ DECLARE_REF(MaterialInterface)
|
||||
class MeshAsset : public Asset
|
||||
{
|
||||
public:
|
||||
static constexpr uint64 IDENTIFIER = 0x2;
|
||||
MeshAsset();
|
||||
MeshAsset(const std::string& directory, const std::string& name);
|
||||
MeshAsset(const std::filesystem::path& fullPath);
|
||||
MeshAsset(std::string_view folderPath, std::string_view name);
|
||||
virtual ~MeshAsset();
|
||||
virtual void save(Gfx::PGraphics graphics) override;
|
||||
virtual void load(Gfx::PGraphics graphics) override;
|
||||
virtual void save(ArchiveBuffer& buffer) const override;
|
||||
virtual void load(ArchiveBuffer& buffer) override;
|
||||
void addMesh(PMesh mesh);
|
||||
const Array<PMesh> getMeshes();
|
||||
//Workaround while no editor
|
||||
Array<PMaterialInterface> referencedMaterials;
|
||||
Array<PMesh> meshes;
|
||||
Component::Collider physicsMesh;
|
||||
};
|
||||
|
||||
@@ -33,20 +33,20 @@ void MeshLoader::importAsset(MeshImportArgs args)
|
||||
{
|
||||
std::filesystem::path assetPath = args.filePath.filename();
|
||||
assetPath.replace_extension("asset");
|
||||
PMeshAsset asset = new MeshAsset(assetPath.generic_string());
|
||||
PMeshAsset asset = new MeshAsset(args.importPath, assetPath.stem().string());
|
||||
asset->setStatus(Asset::Status::Loading);
|
||||
AssetRegistry::get().registerMesh(asset, args.importPath);
|
||||
AssetRegistry::get().registerMesh(asset);
|
||||
import(args, asset);
|
||||
}
|
||||
|
||||
void MeshLoader::loadMaterials(const aiScene* scene, Array<PMaterial>& globalMaterials)
|
||||
void MeshLoader::loadMaterials(const aiScene* scene, const std::string& baseName, const std::filesystem::path& meshDirectory, const std::string& importPath, Array<PMaterialAsset>& globalMaterials)
|
||||
{
|
||||
using json = nlohmann::json;
|
||||
for(uint32 i = 0; i < scene->mNumMaterials; ++i)
|
||||
{
|
||||
aiMaterial* material = scene->mMaterials[i];
|
||||
json matCode;
|
||||
matCode["name"] = material->GetName().C_Str();
|
||||
matCode["name"] = baseName + material->GetName().C_Str();
|
||||
matCode["profile"] = "BlinnPhong"; //TODO: other shading models
|
||||
aiString texPath;
|
||||
//TODO make samplers based on used textures
|
||||
@@ -89,18 +89,17 @@ void MeshLoader::loadMaterials(const aiScene* scene, Array<PMaterial>& globalMat
|
||||
matCode["code"]["normal"] = "return normalTexture.Sample(textureSampler, input.texCoords[0]).xyz;";
|
||||
}
|
||||
std::string outMatFilename = matCode["name"].get<std::string>().append(".asset");
|
||||
std::ofstream outMatFile = AssetRegistry::createWriteStream(outMatFilename);
|
||||
std::ofstream outMatFile = std::ofstream(meshDirectory / outMatFilename);
|
||||
outMatFile << std::setw(4) << matCode;
|
||||
outMatFile.flush();
|
||||
outMatFile.close();
|
||||
|
||||
std::cout << "writing json to " << outMatFilename << std::endl;
|
||||
AssetRegistry::importMaterial(MaterialImportArgs{
|
||||
.filePath = AssetRegistry::getRootFolder() + "/" + outMatFilename,
|
||||
.importPath = "",
|
||||
.filePath = meshDirectory / outMatFilename,
|
||||
.importPath = importPath,
|
||||
});
|
||||
PMaterialAsset asset = AssetRegistry::findMaterial(matCode["name"].get<std::string>());
|
||||
globalMaterials[i] = asset->getMaterial();
|
||||
globalMaterials[i] = AssetRegistry::findMaterial(matCode["name"].get<std::string>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +167,7 @@ VertexStreamComponent createVertexStream(uint32 size, aiColor4D* sourceData, Gfx
|
||||
vertexBuffer->transferOwnership(Gfx::QueueType::GRAPHICS);
|
||||
return VertexStreamComponent(vertexBuffer, 0, vbInfo.vertexSize, Gfx::SE_FORMAT_R32G32B32A32_SFLOAT);
|
||||
}
|
||||
void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterial>& materials, Array<PMesh>& globalMeshes, Component::Collider& collider)
|
||||
void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialAsset>& materials, Array<PMesh>& globalMeshes, Component::Collider& collider)
|
||||
{
|
||||
for (uint32 meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex)
|
||||
{
|
||||
@@ -191,7 +190,7 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterial>&
|
||||
{
|
||||
if(mesh->HasTextureCoords(i))
|
||||
{
|
||||
data.textureCoordinates.add(createVertexStream(mesh->mNumVertices, mesh->mTextureCoords[i], graphics));
|
||||
data.textureCoordinates[i] = createVertexStream(mesh->mNumVertices, mesh->mTextureCoords[i], graphics);
|
||||
}
|
||||
}
|
||||
if(mesh->HasNormals())
|
||||
@@ -243,7 +242,7 @@ void MeshLoader::convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numP
|
||||
dst[i * 4 + 3] = src[i].a;
|
||||
}
|
||||
}
|
||||
void MeshLoader::loadTextures(const aiScene* scene, const std::filesystem::path& meshDirectory)
|
||||
void MeshLoader::loadTextures(const aiScene* scene, const std::filesystem::path& meshDirectory, const std::string& importPath)
|
||||
{
|
||||
for (uint32 i = 0; i < scene->mNumTextures; ++i)
|
||||
{
|
||||
@@ -269,7 +268,7 @@ void MeshLoader::loadTextures(const aiScene* scene, const std::filesystem::path&
|
||||
std::cout << "Loading model texture " << texPngPath.string() << std::endl;
|
||||
AssetRegistry::importTexture(TextureImportArgs {
|
||||
.filePath = texPath,
|
||||
.importPath = ""
|
||||
.importPath = importPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -288,9 +287,9 @@ void MeshLoader::import(MeshImportArgs args, PMeshAsset meshAsset)
|
||||
aiProcess_FindDegenerates));
|
||||
const aiScene *scene = importer.ApplyPostProcessing(aiProcess_CalcTangentSpace);
|
||||
|
||||
Array<PMaterial> globalMaterials(scene->mNumMaterials);
|
||||
loadTextures(scene, args.filePath.parent_path());
|
||||
loadMaterials(scene, globalMaterials);
|
||||
Array<PMaterialAsset> globalMaterials(scene->mNumMaterials);
|
||||
loadTextures(scene, args.filePath.parent_path(), args.importPath);
|
||||
loadMaterials(scene, args.filePath.stem().string(), args.filePath.parent_path(), args.importPath, globalMaterials);
|
||||
|
||||
Array<PMesh> globalMeshes(scene->mNumMeshes);
|
||||
Component::Collider collider;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Seele
|
||||
{
|
||||
DECLARE_REF(Mesh)
|
||||
DECLARE_REF(MeshAsset)
|
||||
DECLARE_REF(Material)
|
||||
DECLARE_REF(MaterialAsset)
|
||||
DECLARE_NAME_REF(Gfx, Graphics)
|
||||
struct MeshImportArgs
|
||||
{
|
||||
@@ -24,9 +24,9 @@ public:
|
||||
~MeshLoader();
|
||||
void importAsset(MeshImportArgs args);
|
||||
private:
|
||||
void loadMaterials(const aiScene* scene, Array<PMaterial>& globalMaterials);
|
||||
void loadTextures(const aiScene* scene, const std::filesystem::path& meshPath);
|
||||
void loadGlobalMeshes(const aiScene* scene, const Array<PMaterial>& materials, Array<PMesh>& globalMeshes, Component::Collider& collider);
|
||||
void loadMaterials(const aiScene* scene, const std::string& baseName, const std::filesystem::path& meshDirectory, const std::string& importPath, Array<PMaterialAsset>& globalMaterials);
|
||||
void loadTextures(const aiScene* scene, const std::filesystem::path& meshDirectory, const std::string& importPath);
|
||||
void loadGlobalMeshes(const aiScene* scene, const Array<PMaterialAsset>& materials, Array<PMesh>& globalMeshes, Component::Collider& collider);
|
||||
void convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numPixels);
|
||||
|
||||
void import(MeshImportArgs args, PMeshAsset meshAsset);
|
||||
|
||||
@@ -7,66 +7,115 @@
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
#define KTX_CHECK(x) { ktx_error_code_e err = x; assert(err == KTX_SUCCESS); }
|
||||
|
||||
TextureAsset::TextureAsset()
|
||||
{
|
||||
}
|
||||
TextureAsset::TextureAsset(const std::string& directory, const std::string& name)
|
||||
: Asset(directory, name)
|
||||
|
||||
TextureAsset::TextureAsset(std::string_view folderPath, std::string_view name)
|
||||
: Asset(folderPath, name)
|
||||
{
|
||||
}
|
||||
TextureAsset::TextureAsset(const std::filesystem::path& fullPath)
|
||||
: Asset(fullPath)
|
||||
{
|
||||
}
|
||||
|
||||
TextureAsset::~TextureAsset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TextureAsset::save(Gfx::PGraphics graphics)
|
||||
void TextureAsset::save(ArchiveBuffer& buffer) const
|
||||
{
|
||||
//TODO: make this an actual file, not just a png wrapper
|
||||
assert(false && "Editing textures is not yet supported");
|
||||
Array<uint8> textureData;
|
||||
ktxTexture2* kTexture;
|
||||
ktxTextureCreateInfo createInfo = {
|
||||
.vkFormat = (uint32_t)texture->getFormat(),
|
||||
.baseWidth = texture->getSizeX(),
|
||||
.baseHeight = texture->getSizeY(),
|
||||
.baseDepth = texture->getSizeZ(),
|
||||
.numDimensions = texture->getSizeZ() > 1 ? 3u : texture->getSizeY() > 1 ? 2u : 1u,
|
||||
.numLevels = texture->getMipLevels(),
|
||||
.numLayers = 1,
|
||||
.numFaces = texture->getNumFaces(),
|
||||
.isArray = false,
|
||||
.generateMipmaps = false,
|
||||
};
|
||||
KTX_CHECK(ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE, &kTexture));
|
||||
|
||||
for (uint32 depth = 0; depth < texture->getSizeZ(); ++depth)
|
||||
{
|
||||
for (uint32 face = 0; face < texture->getNumFaces(); ++face)
|
||||
{
|
||||
// technically, downloading cant be const, because we have to allocate temporary buffers and change layouts
|
||||
// but practically the texture stays the same
|
||||
const_cast<Gfx::Texture*>(texture.getHandle())->download(0, depth, face, textureData);
|
||||
KTX_CHECK(ktxTexture_SetImageFromMemory(ktxTexture(kTexture), 0, depth, face, textureData.data(), textureData.size()));
|
||||
}
|
||||
}
|
||||
char writer[100];
|
||||
snprintf(writer, sizeof(writer), "%s version %s", "SeeleEngine", "0.0.1");
|
||||
ktxHashList_AddKVPair(&kTexture->kvDataHead, KTX_WRITER_KEY,
|
||||
(ktx_uint32_t)strlen(writer) + 1,
|
||||
writer);
|
||||
|
||||
//ktx_error_code_e error = ktxTexture2_CompressBasis(kTexture, 0);
|
||||
|
||||
ktx_uint8_t* texData;
|
||||
ktx_size_t texSize;
|
||||
KTX_CHECK(ktxTexture_WriteToMemory(ktxTexture(kTexture), &texData, &texSize));
|
||||
|
||||
Array<uint8> rawData(texSize);
|
||||
std::memcpy(rawData.data(), texData, texSize);
|
||||
free(texData);
|
||||
|
||||
Serialization::save(buffer, rawData);
|
||||
}
|
||||
|
||||
void TextureAsset::load(Gfx::PGraphics graphics)
|
||||
void TextureAsset::load(ArchiveBuffer& buffer)
|
||||
{
|
||||
setStatus(Status::Loading);
|
||||
ktxTexture2* kTexture;
|
||||
// TODO: consider return
|
||||
std::cout << "Loading texture " << getFullPath() << std::endl;
|
||||
ktxTexture2_CreateFromNamedFile(getFullPath().c_str(),
|
||||
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
||||
&kTexture);
|
||||
|
||||
TextureCreateInfo createInfo;
|
||||
createInfo.width = kTexture->baseWidth;
|
||||
createInfo.height = kTexture->baseHeight;
|
||||
createInfo.depth = kTexture->baseDepth;
|
||||
createInfo.bArray = kTexture->isArray;
|
||||
createInfo.arrayLayers = kTexture->isArray ? kTexture->numLayers : kTexture->numFaces;
|
||||
createInfo.format = Vulkan::cast((VkFormat)kTexture->vkFormat);
|
||||
createInfo.mipLevels = kTexture->numLevels;
|
||||
createInfo.usage = Gfx::SE_IMAGE_USAGE_SAMPLED_BIT;
|
||||
createInfo.resourceData.data = ktxTexture_GetData(ktxTexture(kTexture));
|
||||
createInfo.resourceData.size = ktxTexture_GetDataSize(ktxTexture(kTexture));
|
||||
createInfo.resourceData.owner = Gfx::QueueType::DEDICATED_TRANSFER;
|
||||
Array<uint8> rawData;
|
||||
Serialization::load(buffer, rawData);
|
||||
|
||||
ktxTexture2* kTexture;
|
||||
std::cout << "Loading texture " << name << std::endl;
|
||||
KTX_CHECK(ktxTexture_CreateFromMemory(rawData.data(),
|
||||
rawData.size(),
|
||||
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
||||
(ktxTexture**) & kTexture));
|
||||
|
||||
//ktxTexture2_TranscodeBasis(kTexture, KTX_TTF_BC7_RGBA, 0);
|
||||
|
||||
TextureCreateInfo createInfo = {
|
||||
.resourceData = {
|
||||
.size = ktxTexture_GetDataSize(ktxTexture(kTexture)),
|
||||
.data = ktxTexture_GetData(ktxTexture(kTexture)),
|
||||
.owner = Gfx::QueueType::DEDICATED_TRANSFER,
|
||||
},
|
||||
.width = kTexture->baseWidth,
|
||||
.height = kTexture->baseHeight,
|
||||
.depth = kTexture->baseDepth,
|
||||
.bArray = kTexture->isArray,
|
||||
.arrayLayers = kTexture->isArray ? kTexture->numLayers : kTexture->numFaces,
|
||||
.mipLevels = kTexture->numLevels,
|
||||
.format = Vulkan::cast((VkFormat)kTexture->vkFormat),
|
||||
.usage = Gfx::SE_IMAGE_USAGE_SAMPLED_BIT,
|
||||
};
|
||||
Gfx::PTexture tex;
|
||||
if (kTexture->isCubemap)
|
||||
{
|
||||
tex = graphics->createTextureCube(createInfo);
|
||||
tex = buffer.getGraphics()->createTextureCube(createInfo);
|
||||
}
|
||||
else if (kTexture->isArray)
|
||||
{
|
||||
tex = graphics->createTexture3D(createInfo);
|
||||
tex = buffer.getGraphics()->createTexture3D(createInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
tex = graphics->createTexture2D(createInfo);
|
||||
tex = buffer.getGraphics()->createTexture2D(createInfo);
|
||||
}
|
||||
tex->transferOwnership(Gfx::QueueType::GRAPHICS);
|
||||
setTexture(tex);
|
||||
ktxTexture_Destroy(ktxTexture(kTexture));
|
||||
setStatus(Asset::Status::Ready);
|
||||
}
|
||||
@@ -7,20 +7,18 @@ DECLARE_NAME_REF(Gfx, Texture)
|
||||
class TextureAsset : public Asset
|
||||
{
|
||||
public:
|
||||
static constexpr uint64 IDENTIFIER = 0x1;
|
||||
TextureAsset();
|
||||
TextureAsset(const std::string& directory, const std::string& name);
|
||||
TextureAsset(const std::filesystem::path& fullPath);
|
||||
TextureAsset(std::string_view folderPath, std::string_view name);
|
||||
virtual ~TextureAsset();
|
||||
virtual void save(Gfx::PGraphics graphics) override;
|
||||
virtual void load(Gfx::PGraphics graphics) override;
|
||||
virtual void save(ArchiveBuffer& buffer) const override;
|
||||
virtual void load(ArchiveBuffer& buffer) override;
|
||||
void setTexture(Gfx::PTexture _texture)
|
||||
{
|
||||
std::scoped_lock lck(lock);
|
||||
texture = _texture;
|
||||
}
|
||||
Gfx::PTexture getTexture()
|
||||
{
|
||||
std::scoped_lock lck(lock);
|
||||
return texture;
|
||||
}
|
||||
private:
|
||||
|
||||
@@ -14,9 +14,15 @@ using namespace Seele;
|
||||
TextureLoader::TextureLoader(Gfx::PGraphics graphics)
|
||||
: graphics(graphics)
|
||||
{
|
||||
placeholderAsset = new TextureAsset(std::filesystem::absolute("./textures/placeholder.ktx"));
|
||||
placeholderAsset->load(graphics);
|
||||
AssetRegistry::get().assetRoot.textures[""] = placeholderAsset;
|
||||
//(std::filesystem::absolute("./textures/placeholder.ktx"));
|
||||
//placeholderAsset->load(graphics);
|
||||
//AssetRegistry::get().assetRoot.textures[""] = placeholderAsset;
|
||||
placeholderAsset = new TextureAsset();
|
||||
import(TextureImportArgs{
|
||||
.filePath = std::filesystem::absolute("./textures/placeholder.png"),
|
||||
.importPath = "",
|
||||
}, placeholderAsset);
|
||||
AssetRegistry::get().assetRoot->textures[""] = placeholderAsset;
|
||||
}
|
||||
|
||||
TextureLoader::~TextureLoader()
|
||||
@@ -27,10 +33,10 @@ void TextureLoader::importAsset(TextureImportArgs args)
|
||||
{
|
||||
std::filesystem::path assetPath = args.filePath.filename();
|
||||
assetPath.replace_extension("asset");
|
||||
PTextureAsset asset = new TextureAsset(assetPath.generic_string());
|
||||
PTextureAsset asset = new TextureAsset(args.importPath, assetPath.stem().string());
|
||||
asset->setStatus(Asset::Status::Loading);
|
||||
asset->setTexture(placeholderAsset->getTexture());
|
||||
AssetRegistry::get().registerTexture(asset, args.importPath);
|
||||
AssetRegistry::get().registerTexture(asset);
|
||||
import(args, asset);
|
||||
}
|
||||
|
||||
@@ -45,22 +51,22 @@ void TextureLoader::import(TextureImportArgs args, PTextureAsset textureAsset)
|
||||
unsigned char* data = stbi_load(args.filePath.string().c_str(), &totalWidth, &totalHeight, &n, 4);
|
||||
ktxTexture2* kTexture;
|
||||
ktxTextureCreateInfo createInfo;
|
||||
createInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
createInfo.baseDepth = 1;
|
||||
createInfo.numLevels = 1;
|
||||
createInfo.numLayers = 1;
|
||||
createInfo.isArray = false;
|
||||
createInfo.generateMipmaps = false;
|
||||
|
||||
if (args.type == TextureImportType::TEXTURE_CUBEMAP)
|
||||
{
|
||||
uint32 faceWidth = totalWidth / 4;
|
||||
uint32 faceHeight = totalHeight / 3;
|
||||
// Cube map
|
||||
createInfo.vkFormat = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
createInfo.baseWidth = totalWidth / 4;
|
||||
createInfo.baseHeight = totalHeight / 3;
|
||||
createInfo.baseDepth = 1;
|
||||
createInfo.numFaces = 6;
|
||||
createInfo.numDimensions = 2;
|
||||
createInfo.numLevels = 1;
|
||||
createInfo.numLayers = 1;
|
||||
createInfo.isArray = false;
|
||||
createInfo.generateMipmaps = true;
|
||||
|
||||
ktxTexture2_Create(&createInfo,
|
||||
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
||||
@@ -85,21 +91,15 @@ void TextureLoader::import(TextureImportArgs args, PTextureAsset textureAsset)
|
||||
loadCubeFace(0, 1, 1); // -X
|
||||
loadCubeFace(1, 0, 2); // +Y
|
||||
loadCubeFace(1, 2, 3); // -Y
|
||||
loadCubeFace(1, 1, 4); // -Z
|
||||
loadCubeFace(1, 1, 4); // +Z
|
||||
loadCubeFace(3, 1, 5); // -Z
|
||||
}
|
||||
else
|
||||
{
|
||||
createInfo.vkFormat = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
createInfo.baseWidth = totalWidth;
|
||||
createInfo.baseHeight = totalHeight;
|
||||
createInfo.baseDepth = 1;
|
||||
createInfo.numDimensions = 1 + (totalHeight > 1);
|
||||
createInfo.numLevels = 1;
|
||||
createInfo.numLayers = 1;
|
||||
createInfo.numFaces = 1;
|
||||
createInfo.isArray = false;
|
||||
createInfo.generateMipmaps = true;
|
||||
createInfo.numDimensions = 1 + (totalHeight > 1);
|
||||
|
||||
ktxTexture2_Create(&createInfo,
|
||||
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
||||
@@ -108,13 +108,47 @@ void TextureLoader::import(TextureImportArgs args, PTextureAsset textureAsset)
|
||||
ktxTexture_SetImageFromMemory(ktxTexture(kTexture),
|
||||
0, 0, 0, data, totalWidth * totalHeight * 4 * sizeof(unsigned char));
|
||||
}
|
||||
std::cout << "starting compression of " << textureAsset->getAssetIdentifier() << std::endl;
|
||||
ktxBasisParams params = {
|
||||
.structSize = sizeof(ktxBasisParams),
|
||||
.uastc = KTX_TRUE,
|
||||
.threadCount = std::thread::hardware_concurrency(),
|
||||
.qualityLevel = 0,
|
||||
};
|
||||
//ktx_error_code_e error = ktxTexture2_CompressBasisEx(kTexture, ¶ms);
|
||||
//assert(error == KTX_SUCCESS);
|
||||
|
||||
//error = ktxTexture2_TranscodeBasis(kTexture, KTX_TTF_BC7_RGBA, 0);
|
||||
//assert(error == KTX_SUCCESS);
|
||||
|
||||
stbi_image_free(data);
|
||||
|
||||
ktxTexture_WriteToNamedFile(ktxTexture(kTexture), textureAsset->getFullPath().c_str());
|
||||
ktxTexture_Destroy(ktxTexture(kTexture));
|
||||
TextureCreateInfo texInfo = {
|
||||
.resourceData = {
|
||||
.size = ktxTexture_GetDataSize(ktxTexture(kTexture)),
|
||||
.data = ktxTexture_GetData(ktxTexture(kTexture)),
|
||||
},
|
||||
.width = createInfo.baseWidth,
|
||||
.height = createInfo.baseHeight,
|
||||
.depth = createInfo.baseDepth,
|
||||
.bArray = false,
|
||||
.arrayLayers = createInfo.numFaces,
|
||||
.mipLevels = 1,
|
||||
.samples = 1,
|
||||
.format = (Gfx::SeFormat)kTexture->vkFormat,
|
||||
.usage = args.usage,
|
||||
};
|
||||
|
||||
textureAsset->load(graphics);
|
||||
if (createInfo.numFaces == 1)
|
||||
{
|
||||
textureAsset->setTexture(graphics->createTexture2D(texInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
textureAsset->setTexture(graphics->createTextureCube(texInfo));
|
||||
}
|
||||
|
||||
ktxTexture_Destroy(ktxTexture(kTexture));
|
||||
textureAsset->setStatus(Asset::Status::Ready);
|
||||
////co_return;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "MinimalEngine.h"
|
||||
#include "Containers/List.h"
|
||||
#include "Graphics/GraphicsEnums.h"
|
||||
#include <filesystem>
|
||||
|
||||
namespace Seele
|
||||
@@ -18,6 +19,7 @@ struct TextureImportArgs
|
||||
std::filesystem::path filePath;
|
||||
std::string importPath;
|
||||
TextureImportType type = TextureImportType::TEXTURE_2D;
|
||||
Gfx::SeImageUsageFlagBits usage = Gfx::SE_IMAGE_USAGE_SAMPLED_BIT;
|
||||
};
|
||||
class TextureLoader
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user