Allow building custom materials and images.

This commit is contained in:
momo5502 2016-01-22 16:11:47 +01:00
parent f509e67953
commit 9449750aab
11 changed files with 239 additions and 3 deletions

View File

@ -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 };

View File

@ -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;

View File

@ -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);

View File

@ -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;
};
}

View File

@ -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;

View File

@ -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;
};
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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));
}