[IMaterial] Refactor binary material format

This commit is contained in:
momo5502 2017-03-18 15:19:31 +01:00
parent b3eb28f4ad
commit d47cc138d5
2 changed files with 86 additions and 81 deletions

View File

@ -1,6 +1,6 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
#define IW4X_MAT_VERSION "0" #define IW4X_MAT_VERSION "1"
namespace Assets namespace Assets
{ {
@ -16,111 +16,107 @@ namespace Assets
Components::FileSystem::File materialFile(Utils::String::VA("materials/%s.iw4xMaterial", name.data())); Components::FileSystem::File materialFile(Utils::String::VA("materials/%s.iw4xMaterial", name.data()));
if (!materialFile.exists()) return; if (!materialFile.exists()) return;
Game::Material* material = builder->getAllocator()->allocate<Game::Material>();
if (!material)
{
Components::Logger::Print("Error allocating memory for material structure!\n");
return;
}
Utils::Stream::Reader reader(builder->getAllocator(), materialFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), materialFile.getBuffer());
__int64 magic = reader.read<__int64>(); char* magic = reader.readArray<char>(7);
if (std::memcmp(&magic, "IW4xMat" IW4X_MAT_VERSION, 8)) if (std::memcmp(magic, "IW4xMat", 7))
{ {
Components::Logger::Error(0, "Reading material '%s' failed, header is invalid!", name.data()); Components::Logger::Error(0, "Reading material '%s' failed, header is invalid!", name.data());
} }
material->name = reader.readCString(); std::string version;
material->gameFlags = reader.readByte(); version.push_back(reader.read<char>());
material->sortKey = reader.readByte(); if (version != IW4X_MAT_VERSION)
material->textureAtlasRowCount = reader.readByte();
material->textureAtlasColumnCount = reader.readByte();
material->drawSurf.packed = reader.read<__int64>();
material->surfaceTypeBits = reader.read<int>();
material->hashIndex = reader.read<unsigned __int16>();
char* stateBitsEntry = reader.readArray<char>(48);
std::memcpy(material->stateBitsEntry, stateBitsEntry, 48);
material->textureCount = reader.readByte();
material->constantCount = reader.readByte();
material->stateBitsCount = reader.readByte();
material->stateFlags = reader.readByte();
material->cameraRegion = reader.readByte();
std::string techset = reader.readString();
material->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techset.data(), builder).techniqueSet;
if (!material->techniqueSet)
{ {
Components::Logger::Error("Techset '%s' not found!", techset.data()); Components::Logger::Error("Reading material '%s' failed, expected version is %d, but it was %d!", name.data(), atoi(IW4X_MAT_VERSION), atoi(version.data()));
} }
material->textureTable = builder->getAllocator()->allocateArray<Game::MaterialTextureDef>(material->textureCount & 0xFF); Game::Material* asset = reader.readObject<Game::Material>();
material->constantTable = builder->getAllocator()->allocateArray<Game::MaterialConstantDef>(material->constantCount & 0xFF);
material->stateBitTable = builder->getAllocator()->allocateArray<Game::GfxStateBits>(material->stateBitsCount & 0xFF);
if (!material->textureTable || !material->constantTable || !material->stateBitTable) if (asset->name)
{ {
Components::Logger::Print("Error allocating memory for material structure!\n"); asset->name = reader.readCString();
return;
} }
for (char i = 0; i < material->textureCount; ++i) if (asset->techniqueSet)
{ {
std::string mapName = reader.readString(); std::string techset = reader.readString();
material->textureTable[i].nameStart = mapName.front(); asset->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techset.data(), builder).techniqueSet;
material->textureTable[i].nameEnd = mapName.back();
material->textureTable[i].nameHash = Game::R_HashString(mapName.data());
material->textureTable[i].sampleState = reader.readByte();
material->textureTable[i].semantic = reader.readByte();
if (material->textureTable[i].semantic == SEMANTIC_WATER_MAP) const char* techsetSuffix[] =
{ {
material->textureTable[i].info.water = builder->getAllocator()->allocate<Game::water_t>(); "_lin",
material->textureTable[i].info.water->writable.floatTime = reader.read<float>(); "_add_lin",
material->textureTable[i].info.water->M = reader.read<int>(); "_replace",
material->textureTable[i].info.water->N = reader.read<int>(); "_eyeoffset",
int count = material->textureTable[i].info.water->M * material->textureTable[i].info.water->N; };
material->textureTable[i].info.water->H0 = reader.readArray<Game::complex_s>(count);
material->textureTable[i].info.water->wTerm = reader.readArray<float>(count); for(int i = 0; i < ARRAYSIZE(techsetSuffix) && !asset->techniqueSet; ++i)
material->textureTable[i].info.water->Lx = reader.read<float>(); {
material->textureTable[i].info.water->Lz = reader.read<float>(); asset->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, (techset + techsetSuffix[i]).data(), builder).techniqueSet;
material->textureTable[i].info.water->gravity = reader.read<float>();
material->textureTable[i].info.water->windvel = reader.read<float>(); if(asset->techniqueSet)
material->textureTable[i].info.water->winddir[0] = reader.read<float>(); {
material->textureTable[i].info.water->winddir[1] = reader.read<float>(); Components::Logger::Print("Techset '%s' has been mapped to '%s'\n", techset.data(), asset->techniqueSet->name);
material->textureTable[i].info.water->amplitude = reader.read<float>(); }
material->textureTable[i].info.water->codeConstant[0] = reader.read<float>();
material->textureTable[i].info.water->codeConstant[1] = reader.read<float>();
material->textureTable[i].info.water->codeConstant[2] = reader.read<float>();
material->textureTable[i].info.water->codeConstant[3] = reader.read<float>();
material->textureTable[i].info.water->image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image;
} }
else
if (!asset->techniqueSet)
{ {
material->textureTable[i].info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image; Components::Logger::Error("Techset '%s' not found!", techset.data());
} }
} }
for (char i = 0; i < material->constantCount; ++i) if (asset->textureTable)
{ {
for (int j = 0; j < 12; ++j) asset->textureTable = reader.readArray<Game::MaterialTextureDef>(asset->textureCount);
for (char i = 0; i < asset->textureCount; ++i)
{ {
material->constantTable[i].name[j] = reader.readByte(); Game::MaterialTextureDef* textureDef = &asset->textureTable[i];
if (textureDef->semantic == SEMANTIC_WATER_MAP)
{
if (textureDef->info.water)
{
Game::water_t* water = reader.readObject<Game::water_t>();
textureDef->info.water = water;
// Save_water_t
if (water->H0)
{
water->H0 = reader.readArray<Game::complex_s>(water->M * water->N);
}
if (water->wTerm)
{
water->wTerm = reader.readArray<float>(water->M * water->N);
}
if (water->image)
{
water->image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image;
}
}
}
else if (textureDef->info.image)
{
textureDef->info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image;
}
} }
std::string constName(material->constantTable[i].name, 12);
constName.push_back('0');
material->constantTable[i].nameHash = Game::R_HashString(constName.data());
material->constantTable[i].literal[0] = reader.read<float>();
material->constantTable[i].literal[1] = reader.read<float>();
material->constantTable[i].literal[2] = reader.read<float>();
material->constantTable[i].literal[3] = reader.read<float>();
} }
material->stateBitTable = reader.readArray<Game::GfxStateBits>(material->stateBitsCount); if (asset->constantTable)
header->material = material; {
asset->constantTable = reader.readArray<Game::MaterialConstantDef>(asset->constantCount);
}
if (asset->stateBitTable)
{
asset->stateBitTable = reader.readArray<Game::GfxStateBits>(asset->stateBitsCount);
}
header->material = asset;
// Find correct sortkey by comparing techsets // Find correct sortkey by comparing techsets
Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_MATERIAL, [](Game::XAssetHeader header, void* data) Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_MATERIAL, [](Game::XAssetHeader header, void* data)
@ -140,7 +136,12 @@ namespace Assets
material->constantCount = header.material->constantCount; material->constantCount = header.material->constantCount;
material->constantTable = header.material->constantTable; material->constantTable = header.material->constantTable;
} }
}, material, false); }, asset, false);
if (!reader.end())
{
Components::Logger::Error("Material data left!");
}
} }
void IMaterial::loadNative(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* /*builder*/) void IMaterial::loadNative(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* /*builder*/)

View File

@ -53,6 +53,10 @@ namespace Components
void Logger::ErrorPrint(int error, std::string message) void Logger::ErrorPrint(int error, std::string message)
{ {
#ifdef DEBUG
if (IsDebuggerPresent()) __debugbreak();
#endif
return Game::Com_Error(error, "%s", message.data()); return Game::Com_Error(error, "%s", message.data());
} }