Allow building custom materials and images.
This commit is contained in:
parent
f509e67953
commit
9449750aab
@ -181,6 +181,23 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Game::XAssetHeader AssetHandler::FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder)
|
||||||
|
{
|
||||||
|
Game::XAssetHeader header = { 0 };
|
||||||
|
|
||||||
|
if (AssetHandler::AssetInterfaces.find(type) != AssetHandler::AssetInterfaces.end())
|
||||||
|
{
|
||||||
|
AssetHandler::AssetInterfaces[type]->Load(&header, filename, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!header.data)
|
||||||
|
{
|
||||||
|
header = Game::DB_FindXAssetHeader(type, filename.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
Game::XAssetHeader AssetHandler::FindOriginalAsset(Game::XAssetType type, const char* filename)
|
Game::XAssetHeader AssetHandler::FindOriginalAsset(Game::XAssetType type, const char* filename)
|
||||||
{
|
{
|
||||||
Game::XAssetHeader header = { 0 };
|
Game::XAssetHeader header = { 0 };
|
||||||
|
@ -10,7 +10,7 @@ namespace Components
|
|||||||
virtual void Mark(Game::XAssetHeader header, ZoneBuilder::Zone* builder) { /*ErrorTypeNotSupported(this);*/ };
|
virtual void Mark(Game::XAssetHeader header, ZoneBuilder::Zone* builder) { /*ErrorTypeNotSupported(this);*/ };
|
||||||
virtual void Save(Game::XAssetHeader header, ZoneBuilder::Zone* builder) { /*ErrorTypeNotSupported(this);*/ };
|
virtual void Save(Game::XAssetHeader header, ZoneBuilder::Zone* builder) { /*ErrorTypeNotSupported(this);*/ };
|
||||||
virtual void Dump(Game::XAssetHeader header) { /*ErrorTypeNotSupported(this);*/ };
|
virtual void Dump(Game::XAssetHeader header) { /*ErrorTypeNotSupported(this);*/ };
|
||||||
virtual void Load(Game::XAssetHeader* header, std::string name) { /*ErrorTypeNotSupported(this);*/ };
|
virtual void Load(Game::XAssetHeader* header, std::string name, ZoneBuilder::Zone* builder) { /*ErrorTypeNotSupported(this);*/ };
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Game::XAssetHeader(*Callback)(Game::XAssetType, const char*);
|
typedef Game::XAssetHeader(*Callback)(Game::XAssetType, const char*);
|
||||||
@ -29,6 +29,7 @@ namespace Components
|
|||||||
static void ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder);
|
static void ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder);
|
||||||
|
|
||||||
static Game::XAssetHeader FindOriginalAsset(Game::XAssetType type, const char* filename);
|
static Game::XAssetHeader FindOriginalAsset(Game::XAssetType type, const char* filename);
|
||||||
|
static Game::XAssetHeader FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool BypassState;
|
static bool BypassState;
|
||||||
|
@ -2,6 +2,33 @@
|
|||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
|
void IGfxImage::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
||||||
|
{
|
||||||
|
Game::GfxImage* image = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_IMAGE, name.data()).image;
|
||||||
|
if (image) return; // TODO: Check for default?
|
||||||
|
|
||||||
|
image = builder->GetAllocator()->AllocateArray<Game::GfxImage>();
|
||||||
|
if (!image)
|
||||||
|
{
|
||||||
|
Components::Logger::Error("Failed to allocate GfxImage structure!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
image->semantic = 0;
|
||||||
|
image->category = 3;
|
||||||
|
image->cardMemory = 0;
|
||||||
|
|
||||||
|
Game::Image_LoadFromFileWithReader(image, (Game::Reader_t)0x46CBF0);
|
||||||
|
|
||||||
|
// Free our image when done building zone
|
||||||
|
builder->GetAllocator()->Reference(image, [] (void*data)
|
||||||
|
{
|
||||||
|
Game::Image_Release((Game::GfxImage*)data);
|
||||||
|
});
|
||||||
|
|
||||||
|
header->image = image;
|
||||||
|
}
|
||||||
|
|
||||||
void IGfxImage::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IGfxImage::Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Assert_AssetStruct(Game::GfxImage, 32);
|
Assert_AssetStruct(Game::GfxImage, 32);
|
||||||
|
@ -5,5 +5,6 @@ namespace Assets
|
|||||||
virtual Game::XAssetType GetType() override { return Game::XAssetType::ASSET_TYPE_IMAGE; };
|
virtual Game::XAssetType GetType() override { return Game::XAssetType::ASSET_TYPE_IMAGE; };
|
||||||
|
|
||||||
virtual void Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
virtual void Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||||
|
virtual void Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -2,6 +2,104 @@
|
|||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
|
void IMaterial::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
|
||||||
|
{
|
||||||
|
Components::FileSystem::File materialInfo(Utils::VA("materials/%s.json", name.data()));
|
||||||
|
|
||||||
|
if (!materialInfo.Exists()) return;
|
||||||
|
|
||||||
|
std::string errors;
|
||||||
|
json11::Json infoData = json11::Json::parse(materialInfo.GetBuffer(), errors);
|
||||||
|
|
||||||
|
if (!infoData.is_object())
|
||||||
|
{
|
||||||
|
Components::Logger::Error("Failed to load material information for %s!", name.data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto base = infoData["base"];
|
||||||
|
|
||||||
|
if (!base.is_string())
|
||||||
|
{
|
||||||
|
Components::Logger::Error("No valid material base provided for %s!", name.data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::Material* baseMaterial = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, base.string_value().data()).material;
|
||||||
|
|
||||||
|
if (!baseMaterial) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!?
|
||||||
|
{
|
||||||
|
Components::Logger::Error("Basematerial '%s' not found for %s!", base.string_value().data(), name.data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::Material* material = builder->GetAllocator()->AllocateArray<Game::Material>();
|
||||||
|
|
||||||
|
if (!material)
|
||||||
|
{
|
||||||
|
Components::Logger::Error("Failed to allocate material structure!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy base material to our structure
|
||||||
|
memcpy(material, baseMaterial, sizeof(Game::Material));
|
||||||
|
material->name = builder->GetAllocator()->DuplicateString(name);
|
||||||
|
|
||||||
|
// Load referenced textures
|
||||||
|
auto textures = infoData["textures"];
|
||||||
|
if (textures.is_array())
|
||||||
|
{
|
||||||
|
std::vector<Game::MaterialTextureDef> textureList;
|
||||||
|
|
||||||
|
for (auto texture : textures.array_items())
|
||||||
|
{
|
||||||
|
if (!texture.is_array()) continue;
|
||||||
|
if (textureList.size() >= 0xFF) break;
|
||||||
|
|
||||||
|
auto textureInfo = texture.array_items();
|
||||||
|
if (textureInfo.size() < 2) continue;
|
||||||
|
|
||||||
|
auto map = textureInfo[0];
|
||||||
|
auto image = textureInfo[1];
|
||||||
|
if(!map.is_string() || !image.is_string()) continue;
|
||||||
|
|
||||||
|
Game::MaterialTextureDef textureDef;
|
||||||
|
|
||||||
|
textureDef.semantic = 0; // No water image
|
||||||
|
textureDef.nameEnd = map.string_value().data()[map.string_value().size() - 1];
|
||||||
|
textureDef.nameStart = map.string_value().data()[0];
|
||||||
|
textureDef.nameHash = Game::R_HashString(map.string_value().data());
|
||||||
|
|
||||||
|
textureDef.info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, image.string_value(), builder).image;
|
||||||
|
|
||||||
|
textureList.push_back(textureDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textureList.size())
|
||||||
|
{
|
||||||
|
Game::MaterialTextureDef* textureTable = builder->GetAllocator()->AllocateArray<Game::MaterialTextureDef>(textureList.size());
|
||||||
|
|
||||||
|
if (!textureTable)
|
||||||
|
{
|
||||||
|
Components::Logger::Error("Failed to allocate texture table!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(textureTable, textureList.data(), sizeof(Game::MaterialTextureDef) * textureList.size());
|
||||||
|
|
||||||
|
material->textureTable = textureTable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
material->textureTable = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
material->textureCount = (char)textureList.size() & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
header->material = material;
|
||||||
|
}
|
||||||
|
|
||||||
void IMaterial::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IMaterial::Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Game::Material* asset = header.material;
|
Game::Material* asset = header.material;
|
||||||
|
@ -6,5 +6,6 @@ namespace Assets
|
|||||||
|
|
||||||
virtual void Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
virtual void Save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||||
virtual void Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
virtual void Mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||||
|
virtual void Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -27,6 +27,11 @@ namespace Components
|
|||||||
return &Buffer;
|
return &Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::Memory::Allocator* ZoneBuilder::Zone::GetAllocator()
|
||||||
|
{
|
||||||
|
return &MemAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
void ZoneBuilder::Zone::Zone::Build()
|
void ZoneBuilder::Zone::Zone::Build()
|
||||||
{
|
{
|
||||||
ZoneBuilder::Zone::LoadFastFiles();
|
ZoneBuilder::Zone::LoadFastFiles();
|
||||||
@ -118,7 +123,7 @@ namespace Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::XAssetHeader assetHeader = Game::DB_FindXAssetHeader(type, name.data());
|
Game::XAssetHeader assetHeader = AssetHandler::FindAssetForZone(type, name, this);
|
||||||
|
|
||||||
if (!assetHeader.data)
|
if (!assetHeader.data)
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,7 @@ namespace Components
|
|||||||
void Build();
|
void Build();
|
||||||
|
|
||||||
Utils::Stream* GetBuffer();
|
Utils::Stream* GetBuffer();
|
||||||
|
Utils::Memory::Allocator* GetAllocator();
|
||||||
|
|
||||||
bool HasPointer(const void* pointer);
|
bool HasPointer(const void* pointer);
|
||||||
void StorePointer(const void* pointer);
|
void StorePointer(const void* pointer);
|
||||||
@ -56,6 +57,8 @@ namespace Components
|
|||||||
std::string ZoneName;
|
std::string ZoneName;
|
||||||
Utils::CSV DataMap;
|
Utils::CSV DataMap;
|
||||||
|
|
||||||
|
Utils::Memory::Allocator MemAllocator;
|
||||||
|
|
||||||
std::vector<Game::XAsset> LoadedAssets;
|
std::vector<Game::XAsset> LoadedAssets;
|
||||||
std::vector<std::string> ScriptStrings;
|
std::vector<std::string> ScriptStrings;
|
||||||
std::map<unsigned short, unsigned int> ScriptStringMap;
|
std::map<unsigned short, unsigned int> ScriptStringMap;
|
||||||
|
@ -62,6 +62,9 @@ namespace Game
|
|||||||
FS_Restart_t FS_Restart = (FS_Restart_t)0x461A50;
|
FS_Restart_t FS_Restart = (FS_Restart_t)0x461A50;
|
||||||
FS_BuildPathToFile_t FS_BuildPathToFile = (FS_BuildPathToFile_t)0x4702C0;
|
FS_BuildPathToFile_t FS_BuildPathToFile = (FS_BuildPathToFile_t)0x4702C0;
|
||||||
|
|
||||||
|
Image_LoadFromFileWithReader_t Image_LoadFromFileWithReader = (Image_LoadFromFileWithReader_t)0x53ABF0;
|
||||||
|
Image_Release_t Image_Release = (Image_Release_t)0x51F010;
|
||||||
|
|
||||||
Menus_CloseAll_t Menus_CloseAll = (Menus_CloseAll_t)0x4BA5B0;
|
Menus_CloseAll_t Menus_CloseAll = (Menus_CloseAll_t)0x4BA5B0;
|
||||||
Menus_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60;
|
Menus_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60;
|
||||||
Menus_FindByName_t Menus_FindByName = (Menus_FindByName_t)0x487240;
|
Menus_FindByName_t Menus_FindByName = (Menus_FindByName_t)0x487240;
|
||||||
@ -280,4 +283,17 @@ namespace Game
|
|||||||
SetConsole("com_errorTitle", title.data());
|
SetConsole("com_errorTitle", title.data());
|
||||||
Cbuf_AddText(0, "openmenu error_popmenu_lobby");
|
Cbuf_AddText(0, "openmenu error_popmenu_lobby");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int R_HashString(const char* string)
|
||||||
|
{
|
||||||
|
unsigned int hash = 0;
|
||||||
|
|
||||||
|
while (*string)
|
||||||
|
{
|
||||||
|
hash = (*string | 0x20) ^ (33 * hash);
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,13 @@ namespace Game
|
|||||||
typedef int(__cdecl * FS_BuildPathToFile_t)(const char*, const char*, const char*, char**);
|
typedef int(__cdecl * FS_BuildPathToFile_t)(const char*, const char*, const char*, char**);
|
||||||
extern FS_BuildPathToFile_t FS_BuildPathToFile;
|
extern FS_BuildPathToFile_t FS_BuildPathToFile;
|
||||||
|
|
||||||
|
typedef int(__cdecl * Reader_t)(char const*, int *);
|
||||||
|
typedef bool(__cdecl * Image_LoadFromFileWithReader_t)(GfxImage* image, Reader_t reader);
|
||||||
|
extern Image_LoadFromFileWithReader_t Image_LoadFromFileWithReader;
|
||||||
|
|
||||||
|
typedef void(__cdecl * Image_Release_t)(GfxImage* image);
|
||||||
|
extern Image_Release_t Image_Release;
|
||||||
|
|
||||||
typedef void(__cdecl * Menus_CloseAll_t)(UiContext *dc);
|
typedef void(__cdecl * Menus_CloseAll_t)(UiContext *dc);
|
||||||
extern Menus_CloseAll_t Menus_CloseAll;
|
extern Menus_CloseAll_t Menus_CloseAll;
|
||||||
|
|
||||||
@ -356,4 +363,6 @@ namespace Game
|
|||||||
XAssetType DB_GetXAssetNameType(const char* name);
|
XAssetType DB_GetXAssetNameType(const char* name);
|
||||||
|
|
||||||
void MessageBox(std::string message, std::string title);
|
void MessageBox(std::string message, std::string title);
|
||||||
|
|
||||||
|
unsigned int R_HashString(const char* string);
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,66 @@ namespace Utils
|
|||||||
class Memory
|
class Memory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
class Allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef void(*FreeCallback)(void*);
|
||||||
|
|
||||||
|
Allocator()
|
||||||
|
{
|
||||||
|
this->Pool.clear();
|
||||||
|
this->RefMemory.clear();
|
||||||
|
}
|
||||||
|
~Allocator()
|
||||||
|
{
|
||||||
|
for (auto i = this->RefMemory.begin(); i != this->RefMemory.end(); i++)
|
||||||
|
{
|
||||||
|
if (i->first && i->second)
|
||||||
|
{
|
||||||
|
i->second(i->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->RefMemory.clear();
|
||||||
|
|
||||||
|
for (auto data : this->Pool)
|
||||||
|
{
|
||||||
|
Memory::Free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->Pool.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reference(void* memory, FreeCallback callback)
|
||||||
|
{
|
||||||
|
this->RefMemory[memory] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Allocate(size_t length)
|
||||||
|
{
|
||||||
|
void* data = Memory::Allocate(length);
|
||||||
|
this->Pool.push_back(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
template <typename T> T* AllocateArray(size_t count = 1)
|
||||||
|
{
|
||||||
|
return (T*)this->Allocate(count * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
char* DuplicateString(std::string string)
|
||||||
|
{
|
||||||
|
char* data = Memory::DuplicateString(string);
|
||||||
|
this->Pool.push_back(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<void*> Pool;
|
||||||
|
std::map<void*, FreeCallback> RefMemory;
|
||||||
|
};
|
||||||
|
|
||||||
static void* Allocate(size_t length);
|
static void* Allocate(size_t length);
|
||||||
template <typename T> static T* AllocateArray(size_t count)
|
template <typename T> static T* AllocateArray(size_t count = 1)
|
||||||
{
|
{
|
||||||
return (T*)Allocate(count * sizeof(T));
|
return (T*)Allocate(count * sizeof(T));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user