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 header = { 0 };
|
||||
|
@ -10,7 +10,7 @@ namespace Components
|
||||
virtual void Mark(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 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*);
|
||||
@ -29,6 +29,7 @@ namespace Components
|
||||
static void ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder);
|
||||
|
||||
static Game::XAssetHeader FindOriginalAsset(Game::XAssetType type, const char* filename);
|
||||
static Game::XAssetHeader FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder);
|
||||
|
||||
private:
|
||||
static bool BypassState;
|
||||
|
@ -2,6 +2,33 @@
|
||||
|
||||
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)
|
||||
{
|
||||
Assert_AssetStruct(Game::GfxImage, 32);
|
||||
|
@ -5,5 +5,6 @@ namespace Assets
|
||||
virtual Game::XAssetType GetType() override { return Game::XAssetType::ASSET_TYPE_IMAGE; };
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
Game::Material* asset = header.material;
|
||||
|
@ -6,5 +6,6 @@ namespace Assets
|
||||
|
||||
virtual void Save(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;
|
||||
}
|
||||
|
||||
Utils::Memory::Allocator* ZoneBuilder::Zone::GetAllocator()
|
||||
{
|
||||
return &MemAllocator;
|
||||
}
|
||||
|
||||
void ZoneBuilder::Zone::Zone::Build()
|
||||
{
|
||||
ZoneBuilder::Zone::LoadFastFiles();
|
||||
@ -118,7 +123,7 @@ namespace Components
|
||||
return false;
|
||||
}
|
||||
|
||||
Game::XAssetHeader assetHeader = Game::DB_FindXAssetHeader(type, name.data());
|
||||
Game::XAssetHeader assetHeader = AssetHandler::FindAssetForZone(type, name, this);
|
||||
|
||||
if (!assetHeader.data)
|
||||
{
|
||||
|
@ -15,6 +15,7 @@ namespace Components
|
||||
void Build();
|
||||
|
||||
Utils::Stream* GetBuffer();
|
||||
Utils::Memory::Allocator* GetAllocator();
|
||||
|
||||
bool HasPointer(const void* pointer);
|
||||
void StorePointer(const void* pointer);
|
||||
@ -56,6 +57,8 @@ namespace Components
|
||||
std::string ZoneName;
|
||||
Utils::CSV DataMap;
|
||||
|
||||
Utils::Memory::Allocator MemAllocator;
|
||||
|
||||
std::vector<Game::XAsset> LoadedAssets;
|
||||
std::vector<std::string> ScriptStrings;
|
||||
std::map<unsigned short, unsigned int> ScriptStringMap;
|
||||
|
@ -62,6 +62,9 @@ namespace Game
|
||||
FS_Restart_t FS_Restart = (FS_Restart_t)0x461A50;
|
||||
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_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60;
|
||||
Menus_FindByName_t Menus_FindByName = (Menus_FindByName_t)0x487240;
|
||||
@ -280,4 +283,17 @@ namespace Game
|
||||
SetConsole("com_errorTitle", title.data());
|
||||
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**);
|
||||
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);
|
||||
extern Menus_CloseAll_t Menus_CloseAll;
|
||||
|
||||
@ -356,4 +363,6 @@ namespace Game
|
||||
XAssetType DB_GetXAssetNameType(const char* name);
|
||||
|
||||
void MessageBox(std::string message, std::string title);
|
||||
|
||||
unsigned int R_HashString(const char* string);
|
||||
}
|
||||
|
@ -3,8 +3,66 @@ namespace Utils
|
||||
class Memory
|
||||
{
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user