[IMaterial] Refactor binary material format
This commit is contained in:
parent
b3eb28f4ad
commit
d47cc138d5
@ -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();
|
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->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();
|
|
||||||
|
|
||||||
|
Game::Material* asset = reader.readObject<Game::Material>();
|
||||||
|
|
||||||
|
if (asset->name)
|
||||||
|
{
|
||||||
|
asset->name = reader.readCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->techniqueSet)
|
||||||
|
{
|
||||||
std::string techset = reader.readString();
|
std::string techset = reader.readString();
|
||||||
material->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techset.data(), builder).techniqueSet;
|
asset->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techset.data(), builder).techniqueSet;
|
||||||
|
|
||||||
if (!material->techniqueSet)
|
const char* techsetSuffix[] =
|
||||||
|
{
|
||||||
|
"_lin",
|
||||||
|
"_add_lin",
|
||||||
|
"_replace",
|
||||||
|
"_eyeoffset",
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int i = 0; i < ARRAYSIZE(techsetSuffix) && !asset->techniqueSet; ++i)
|
||||||
|
{
|
||||||
|
asset->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, (techset + techsetSuffix[i]).data(), builder).techniqueSet;
|
||||||
|
|
||||||
|
if(asset->techniqueSet)
|
||||||
|
{
|
||||||
|
Components::Logger::Print("Techset '%s' has been mapped to '%s'\n", techset.data(), asset->techniqueSet->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!asset->techniqueSet)
|
||||||
{
|
{
|
||||||
Components::Logger::Error("Techset '%s' not found!", techset.data());
|
Components::Logger::Error("Techset '%s' not found!", techset.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
material->textureTable = builder->getAllocator()->allocateArray<Game::MaterialTextureDef>(material->textureCount & 0xFF);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
Components::Logger::Print("Error allocating memory for material structure!\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char i = 0; i < material->textureCount; ++i)
|
if (asset->textureTable)
|
||||||
{
|
{
|
||||||
std::string mapName = reader.readString();
|
asset->textureTable = reader.readArray<Game::MaterialTextureDef>(asset->textureCount);
|
||||||
material->textureTable[i].nameStart = mapName.front();
|
|
||||||
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)
|
for (char i = 0; i < asset->textureCount; ++i)
|
||||||
{
|
{
|
||||||
material->textureTable[i].info.water = builder->getAllocator()->allocate<Game::water_t>();
|
Game::MaterialTextureDef* textureDef = &asset->textureTable[i];
|
||||||
material->textureTable[i].info.water->writable.floatTime = reader.read<float>();
|
|
||||||
material->textureTable[i].info.water->M = reader.read<int>();
|
if (textureDef->semantic == SEMANTIC_WATER_MAP)
|
||||||
material->textureTable[i].info.water->N = reader.read<int>();
|
{
|
||||||
int count = material->textureTable[i].info.water->M * material->textureTable[i].info.water->N;
|
if (textureDef->info.water)
|
||||||
material->textureTable[i].info.water->H0 = reader.readArray<Game::complex_s>(count);
|
{
|
||||||
material->textureTable[i].info.water->wTerm = reader.readArray<float>(count);
|
Game::water_t* water = reader.readObject<Game::water_t>();
|
||||||
material->textureTable[i].info.water->Lx = reader.read<float>();
|
textureDef->info.water = water;
|
||||||
material->textureTable[i].info.water->Lz = reader.read<float>();
|
|
||||||
material->textureTable[i].info.water->gravity = reader.read<float>();
|
// Save_water_t
|
||||||
material->textureTable[i].info.water->windvel = reader.read<float>();
|
if (water->H0)
|
||||||
material->textureTable[i].info.water->winddir[0] = reader.read<float>();
|
{
|
||||||
material->textureTable[i].info.water->winddir[1] = reader.read<float>();
|
water->H0 = reader.readArray<Game::complex_s>(water->M * water->N);
|
||||||
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 (water->wTerm)
|
||||||
{
|
{
|
||||||
material->textureTable[i].info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char i = 0; i < material->constantCount; ++i)
|
if (asset->constantTable)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < 12; ++j)
|
asset->constantTable = reader.readArray<Game::MaterialConstantDef>(asset->constantCount);
|
||||||
{
|
|
||||||
material->constantTable[i].name[j] = reader.readByte();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string constName(material->constantTable[i].name, 12);
|
if (asset->stateBitTable)
|
||||||
constName.push_back('0');
|
{
|
||||||
|
asset->stateBitTable = reader.readArray<Game::GfxStateBits>(asset->stateBitsCount);
|
||||||
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);
|
header->material = asset;
|
||||||
header->material = material;
|
|
||||||
|
|
||||||
// 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*/)
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user