From f91fa0d0b22417eccf0bd06ef66ae600cbc3ee3d Mon Sep 17 00:00:00 2001 From: Louve <33836535+Rackover@users.noreply.github.com> Date: Wed, 14 Dec 2022 09:40:15 +0100 Subject: [PATCH] Big zonebuilder update (#427) --- src/Components/Modules/AssetHandler.cpp | 2 +- .../Modules/AssetInterfaces/IFxEffectDef.cpp | 18 +- .../Modules/AssetInterfaces/IFxWorld.cpp | 13 +- .../Modules/AssetInterfaces/IGameWorldMp.cpp | 116 ++ .../Modules/AssetInterfaces/IGameWorldMp.hpp | 1 + .../Modules/AssetInterfaces/IGameWorldSp.cpp | 2 +- .../Modules/AssetInterfaces/IGfxImage.cpp | 4 +- .../Modules/AssetInterfaces/IGfxWorld.cpp | 27 +- .../Modules/AssetInterfaces/ILoadedSound.cpp | 13 +- .../Modules/AssetInterfaces/IMaterial.cpp | 580 ++++++-- .../Modules/AssetInterfaces/IMaterial.hpp | 3 + .../AssetInterfaces/IMaterialPixelShader.cpp | 39 +- .../AssetInterfaces/IMaterialTechniqueSet.cpp | 208 ++- .../AssetInterfaces/IMaterialTechniqueSet.hpp | 4 +- .../IMaterialVertexDeclaration.cpp | 11 +- .../AssetInterfaces/IMaterialVertexShader.cpp | 40 +- .../Modules/AssetInterfaces/IWeapon.cpp | 10 +- .../Modules/AssetInterfaces/IXAnimParts.cpp | 4 +- .../Modules/AssetInterfaces/IXModel.cpp | 178 +-- .../Modules/AssetInterfaces/IXModelSurfs.cpp | 77 +- src/Components/Modules/Maps.cpp | 94 +- src/Components/Modules/Menus.cpp | 15 - src/Components/Modules/Menus.hpp | 2 - src/Components/Modules/Renderer.cpp | 72 +- src/Components/Modules/Renderer.hpp | 4 + src/Components/Modules/ZoneBuilder.cpp | 104 +- src/Components/Modules/ZoneBuilder.hpp | 3 +- src/Components/Modules/Zones.cpp | 4 +- src/Game/Functions.cpp | 1 + src/Game/Functions.hpp | 1 + src/Game/Structs.hpp | 1230 ++++++++++++++++- src/Utils/Compression.cpp | 19 +- src/Utils/Entities.cpp | 4 +- src/Utils/Json.cpp | 29 + src/Utils/Json.hpp | 2 + src/Utils/Stream.hpp | 34 + 36 files changed, 2395 insertions(+), 573 deletions(-) diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index d450d50b..94220280 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -257,7 +257,7 @@ namespace Components for (int k = 0; k < (pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount); ++k) { - if (pass->args[k].type == D3DSHADER_PARAM_REGISTER_TYPE::D3DSPR_CONSTINT) + if (pass->args[k].type == Game::MaterialShaderArgumentType::MTL_ARG_LITERAL_PIXEL_CONST) { if (pass->args[k].u.codeConst.index == -28132) { diff --git a/src/Components/Modules/AssetInterfaces/IFxEffectDef.cpp b/src/Components/Modules/AssetInterfaces/IFxEffectDef.cpp index 37e2c8db..994a6349 100644 --- a/src/Components/Modules/AssetInterfaces/IFxEffectDef.cpp +++ b/src/Components/Modules/AssetInterfaces/IFxEffectDef.cpp @@ -391,7 +391,7 @@ namespace Assets switch (elemType) { - case 7: + case Game::FX_ELEM_TYPE_MODEL: { if (visuals->model) { @@ -401,11 +401,11 @@ namespace Assets break; } - case 8: - case 9: + case Game::FX_ELEM_TYPE_OMNI_LIGHT: + case Game::FX_ELEM_TYPE_SPOT_LIGHT: break; - case 0xA: + case Game::FX_ELEM_TYPE_SOUND: { if (visuals->soundName) { @@ -416,7 +416,7 @@ namespace Assets break; } - case 0xC: + case Game::FX_ELEM_TYPE_RUNNER: { if (visuals->effectDef.handle) { @@ -491,7 +491,7 @@ namespace Assets // Save_FxElemDefVisuals { - if (elemDef->elemType == 11) + if (elemDef->elemType == Game::FX_ELEM_TYPE_DECAL) { if (elemDef->visuals.markArray) { @@ -501,7 +501,7 @@ namespace Assets Game::FxElemMarkVisuals* destMarkArray = buffer->dest(); buffer->saveArray(elemDef->visuals.markArray, elemDef->visualCount); - for (char j = 0; j < elemDef->visualCount; ++j) + for (auto j = 0; j < elemDef->visualCount; ++j) { if (elemDef->visuals.markArray[j].materials[0]) { @@ -563,7 +563,7 @@ namespace Assets { AssertSize(Game::FxElemExtendedDefPtr, 4); - if (elemDef->elemType == 3) + if (elemDef->elemType == Game::FX_ELEM_TYPE_TRAIL) { // Save_FxTrailDef { @@ -597,7 +597,7 @@ namespace Assets } } } - else if (elemDef->elemType == 6) + else if (elemDef->elemType == Game::FX_ELEM_TYPE_SPARK_FOUNTAIN) { if (elemDef->extended.sparkFountainDef) { diff --git a/src/Components/Modules/AssetInterfaces/IFxWorld.cpp b/src/Components/Modules/AssetInterfaces/IFxWorld.cpp index cec5b4dc..6988543f 100644 --- a/src/Components/Modules/AssetInterfaces/IFxWorld.cpp +++ b/src/Components/Modules/AssetInterfaces/IFxWorld.cpp @@ -186,11 +186,20 @@ namespace Assets } } - void IFxWorld::load(Game::XAssetHeader* /*header*/, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) + void IFxWorld::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { Game::FxWorld* map = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FXWORLD, name.data()).fxWorld; if (map) return; - Components::Logger::Error(Game::ERR_FATAL, "Missing fx_map {}... you can't make them yet you idiot.", name); + // Generate + map = builder->getAllocator()->allocate(); + map->name = builder->getAllocator()->duplicateString(name); + + // No glass for you! + ZeroMemory(&map->glassSys, sizeof(map->glassSys)); + + map->glassSys.firstFreePiece = 0xFFFF; // That's how rust has it (no glass) + + header->fxWorld = map; } } diff --git a/src/Components/Modules/AssetInterfaces/IGameWorldMp.cpp b/src/Components/Modules/AssetInterfaces/IGameWorldMp.cpp index 64c53039..1656d480 100644 --- a/src/Components/Modules/AssetInterfaces/IGameWorldMp.cpp +++ b/src/Components/Modules/AssetInterfaces/IGameWorldMp.cpp @@ -1,6 +1,8 @@ #include #include "IGameWorldMp.hpp" +#define IW4X_GAMEWORLD_VERSION 1 + namespace Assets { void IGameWorldMp::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) @@ -75,4 +77,118 @@ namespace Assets buffer->popBlock(); } + + void IGameWorldMp::load(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder) + { + std::string name = _name; + Utils::String::Replace(name, "maps/mp/", ""); + Utils::String::Replace(name, ".d3dbsp", ""); + + Components::FileSystem::File gameWorld(std::format("gameworld/{}.iw4x.json", name)); + + if (gameWorld.exists()) + { + nlohmann::json gameWorldJson; + + try + { + + gameWorldJson = nlohmann::json::parse(gameWorld.getBuffer()); + } + catch (const std::exception& e) + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid JSON for gameworld {}! {}", name, e.what()); + return; + } + + auto* asset = builder->getAllocator()->allocate(); + + if (!gameWorldJson.is_object()) + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid GameWorldMp json for {}\n", name); + return; + } + + auto version = gameWorldJson["version"].is_number() ? gameWorldJson["version"].get() : 0; + if (version != IW4X_GAMEWORLD_VERSION) + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid GameWorld json version for {}, expected {} and got {}\n", name, IW4X_GAMEWORLD_VERSION, version); + return; + } + + if (!gameWorldJson["name"].is_string()) + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Missing gameworld name! on {}\n", name); + return; + } + + asset->name = builder->getAllocator()->duplicateString(gameWorldJson["name"].get()); + auto glassData = builder->getAllocator()->allocate(); + + if (gameWorldJson["glassData"].is_object()) + { + auto jsonGlassData = gameWorldJson["glassData"]; + + try + { + glassData->damageToDestroy = jsonGlassData["damageToDestroy"].get(); + glassData->damageToWeaken = jsonGlassData["damageToWeaken"].get(); + + if (jsonGlassData["glassNames"].is_array()) + { + nlohmann::json::array_t glassNames = jsonGlassData["glassNames"]; + glassData->glassNameCount = glassNames.size(); + glassData->glassNames = builder->getAllocator()->allocateArray(glassData->glassNameCount); + + for (size_t i = 0; i < glassData->glassNameCount; i++) + { + auto jsonGlassName = glassNames[i]; + glassData->glassNames[i].nameStr = builder->getAllocator()->duplicateString(jsonGlassName["nameStr"]); + + glassData->glassNames[i].name = jsonGlassName["name"].get(); + + if (jsonGlassName["piecesIndices"].is_array()) + { + nlohmann::json::array_t jsonPiecesIndices = jsonGlassName["piecesIndices"]; + glassData->glassNames[i].pieceCount = static_cast(jsonPiecesIndices.size()); + + for (size_t j = 0; j < glassData->glassNames[i].pieceCount; j++) + { + glassData->glassNames[i].pieceIndices[j] = jsonPiecesIndices[j].get(); + } + } + } + } + + if (gameWorldJson["glassPieces"].is_array()) + { + nlohmann::json::array_t glassPieces = gameWorldJson["glassPieces"]; + glassData->pieceCount = glassPieces.size(); + glassData->glassPieces = builder->getAllocator()->allocateArray(glassData->pieceCount); + + for (size_t i = 0; i < glassData->pieceCount; i++) + { + glassData->glassPieces[i].collapseTime = glassPieces[i]["collapseTime"].get(); + glassData->glassPieces[i].damageTaken = glassPieces[i]["damageTaken"].get(); + glassData->glassPieces[i].lastStateChangeTime = glassPieces[i]["lastStateChangeTime"].get(); + glassData->glassPieces[i].impactDir = glassPieces[i]["impactDir"].get(); + + nlohmann::json::array_t jsonPos = glassPieces[i]["impactPos"]; + glassData->glassPieces[i].impactPos[0] = jsonPos[0].get(); + glassData->glassPieces[i].impactPos[1] = jsonPos[1].get(); + } + } + } + catch (const nlohmann::json::exception& e) + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Malformed GameWorldMp json for {} ({})\n", name, e.what()); + return; + } + } + + asset->g_glassData = glassData; + + header->gameWorldMp = asset; + } + } } diff --git a/src/Components/Modules/AssetInterfaces/IGameWorldMp.hpp b/src/Components/Modules/AssetInterfaces/IGameWorldMp.hpp index 243378ef..f19b8d58 100644 --- a/src/Components/Modules/AssetInterfaces/IGameWorldMp.hpp +++ b/src/Components/Modules/AssetInterfaces/IGameWorldMp.hpp @@ -8,5 +8,6 @@ namespace Assets Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP; } void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; }; } diff --git a/src/Components/Modules/AssetInterfaces/IGameWorldSp.cpp b/src/Components/Modules/AssetInterfaces/IGameWorldSp.cpp index 64904c86..0b06b0c2 100644 --- a/src/Components/Modules/AssetInterfaces/IGameWorldSp.cpp +++ b/src/Components/Modules/AssetInterfaces/IGameWorldSp.cpp @@ -187,7 +187,7 @@ namespace Assets for (char j = 0; j < 5; ++j) { - builder->mapScriptString(&(&node->constant.targetname)[j]); + builder->mapScriptString((&node->constant.targetname)[j]); } if (node->constant.Links) diff --git a/src/Components/Modules/AssetInterfaces/IGfxImage.cpp b/src/Components/Modules/AssetInterfaces/IGfxImage.cpp index 823876eb..3c7bfee4 100644 --- a/src/Components/Modules/AssetInterfaces/IGfxImage.cpp +++ b/src/Components/Modules/AssetInterfaces/IGfxImage.cpp @@ -18,7 +18,7 @@ namespace Assets } image->name = builder->getAllocator()->duplicateString(name); - image->semantic = 2; + image->semantic = Game::TextureSemantic::TS_COLOR_MAP; const char* tempName = image->name; if (tempName[0] == '*') tempName++; @@ -35,7 +35,7 @@ namespace Assets } image->mapType = reader.read(); - image->semantic = reader.read(); + image->semantic = reader.read(); image->category = reader.read(); int dataLength = reader.read(); diff --git a/src/Components/Modules/AssetInterfaces/IGfxWorld.cpp b/src/Components/Modules/AssetInterfaces/IGfxWorld.cpp index 3a84a800..8548c309 100644 --- a/src/Components/Modules/AssetInterfaces/IGfxWorld.cpp +++ b/src/Components/Modules/AssetInterfaces/IGfxWorld.cpp @@ -3,6 +3,27 @@ #define IW4X_GFXMAP_VERSION 1 +// The xmodel vehicle_small_hatch_green_destructible_mp causes EXTREME lag +// when placed in the world, for reasons unknown. +// +// Something happens with the SModelSurfIterator which makes it load garbage +// as an XSurface in the middle of otherwise valid surfaces. This bug is very +// easy to reproduce with an empty map and just this car in the middle +// +// As of know we do not know why the iterator corruption occurs or what causes +// it. It doesn't seem linked to the SModel, nor to the materials or techsets, +// nor to the sortkeys, nor to the tilemode, boneinfo, and so on. So for now +// and to make it work for majority of users, we just swap the car. (no, using +// the identical car from iw4's favela_escape doesn't work either!) +// +// Two other models have this problem: ch_apartment_9story_noentry_02 and +// ch_apartment_5story_noentry_01 +// But these exist in mp_vacant in slightly different versions, and can be +// swapped safely by deleting the two .iw4XModel files and requiring mp_vacant +// or a minimal zone containing just these two models. +// +#define SWAP_GREEN_VEHICLE_XMODEL 1 + namespace Assets { void IGfxWorld::loadGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader) @@ -47,7 +68,11 @@ namespace Assets if (model->model) { - model->model = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_XMODEL, reader->readString().data(), builder).model; + auto name = reader->readString(); + + model->model = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_XMODEL, name.data(), builder).model; + + assert(model->model); } } } diff --git a/src/Components/Modules/AssetInterfaces/ILoadedSound.cpp b/src/Components/Modules/AssetInterfaces/ILoadedSound.cpp index 45b291a4..d651e99a 100644 --- a/src/Components/Modules/AssetInterfaces/ILoadedSound.cpp +++ b/src/Components/Modules/AssetInterfaces/ILoadedSound.cpp @@ -120,17 +120,8 @@ namespace Assets if (asset->sound.data) { - if (builder->hasPointer(asset->sound.data)) - { - dest->sound.data = builder->getPointer(asset->sound.data); - } - else - { - builder->storePointer(asset->sound.data); - - buffer->saveArray(asset->sound.data, asset->sound.info.data_len); - Utils::Stream::ClearPointer(&dest->sound.data); - } + buffer->saveArray(asset->sound.data, asset->sound.info.data_len); + Utils::Stream::ClearPointer(&dest->sound.data); } buffer->popBlock(); diff --git a/src/Components/Modules/AssetInterfaces/IMaterial.cpp b/src/Components/Modules/AssetInterfaces/IMaterial.cpp index e6635b0e..42b63a8e 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterial.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterial.cpp @@ -1,15 +1,439 @@ #include #include "IMaterial.hpp" -#define IW4X_MAT_VERSION "1" +#define IW4X_MAT_BIN_VERSION "1" +#define IW4X_MAT_JSON_VERSION 1 namespace Assets { + const std::unordered_map techSetCorrespondance = + { + {"effect", "effect_blend"}, + {"effect", "effect_blend"}, + {"effect_nofog", "effect_blend_nofog"}, + {"effect_zfeather", "effect_zfeather_blend"}, + {"effect_zfeather_falloff", "effect_zfeather_falloff_add"}, + {"effect_zfeather_nofog", "effect_zfeather_add_nofog"}, + + {"wc_unlit_add", "wc_unlit_add_lin"}, + {"wc_unlit_distfalloff", "wc_unlit_distfalloff_replace"}, + {"wc_unlit_multiply", "wc_unlit_multiply_lin"}, + {"wc_unlit_falloff_add", "wc_unlit_falloff_add_lin"}, + {"wc_unlit", "wc_unlit_replace_lin"}, + {"wc_unlit_alphatest", "wc_unlit_blend_lin"}, + {"wc_unlit_blend", "wc_unlit_blend_lin"}, + {"wc_unlit_replace", "wc_unlit_replace_lin"}, + {"wc_unlit_nofog", "wc_unlit_replace_lin_nofog_nocast" }, + + {"mc_unlit_replace", "mc_unlit_replace_lin"}, + {"mc_unlit_nofog", "mc_unlit_blend_nofog_ua"}, + {"mc_unlit", "mc_unlit_replace_lin_nocast"}, + {"mc_unlit_alphatest", "mc_unlit_blend_lin"}, + {"mc_effect_nofog", "mc_effect_blend_nofog"}, + {"mc_effect_falloff_add_nofog", "mc_effect_falloff_add_nofog_eyeoffset"}, + }; + void IMaterial::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - if (!header->data) this->loadJson(header, name, builder); // Check if we want to override materials + if (!header->data) this->loadJson(header, name, builder); // Check if we want to load a material from disk + if (!header->data) this->loadBinary(header, name, builder); // Check if we want to load a material from disk (binary format) if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one - if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game + } + + + void IMaterial::loadJson(Game::XAssetHeader* header, const std::string& name, [[maybe_unused]] Components::ZoneBuilder::Zone* builder) + { + Components::FileSystem::File materialInfo(std::format("materials/{}.iw4x.json", name)); + + if (!materialInfo.exists()) return; + + Game::Material* asset = builder->getAllocator()->allocate(); + + + nlohmann::json materialJson; + try + { + materialJson = nlohmann::json::parse(materialInfo.getBuffer()); + } + catch (const std::exception& e) + { + Components::Logger::Print("Invalid material json for {} (broken json {})\n", name, e.what()); + } + + if (!materialJson.is_object()) + { + Components::Logger::Print("Invalid material json for {} (Is it zonebuilder format?)\n", name); + return; + } + + if (materialJson["version"].get() != IW4X_MAT_JSON_VERSION) + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid material json version for {}, expected {} and got {}\n", name, IW4X_MAT_JSON_VERSION, materialJson["version"].get()); + return; + } + + try + { + asset->info.name = builder->getAllocator()->duplicateString(materialJson["name"].get()); + asset->info.gameFlags = static_cast(Utils::Json::ReadFlags(materialJson["gameFlags"].get(), sizeof(char))); + + asset->info.sortKey = materialJson["sortKey"].get(); + // * We do techset later * // + asset->info.textureAtlasRowCount = materialJson["textureAtlasRowCount"].get(); + asset->info.textureAtlasColumnCount = materialJson["textureAtlasColumnCount"].get(); + asset->info.surfaceTypeBits = static_cast(Utils::Json::ReadFlags(materialJson["surfaceTypeBits"].get(), sizeof(int))); + asset->info.hashIndex = materialJson["hashIndex"].get(); + asset->cameraRegion = materialJson["cameraRegion"].get(); + } + catch (const nlohmann::json::exception& e) + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid material json for {} (broken json {})\n", name, e.what()); + return; + } + + if (materialJson["gfxDrawSurface"].is_object()) + { + asset->info.drawSurf.fields.customIndex = materialJson["gfxDrawSurface"]["customIndex"].get(); + asset->info.drawSurf.fields.hasGfxEntIndex = materialJson["gfxDrawSurface"]["hasGfxEntIndex"].get(); + asset->info.drawSurf.fields.materialSortedIndex = materialJson["gfxDrawSurface"]["materialSortedIndex"].get(); + asset->info.drawSurf.fields.objectId = materialJson["gfxDrawSurface"]["objectId"].get(); + asset->info.drawSurf.fields.prepass = materialJson["gfxDrawSurface"]["prepass"].get(); + asset->info.drawSurf.fields.primarySortKey = materialJson["gfxDrawSurface"]["primarySortKey"].get(); + asset->info.drawSurf.fields.reflectionProbeIndex = materialJson["gfxDrawSurface"]["reflectionProbeIndex"].get(); + asset->info.drawSurf.fields.sceneLightIndex = materialJson["gfxDrawSurface"]["sceneLightIndex"].get(); + asset->info.drawSurf.fields.surfType = materialJson["gfxDrawSurface"]["surfType"].get(); + asset->info.drawSurf.fields.unused = materialJson["gfxDrawSurface"]["unused"].get(); + asset->info.drawSurf.fields.useHeroLighting = materialJson["gfxDrawSurface"]["useHeroLighting"].get(); + } + + asset->stateFlags = static_cast(Utils::Json::ReadFlags(materialJson["stateFlags"].get(), sizeof(char))); + + if (materialJson["textureTable"].is_array()) + { + nlohmann::json::array_t textureTable = materialJson["textureTable"]; + asset->textureCount = static_cast(textureTable.size()); + asset->textureTable = builder->getAllocator()->allocateArray(asset->textureCount); + + for (size_t i = 0; i < textureTable.size(); i++) + { + auto& textureJson = textureTable[i]; + if (textureJson.is_object()) + { + Game::MaterialTextureDef* textureDef = &asset->textureTable[i]; + textureDef->semantic = textureJson["semantic"].get(); + textureDef->samplerState = textureJson["samplerState"].get(); + textureDef->nameStart = textureJson["nameStart"].get(); + textureDef->nameEnd = textureJson["nameEnd"].get(); + textureDef->nameHash = textureJson["nameHash"].get(); + + if (textureDef->semantic == Game::TextureSemantic::TS_WATER_MAP) + { + Game::water_t* water = builder->getAllocator()->allocate(); + + if (textureJson["water"].is_object()) + { + auto& waterJson = textureJson["water"]; + + if (waterJson["image"].is_string()) + { + auto imageName = waterJson["image"].get(); + + water->image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, imageName.data(), builder).image; + } + + water->amplitude = waterJson["amplitude"].get(); + water->M = waterJson["M"].get(); + water->N = waterJson["N"].get(); + water->Lx = waterJson["Lx"].get(); + water->Lz = waterJson["Lz"].get(); + water->gravity = waterJson["gravity"].get(); + water->windvel = waterJson["windvel"].get(); + + auto winddir = waterJson["winddir"].get>(); + if (winddir.size() == 2) + { + std::copy(winddir.begin(), winddir.end(), water->winddir); + } + + auto codeConstant = waterJson["codeConstant"].get>(); + + if (codeConstant.size() == 4) + { + std::copy(codeConstant.begin(), codeConstant.end(), water->codeConstant); + } + + /// H0 + [[maybe_unused]] auto idealSize = water->M * water->N * sizeof(Game::complex_s); + auto h064 = waterJson["H0"].get(); + auto predictedSize = static_cast(std::ceilf((h064.size() / 4.f) * 3.f)); + assert(predictedSize >= idealSize); + + auto h0 = reinterpret_cast(builder->getAllocator()->allocate(predictedSize)); + + [[maybe_unused]] auto h0Result = base64_decode( + h064.data(), + h064.size(), + reinterpret_cast(h0), + &predictedSize + ); + + assert(h0Result == CRYPT_OK); + water->H0 = h0; + + /// WTerm + auto wTerm64 = waterJson["wTerm"].get(); + auto predictedWTermSize = static_cast(std::ceilf((wTerm64.size() / 4.f) * 3.f)); + + auto wTerm = reinterpret_cast(builder->getAllocator()->allocate(predictedWTermSize)); + + [[maybe_unused]] auto wTermResult = base64_decode( + wTerm64.data(), + wTerm64.size(), + reinterpret_cast(wTerm), + &predictedWTermSize + ); + + assert(wTermResult == CRYPT_OK); + water->wTerm = wTerm; + } + + textureDef->u.water = water; + } + else + { + textureDef->u.image = nullptr; + if (textureJson["image"].is_string()) + { + textureDef->u.image = Components::AssetHandler::FindAssetForZone + ( + Game::XAssetType::ASSET_TYPE_IMAGE, + textureJson["image"].get(), + builder + ).image; + } + } + } + } + } + + // Statebits + if (materialJson["stateBitsEntry"].is_array()) + { + nlohmann::json::array_t stateBitsEntry = materialJson["stateBitsEntry"]; + + for (size_t i = 0; i < std::min(stateBitsEntry.size(), 48u); i++) + { + asset->stateBitsEntry[i] = stateBitsEntry[i].get(); + } + } + + if (materialJson["stateBitsTable"].is_array()) + { + nlohmann::json::array_t array = materialJson["stateBitsTable"]; + asset->stateBitsCount = static_cast(array.size()); + + asset->stateBitsTable = builder->getAllocator()->allocateArray(array.size()); + + size_t statebitTableIndex = 0; + for (auto& jsonStateBitEntry : array) + { + auto stateBit = &asset->stateBitsTable[statebitTableIndex++]; + + unsigned int loadbits0 = 0; + unsigned int loadbits1 = 0; + +#define READ_INT_LB_FROM_JSON(x) unsigned int x = jsonStateBitEntry[#x].get() +#define READ_BOOL_LB_FROM_JSON(x) bool x = jsonStateBitEntry[#x].get() + + READ_INT_LB_FROM_JSON(srcBlendRgb); + READ_INT_LB_FROM_JSON(dstBlendRgb); + READ_INT_LB_FROM_JSON(blendOpRgb); + READ_INT_LB_FROM_JSON(srcBlendAlpha); + READ_INT_LB_FROM_JSON(dstBlendAlpha); + READ_INT_LB_FROM_JSON(blendOpAlpha); + READ_INT_LB_FROM_JSON(depthTest); + READ_INT_LB_FROM_JSON(polygonOffset); + + const auto alphaTest = jsonStateBitEntry["alphaTest"].get(); + const auto cullFace = jsonStateBitEntry["cullFace"].get(); + + READ_BOOL_LB_FROM_JSON(colorWriteRgb); + READ_BOOL_LB_FROM_JSON(colorWriteAlpha); + READ_BOOL_LB_FROM_JSON(polymodeLine); + + READ_BOOL_LB_FROM_JSON(gammaWrite); + READ_BOOL_LB_FROM_JSON(depthWrite); + READ_BOOL_LB_FROM_JSON(stencilFrontEnabled); + READ_BOOL_LB_FROM_JSON(stencilBackEnabled); + + READ_INT_LB_FROM_JSON(stencilFrontPass); + READ_INT_LB_FROM_JSON(stencilFrontFail); + READ_INT_LB_FROM_JSON(stencilFrontZFail); + READ_INT_LB_FROM_JSON(stencilFrontFunc); + READ_INT_LB_FROM_JSON(stencilBackPass); + READ_INT_LB_FROM_JSON(stencilBackFail); + READ_INT_LB_FROM_JSON(stencilBackZFail); + READ_INT_LB_FROM_JSON(stencilBackFunc); + + loadbits0 |= srcBlendRgb << Game::GFXS0_SRCBLEND_RGB_SHIFT; + loadbits0 |= dstBlendRgb << Game::GFXS0_DSTBLEND_RGB_SHIFT; + loadbits0 |= blendOpRgb << Game::GFXS0_BLENDOP_RGB_SHIFT; + loadbits0 |= srcBlendAlpha << Game::GFXS0_SRCBLEND_ALPHA_SHIFT; + loadbits0 |= dstBlendAlpha << Game::GFXS0_DSTBLEND_ALPHA_SHIFT; + loadbits0 |= blendOpAlpha << Game::GFXS0_BLENDOP_ALPHA_SHIFT; + + if (depthTest == -1) + { + loadbits1 |= Game::GFXS1_DEPTHTEST_DISABLE; + } + else + { + loadbits1 |= depthTest << Game::GFXS1_DEPTHTEST_SHIFT; + } + + loadbits1 |= polygonOffset << Game::GFXS1_POLYGON_OFFSET_SHIFT; + + if (alphaTest == "disable") + { + loadbits0 |= Game::GFXS0_ATEST_DISABLE; + } + else if (alphaTest == ">0") + { + loadbits0 |= Game::GFXS0_ATEST_GT_0; + } + else if (alphaTest == "<128") + { + loadbits0 |= Game::GFXS0_ATEST_LT_128; + } + else if (alphaTest == ">=128") + { + loadbits0 |= Game::GFXS0_ATEST_GE_128; + } + else + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid alphatest loadbit0 '{}' in material {}\n", alphaTest, name); + return; + } + + if (cullFace == "none") + { + loadbits0 |= Game::GFXS0_CULL_NONE; + } + else if (cullFace == "back") + { + loadbits0 |= Game::GFXS0_CULL_BACK; + } + else if (cullFace == "front") + { + loadbits0 |= Game::GFXS0_CULL_FRONT; + } + else + { + Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid cullFace loadbit0 '{}' in material {}\n", cullFace, name); + return; + } + + if (gammaWrite) + { + loadbits0 |= Game::GFXS0_GAMMAWRITE; + } + + if (colorWriteAlpha) + { + loadbits0 |= Game::GFXS0_COLORWRITE_ALPHA; + } + + if (colorWriteRgb) + { + loadbits0 |= Game::GFXS0_COLORWRITE_RGB; + } + + if (polymodeLine) + { + loadbits0 |= Game::GFXS0_POLYMODE_LINE; + } + + if (depthWrite) + { + loadbits1 |= Game::GFXS1_DEPTHWRITE; + } + if (stencilFrontEnabled) + { + loadbits1 |= Game::GFXS1_STENCIL_FRONT_ENABLE; + } + if (stencilBackEnabled) + { + loadbits1 |= Game::GFXS1_STENCIL_BACK_ENABLE; + } + + loadbits1 |= stencilFrontPass << Game::GFXS1_STENCIL_FRONT_PASS_SHIFT; + loadbits1 |= stencilFrontFail << Game::GFXS1_STENCIL_FRONT_FAIL_SHIFT; + loadbits1 |= stencilFrontZFail << Game::GFXS1_STENCIL_FRONT_ZFAIL_SHIFT; + loadbits1 |= stencilFrontFunc << Game::GFXS1_STENCIL_FRONT_FUNC_SHIFT; + loadbits1 |= stencilBackPass << Game::GFXS1_STENCIL_BACK_PASS_SHIFT; + loadbits1 |= stencilBackFail << Game::GFXS1_STENCIL_BACK_FAIL_SHIFT; + loadbits1 |= stencilBackZFail << Game::GFXS1_STENCIL_BACK_ZFAIL_SHIFT; + loadbits1 |= stencilBackFunc << Game::GFXS1_STENCIL_BACK_FUNC_SHIFT; + + stateBit->loadBits[0] = loadbits0; + stateBit->loadBits[1] = loadbits1; + } + + // Constant table + if (materialJson["constantTable"].is_array()) + { + + nlohmann::json::array_t constants = materialJson["constantTable"]; + asset->constantCount = static_cast(constants.size()); + auto table = builder->getAllocator()->allocateArray(asset->constantCount); + + for (size_t constantIndex = 0; constantIndex < asset->constantCount; constantIndex++) + { + auto& constant = constants[constantIndex]; + auto entry = &table[constantIndex]; + + auto litVec = constant["literal"].get>(); + std::copy(litVec.begin(), litVec.end(), entry->literal); + + auto constantName = constant["name"].get(); + std::copy(constantName.begin(), constantName.end(), entry->name); + + entry->nameHash = constant["nameHash"].get(); + } + + asset->constantTable = table; + } + + if (materialJson["techniqueSet"].is_string()) + { + const std::string techsetName = materialJson["techniqueSet"].get(); + asset->techniqueSet = findWorkingTechset(techsetName, asset, builder); + + if (asset->techniqueSet == nullptr) + { + assert(false); + } + } + + header->material = asset; + } + } + + Game::MaterialTechniqueSet* IMaterial::findWorkingTechset(std::string techsetName, [[maybe_unused]] Game::Material* material, Components::ZoneBuilder::Zone* builder) const + { + Game::MaterialTechniqueSet* techset; + + // Pass 1: Identical techset (1:1) + techset = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techsetName.data(), builder).techniqueSet; + if (techset != nullptr) + { + return techset; + } + + // We do no more cause we use CoD4 techset and they should always be present + // If one day we want to go back to mw2 fallback we can add extra steps here! + + return nullptr; } void IMaterial::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) @@ -30,29 +454,6 @@ namespace Assets "_add_lin_nofog", }; - static std::unordered_map techSetCorrespondance = - { - {"effect", "effect_blend"}, - {"effect", "effect_blend"}, - {"effect_nofog", "effect_blend_nofog"}, - {"effect_zfeather", "effect_zfeather_blend"}, - - {"wc_unlit_add", "wc_unlit_add_lin"}, - {"wc_unlit_distfalloff", "wc_unlit_distfalloff_replace"}, - {"wc_unlit_multiply", "wc_unlit_multiply_lin"}, - {"wc_unlit_falloff_add", "wc_unlit_falloff_add_lin_ua"}, - {"wc_unlit", "wc_unlit_replace_lin"}, - {"wc_unlit_alphatest", "wc_unlit_blend_lin"}, - {"wc_unlit_blend", "wc_unlit_blend_lin_ua"}, - {"wc_unlit_replace", "wc_unlit_replace_lin"}, - {"wc_unlit_nofog", "wc_unlit_replace_lin_nofog_nocast" }, - - {"mc_unlit_replace", "mc_unlit_replace_lin"}, - {"mc_unlit_nofog", "mc_unlit_blend_nofog_ua"}, - {"mc_unlit", "mc_unlit_replace_lin_nocast"}, - {"mc_unlit_alphatest", "mc_unlit_blend_lin"} - }; - Components::FileSystem::File materialFile(std::format("materials/{}.iw4xMaterial", name)); if (!materialFile.exists()) return; @@ -66,9 +467,9 @@ namespace Assets std::string version; version.push_back(reader.read()); - if (version != IW4X_MAT_VERSION) + if (version != IW4X_MAT_BIN_VERSION) { - Components::Logger::Error(Game::ERR_FATAL, "Reading material '{}' failed, expected version is {}, but it was {}!", name, IW4X_MAT_VERSION, version); + Components::Logger::Error(Game::ERR_FATAL, "Reading material '{}' failed, expected version is {}, but it was {}!", name, IW4X_MAT_BIN_VERSION, version); } auto* asset = reader.readObject(); @@ -127,7 +528,7 @@ namespace Assets { Game::MaterialTextureDef* textureDef = &asset->textureTable[i]; - if (textureDef->semantic == SEMANTIC_WATER_MAP) + if (textureDef->semantic == Game::TextureSemantic::TS_WATER_MAP) { if (textureDef->u.water) { @@ -175,29 +576,29 @@ namespace Assets // Find correct sortkey by comparing techsets Game::DB_EnumXAssetEntries(Game::XAssetType::ASSET_TYPE_MATERIAL, [asset](Game::XAssetEntry* entry) - { - if (!replacementFound) { - Game::XAssetHeader header = entry->asset.header; - - const char* name = asset->techniqueSet->name; - if (name[0] == ',') ++name; - - if (std::string(name) == header.material->techniqueSet->name) + if (!replacementFound) { - asset->info.sortKey = header.material->info.sortKey; + Game::XAssetHeader header = entry->asset.header; - // This is temp, as nobody has time to fix materials - asset->stateBitsCount = header.material->stateBitsCount; - asset->stateBitsTable = header.material->stateBitsTable; - std::memcpy(asset->stateBitsEntry, header.material->stateBitsEntry, 48); - asset->constantCount = header.material->constantCount; - asset->constantTable = header.material->constantTable; - Components::Logger::Print("For {}, copied constants & statebits from {}\n", asset->info.name, header.material->info.name); - replacementFound = true; + const char* name = asset->techniqueSet->name; + if (name[0] == ',') ++name; + + if (std::string(name) == header.material->techniqueSet->name) + { + asset->info.sortKey = header.material->info.sortKey; + + // This is temp, as nobody has time to fix materials + asset->stateBitsCount = header.material->stateBitsCount; + asset->stateBitsTable = header.material->stateBitsTable; + std::memcpy(asset->stateBitsEntry, header.material->stateBitsEntry, ARRAYSIZE(asset->stateBitsEntry)); + asset->constantCount = header.material->constantCount; + asset->constantTable = header.material->constantTable; + Components::Logger::Print("For {}, copied constants & statebits from {}\n", asset->info.name, header.material->info.name); + replacementFound = true; + } } - } - }, false); + }, false); if (!replacementFound) { @@ -222,70 +623,72 @@ namespace Assets Game::DB_EnumXAssetEntries(Game::XAssetType::ASSET_TYPE_MATERIAL, [asset, techsetMatches](Game::XAssetEntry* entry) - { - if (!replacementFound) { - Game::XAssetHeader header = entry->asset.header; - - if (techsetMatches(header.material, asset)) + if (!replacementFound) { - Components::Logger::Print("Material {} with techset {} has been mapped to {}\n", asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name); - asset->info.sortKey = header.material->info.sortKey; - replacementFound = true; + Game::XAssetHeader header = entry->asset.header; + + if (techsetMatches(header.material, asset)) + { + Components::Logger::Print("Material {} with techset {} has been mapped to {}\n", asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name); + asset->info.sortKey = header.material->info.sortKey; + replacementFound = true; + } } - } - }, false); + }, false); } if (!replacementFound && asset->techniqueSet) { Components::Logger::Print("No replacement found for material {} with techset {}\n", asset->info.name, asset->techniqueSet->name); std::string techName = asset->techniqueSet->name; - if (techSetCorrespondance.contains(techName)) + if (const auto itr = techSetCorrespondance.find(techName); itr != techSetCorrespondance.end()) { - auto iw4TechSetName = techSetCorrespondance[techName]; - Game::XAssetEntry* iw4TechSet = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, iw4TechSetName.data()); + auto& iw4TechSetName = itr->second; + auto* iw4TechSet = Game::DB_FindXAssetEntry(Game::ASSET_TYPE_TECHNIQUE_SET, iw4TechSetName.data()); - if (iw4TechSet) + if (iw4TechSet) { Game::DB_EnumXAssetEntries(Game::XAssetType::ASSET_TYPE_MATERIAL, [asset, iw4TechSet](Game::XAssetEntry* entry) - { - if (!replacementFound) { - Game::XAssetHeader header = entry->asset.header; - - if (header.material->techniqueSet == iw4TechSet->asset.header.techniqueSet - && std::string(header.material->info.name).find("icon") == std::string::npos) // Yeah this has a tendency to fuck up a LOT of transparent materials + if (!replacementFound) { + Game::XAssetHeader header = entry->asset.header; Components::Logger::Print("Material {} with techset {} has been mapped to {} (last chance!), taking the sort key of material {}\n", asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name, header.material->info.name); - asset->info.sortKey = header.material->info.sortKey; - asset->techniqueSet = iw4TechSet->asset.header.techniqueSet; + // Yeah this has a tendency to fuck up a LOT of transparent materials + if (header.material->techniqueSet == iw4TechSet->asset.header.techniqueSet && std::string(header.material->info.name).find("icon") != std::string::npos) + { + Components::Logger::Print("Material {} with techset {} has been mapped to {} (last chance!), taking the sort key of material {}\n", + asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name, header.material->info.name); - // this is terrible! - asset->stateBitsCount = header.material->stateBitsCount; - asset->stateBitsTable = header.material->stateBitsTable; - std::memcpy(asset->stateBitsEntry, header.material->stateBitsEntry, 48); - asset->constantCount = header.material->constantCount; - asset->constantTable = header.material->constantTable; + asset->info.sortKey = header.material->info.sortKey; + asset->techniqueSet = iw4TechSet->asset.header.techniqueSet; - replacementFound = true; + // this is terrible! + asset->stateBitsCount = header.material->stateBitsCount; + asset->stateBitsTable = header.material->stateBitsTable; + std::memcpy(asset->stateBitsEntry, header.material->stateBitsEntry, 48); + asset->constantCount = header.material->constantCount; + asset->constantTable = header.material->constantTable; + + replacementFound = true; + } } - } - }, false); + }, false); - if (!replacementFound) + if (!replacementFound) { Components::Logger::Print("Could not find any loaded material with techset {} (in replacement of {}), so I cannot set the sortkey for material {}\n", iw4TechSetName, asset->techniqueSet->name, asset->info.name); } } - else + else { Components::Logger::Print("Could not find any loaded techset with iw4 name {} for iw3 techset {}\n", iw4TechSetName, asset->techniqueSet->name); } } - else + else { Components::Logger::Print("Could not match iw3 techset {} with any of the techsets I know! This is a critical error, there's a good chance the map will not be playable.\n", techName); } @@ -327,15 +730,6 @@ namespace Assets header->material = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).material; } - void IMaterial::loadJson(Game::XAssetHeader* header, const std::string& name, [[maybe_unused]] Components::ZoneBuilder::Zone* builder) - { - Components::FileSystem::File materialInfo(std::format("materials/{}.json", name)); - - if (!materialInfo.exists()) return; - - header->material = nullptr; - } - void IMaterial::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) { Game::Material* asset = header.material; @@ -351,7 +745,7 @@ namespace Assets { if (asset->textureTable[i].u.image) { - if (asset->textureTable[i].semantic == SEMANTIC_WATER_MAP) + if (asset->textureTable[i].semantic == Game::TextureSemantic::TS_WATER_MAP) { if (asset->textureTable[i].u.water->image) { @@ -411,7 +805,7 @@ namespace Assets auto* destTextureDef = &destTextureTable[i]; auto* textureDef = &asset->textureTable[i]; - if (textureDef->semantic == SEMANTIC_WATER_MAP) + if (textureDef->semantic == Game::TextureSemantic::TS_WATER_MAP) { AssertSize(Game::water_t, 68); diff --git a/src/Components/Modules/AssetInterfaces/IMaterial.hpp b/src/Components/Modules/AssetInterfaces/IMaterial.hpp index 54c10449..2aa645b7 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterial.hpp +++ b/src/Components/Modules/AssetInterfaces/IMaterial.hpp @@ -13,5 +13,8 @@ namespace Assets void loadJson(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); + + private: + Game::MaterialTechniqueSet* findWorkingTechset(const std::string techsetName, Game::Material* material, Components::ZoneBuilder::Zone* builder) const; }; } diff --git a/src/Components/Modules/AssetInterfaces/IMaterialPixelShader.cpp b/src/Components/Modules/AssetInterfaces/IMaterialPixelShader.cpp index 47c24cdd..7c3737e4 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterialPixelShader.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterialPixelShader.cpp @@ -1,15 +1,15 @@ #include #include "IMaterialPixelShader.hpp" -#define IW4X_TECHSET_VERSION "0" +#define GFX_RENDERER_SHADER_SM3 0 namespace Assets { void IMaterialPixelShader::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game + if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one } void IMaterialPixelShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) @@ -19,36 +19,19 @@ namespace Assets void IMaterialPixelShader::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - Components::FileSystem::File psFile(std::format("ps/{}.iw4xPS", name)); + Components::FileSystem::File psFile(std::format("ps/{}.cso", name)); if (!psFile.exists()) return; - Utils::Stream::Reader reader(builder->getAllocator(), psFile.getBuffer()); + auto buff = psFile.getBuffer(); + auto programSize = buff.size() / 4; + Game::MaterialPixelShader* asset = builder->getAllocator()->allocate(); - char* magic = reader.readArray(8); - if (std::memcmp(magic, "IW4xPIXL", 8)) - { - Components::Logger::Error(Game::ERR_FATAL, "Reading pixel shader '{}' failed, header is invalid!", name); - } + asset->name = builder->getAllocator()->duplicateString(name); + asset->prog.loadDef.loadForRenderer = GFX_RENDERER_SHADER_SM3; + asset->prog.loadDef.programSize = static_cast(programSize); + asset->prog.loadDef.program = builder->getAllocator()->allocateArray(programSize); + memcpy_s(asset->prog.loadDef.program, buff.size(), buff.data(), buff.size()); - std::string version; - version.push_back(reader.read()); - if (version != IW4X_TECHSET_VERSION) - { - Components::Logger::Error(Game::ERR_FATAL, - "Reading pixel shader '{}' failed, expected version is {}, but it was {}!", name, IW4X_TECHSET_VERSION, version); - } - - Game::MaterialPixelShader* asset = reader.readObject(); - - if (asset->name) - { - asset->name = reader.readCString(); - } - - if (asset->prog.loadDef.program) - { - asset->prog.loadDef.program = reader.readArray(asset->prog.loadDef.programSize); - } header->pixelShader = asset; } diff --git a/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp b/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp index cf713cea..839c3fb0 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp @@ -1,14 +1,14 @@ #include #include "IMaterialTechniqueSet.hpp" -#define IW4X_TECHSET_VERSION "0" +#define IW4X_TECHSET_VERSION 1 namespace Assets { void IMaterialTechniqueSet::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { + if (!header->data) this->loadFromDisk(header, name, builder); // Check if we need to import a new one into the game if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one - if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game } void IMaterialTechniqueSet::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) @@ -16,132 +16,202 @@ namespace Assets header->techniqueSet = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).techniqueSet; } - void IMaterialTechniqueSet::loadBinaryTechnique(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder) + void IMaterialTechniqueSet::loadTechniqueFromDisk(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder) { AssertSize(Game::MaterialPass, 20); - Components::FileSystem::File techFile(std::format("techniques/{}.iw4xTech", name)); - if (!techFile.exists()) { + Components::FileSystem::File techFile(std::format("techniques/{}.iw4x.json", name)); + if (!techFile.exists()) + { *tech = nullptr; + Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Missing technique '{}'\n", name); return; } - Utils::Stream::Reader reader(builder->getAllocator(), techFile.getBuffer()); + nlohmann::json technique; - char* magic = reader.readArray(8); - if (std::memcmp(magic, "IW4xTECH", 8)) + try { - Components::Logger::Error(Game::ERR_FATAL, "Reading technique '{}' failed, header is invalid!", name); + technique = nlohmann::json::parse(techFile.getBuffer()); + } + catch (std::exception& e) + { + Components::Logger::Error(Game::ERR_FATAL, "Reading techset '{}' failed, file is messed up! {}", name, e.what()); } - std::string version; - version.push_back(reader.read()); + int version = technique["version"].get(); + if (version != IW4X_TECHSET_VERSION) { Components::Logger::Error(Game::ERR_FATAL, - "Reading technique '{}' failed, expected version is {}, but it was {}!", name, IW4X_TECHSET_VERSION, version.data()); + "Reading technique '{}' failed, expected version is {}, but it was {}!", name, IW4X_TECHSET_VERSION, version); } - unsigned short flags = reader.read(); - unsigned short passCount = reader.read(); + unsigned short flags = static_cast(Utils::Json::ReadFlags(technique["flags"].get(), sizeof(short))); - Game::MaterialTechnique* asset = (Game::MaterialTechnique*)builder->getAllocator()->allocateArray(sizeof(Game::MaterialTechnique) + (sizeof(Game::MaterialPass) * (passCount - 1))); + if (technique["passArray"].is_array()) + { + nlohmann::json::array_t passArray = technique["passArray"]; - asset->name = builder->getAllocator()->duplicateString(name); - asset->flags = flags; - asset->passCount = passCount; + Game::MaterialTechnique* asset = (Game::MaterialTechnique*)builder->getAllocator()->allocateArray(sizeof(Game::MaterialTechnique) + (sizeof(Game::MaterialPass) * (passArray.size() - 1))); - Game::MaterialPass* passes = reader.readArray(passCount); - std::memcpy(asset->passArray, passes, sizeof(Game::MaterialPass) * passCount); + asset->name = builder->getAllocator()->duplicateString(name); + asset->flags = flags; + asset->passCount = static_cast(passArray.size()); - for (unsigned short i = 0; i < asset->passCount; i++) - { - Game::MaterialPass* pass = &asset->passArray[i]; + Game::MaterialPass* passes = builder->getAllocator()->allocateArray(asset->passCount); + std::memcpy(asset->passArray, passes, sizeof(Game::MaterialPass) * asset->passCount); - if (pass->vertexDecl) + for (unsigned short i = 0; i < asset->passCount; i++) { - const char* declName = reader.readCString(); - pass->vertexDecl = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_VERTEXDECL, declName, builder).vertexDecl; - } + Game::MaterialPass* pass = &asset->passArray[i]; + auto jsonPass = passArray[i]; - if (pass->vertexShader) - { - const char* vsName = reader.readCString(); - pass->vertexShader = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, vsName, builder).vertexShader; - - } - - if (pass->pixelShader) - { - const char* psName = reader.readCString(); - pass->pixelShader = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_PIXELSHADER, psName, builder).pixelShader; - } - - pass->args = reader.readArray(pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount); - - for (int j = 0; j < pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount; j++) - { - if (pass->args[j].type == 1 || pass->args[j].type == 7) + if (jsonPass["vertexDeclaration"].is_string()) { - pass->args[j].u.literalConst = reader.readArray(4); + auto declName = jsonPass["vertexDeclaration"].get(); + pass->vertexDecl = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_VERTEXDECL, declName, builder).vertexDecl; } - if (pass->args[j].type == 3 || pass->args[j].type == 5) + if (jsonPass["vertexShader"].is_string()) { - pass->args[j].u.codeConst.index = *reader.readObject(); - pass->args[j].u.codeConst.firstRow = *reader.readObject(); - pass->args[j].u.codeConst.rowCount = *reader.readObject(); + auto vsName = jsonPass["vertexShader"].get(); + pass->vertexShader = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, vsName, builder).vertexShader; + } + + if (jsonPass["pixelShader"].is_string()) + { + auto psName = jsonPass["pixelShader"].get(); + pass->pixelShader = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_PIXELSHADER, psName, builder).pixelShader; + } + + pass->perPrimArgCount = jsonPass["perPrimArgCount"].get(); + pass->perObjArgCount = jsonPass["perObjArgCount"].get(); + pass->stableArgCount = jsonPass["stableArgCount"].get(); + pass->customSamplerFlags = jsonPass["customSamplerFlags"].get(); + + + if (jsonPass["arguments"].is_array()) + { + nlohmann::json::array_t jsonAguments = jsonPass["arguments"]; + + pass->args = builder->getAllocator()->allocateArray(jsonAguments.size()); + + for (size_t j = 0; j < jsonAguments.size(); j++) + { + auto jsonArgument = jsonAguments[j]; + Game::MaterialShaderArgument* argument = &pass->args[j]; + + argument->type = jsonArgument["type"].get(); + argument->dest = jsonArgument["dest"].get(); + + if (argument->type == Game::MaterialShaderArgumentType::MTL_ARG_LITERAL_VERTEX_CONST || + argument->type == Game::MaterialShaderArgumentType::MTL_ARG_LITERAL_PIXEL_CONST) + { + argument->u.literalConst = builder->getAllocator()->allocateArray(4); + + auto literals = jsonArgument["literals"].get>(); + std::copy(literals.begin(), literals.end(), argument->u.literalConst); + } + else if (argument->type == Game::MaterialShaderArgumentType::MTL_ARG_CODE_VERTEX_CONST || + argument->type == Game::MaterialShaderArgumentType::MTL_ARG_CODE_PIXEL_CONST) + { + if (jsonArgument["codeConst"].is_object()) + { + auto codeConst = jsonArgument["codeConst"]; + + argument->u.codeConst.index = codeConst["index"].get(); + argument->u.codeConst.firstRow = codeConst["firstRow"].get(); + argument->u.codeConst.rowCount = codeConst["rowCount"].get(); + } + } + else if (argument->type == Game::MaterialShaderArgumentType::MTL_ARG_MATERIAL_PIXEL_SAMPLER || + argument->type == Game::MaterialShaderArgumentType::MTL_ARG_MATERIAL_VERTEX_CONST || + argument->type == Game::MaterialShaderArgumentType::MTL_ARG_MATERIAL_PIXEL_CONST) + { + argument->u.nameHash = jsonArgument["nameHash"].get(); + } + else if (argument->type == Game::MaterialShaderArgumentType::MTL_ARG_CODE_PIXEL_SAMPLER) + { + argument->u.codeSampler = jsonArgument["codeSampler"].get(); + } + } } } + + *tech = asset; } - - *tech = asset; } - void IMaterialTechniqueSet::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) + void IMaterialTechniqueSet::loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - Components::FileSystem::File tsFile(std::format("techsets/{}.iw4xTS", name)); + Components::FileSystem::File tsFile(std::format("techsets/{}.iw4x.json", name)); if (!tsFile.exists()) return; - Utils::Stream::Reader reader(builder->getAllocator(), tsFile.getBuffer()); + nlohmann::json techset; - char* magic = reader.readArray(8); - if (std::memcmp(magic, "IW4xTSET", 8)) + try { - Components::Logger::Error(Game::ERR_FATAL, "Reading techset '{}' failed, header is invalid!", name); + techset = nlohmann::json::parse(tsFile.getBuffer()); + } + catch (std::exception& e) + { + Components::Logger::Error(Game::ERR_FATAL, "Reading techset '{}' failed, file is messed up! {}", name, e.what()); } - std::string version; - version.push_back(reader.read()); + auto version = techset["version"].get(); if (version != IW4X_TECHSET_VERSION) { Components::Logger::Error(Game::ERR_FATAL, "Reading techset '{}' failed, expected version is {}, but it was {}!", name, IW4X_TECHSET_VERSION, version); } - Game::MaterialTechniqueSet* asset = reader.readObject(); + Game::MaterialTechniqueSet* asset = builder->getAllocator()->allocate(); - if (asset->name) + if (asset == nullptr) { - asset->name = reader.readCString(); + Components::Logger::Error(Game::ERR_FATAL, "Reading techset '{}' failed, allocation failed!", name); + return; } - for (int i = 0; i < 48; i++) + if (techset["name"].is_string()) { - if (asset->techniques[i]) + asset->name = builder->getAllocator()->duplicateString(techset["name"].get()); + } + + asset->hasBeenUploaded = techset["hasBeenUploaded"].get(); + asset->worldVertFormat = techset["worldVertFormat"].get(); + + + if (techset["remappedTechniqueSet"].is_string()) + { + auto remapped = techset["remappedTechniqueSet"].get(); + + if (remapped != asset->name) { - const char* techName = reader.readCString(); - this->loadBinaryTechnique(&asset->techniques[i], techName, builder); + builder->loadAssetByName(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, remapped, false); } } + if (techset["techniques"].is_object()) + { + for (int i = 0; i < Game::TECHNIQUE_COUNT; i++) + { + auto technique = techset["techniques"].at(std::to_string(i)); + + if (technique.is_string()) + { + this->loadTechniqueFromDisk(&asset->techniques[i], technique.get(), builder); + } + } + } header->techniqueSet = asset; } void IMaterialTechniqueSet::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) - { + { Game::MaterialTechniqueSet* asset = header.techniqueSet; for (int i = 0; i < ARRAYSIZE(Game::MaterialTechniqueSet::techniques); ++i) @@ -177,8 +247,10 @@ namespace Assets AssertSize(Game::MaterialTechniqueSet, 204); Utils::Stream* buffer = builder->getBuffer(); + Game::MaterialTechniqueSet* asset = header.techniqueSet; Game::MaterialTechniqueSet* dest = buffer->dest(); + buffer->save(asset); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); diff --git a/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.hpp b/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.hpp index 9978b6cd..60275dc4 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.hpp +++ b/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.hpp @@ -12,8 +12,8 @@ namespace Assets void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override; void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); - void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); + void loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder); - void loadBinaryTechnique(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder); + void loadTechniqueFromDisk(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder); }; } diff --git a/src/Components/Modules/AssetInterfaces/IMaterialVertexDeclaration.cpp b/src/Components/Modules/AssetInterfaces/IMaterialVertexDeclaration.cpp index e1225f7e..26b16d11 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterialVertexDeclaration.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterialVertexDeclaration.cpp @@ -1,14 +1,14 @@ #include #include "IMaterialVertexDeclaration.hpp" -#define IW4X_TECHSET_VERSION "0" +#define IW4X_TECHSET_VERSION 1 namespace Assets { void IMaterialVertexDeclaration::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game + if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one } void IMaterialVertexDeclaration::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) @@ -29,12 +29,11 @@ namespace Assets Components::Logger::Error(Game::ERR_FATAL, "Reading vertex declaration '{}' failed, header is invalid!", name); } - std::string version; - version.push_back(reader.read()); + auto version = reader.read(); if (version != IW4X_TECHSET_VERSION) { - Components::Logger::Error(Game::ERR_FATAL, "Reading vertex declaration '{}' failed, expected version is {}, but it was {}!", - name, IW4X_TECHSET_VERSION, version.data()); + Components::Logger::Error(Game::ERR_FATAL, "Reading vertex declaration '{}' failed, expected version is {}, but it was {:d}!", + name, IW4X_TECHSET_VERSION, version); } Game::MaterialVertexDeclaration* asset = reader.readObject(); diff --git a/src/Components/Modules/AssetInterfaces/IMaterialVertexShader.cpp b/src/Components/Modules/AssetInterfaces/IMaterialVertexShader.cpp index 3acd7be2..e4d7c9b5 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterialVertexShader.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterialVertexShader.cpp @@ -1,14 +1,14 @@ #include #include "IMaterialVertexShader.hpp" -#define IW4X_TECHSET_VERSION "0" +#define GFX_RENDERER_SHADER_SM3 0 namespace Assets { void IMaterialVertexShader::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game + if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one } void IMaterialVertexShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/) @@ -18,36 +18,18 @@ namespace Assets void IMaterialVertexShader::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - Components::FileSystem::File vsFile(std::format("vs/{}.iw4xVS", name)); + Components::FileSystem::File vsFile(std::format("vs/{}.cso", name)); if (!vsFile.exists()) return; - Utils::Stream::Reader reader(builder->getAllocator(), vsFile.getBuffer()); + auto buff = vsFile.getBuffer(); + auto programSize = buff.size() / 4; + Game::MaterialVertexShader* asset = builder->getAllocator()->allocate(); - char* magic = reader.readArray(8); - if (std::memcmp(magic, "IW4xVERT", 8)) - { - Components::Logger::Error(Game::ERR_FATAL, "Reading vertex shader '{}' failed, header is invalid!", name); - } - - std::string version; - version.push_back(reader.read()); - if (version != IW4X_TECHSET_VERSION) - { - Components::Logger::Error(Game::ERR_FATAL, "Reading vertex shader '{}' failed, expected version is {}, but it was {}!", - name, IW4X_TECHSET_VERSION, version); - } - - Game::MaterialVertexShader* asset = reader.readObject(); - - if (asset->name) - { - asset->name = reader.readCString(); - } - - if (asset->prog.loadDef.program) - { - asset->prog.loadDef.program = reader.readArray(asset->prog.loadDef.programSize); - } + asset->name = builder->getAllocator()->duplicateString(name); + asset->prog.loadDef.loadForRenderer = GFX_RENDERER_SHADER_SM3; + asset->prog.loadDef.programSize = static_cast(programSize); + asset->prog.loadDef.program = builder->getAllocator()->allocateArray(programSize); + memcpy_s(asset->prog.loadDef.program, buff.size(), buff.data(), buff.size()); header->vertexShader = asset; } diff --git a/src/Components/Modules/AssetInterfaces/IWeapon.cpp b/src/Components/Modules/AssetInterfaces/IWeapon.cpp index d98b310f..40e8fdd5 100644 --- a/src/Components/Modules/AssetInterfaces/IWeapon.cpp +++ b/src/Components/Modules/AssetInterfaces/IWeapon.cpp @@ -280,7 +280,7 @@ namespace Assets unsigned short* scriptStringTable = buffer->dest(); buffer->saveArray(def->notetrackSoundMapKeys, 16); for (int i = 0; i < 16; i++) { - builder->mapScriptString(&scriptStringTable[i]); + builder->mapScriptString(scriptStringTable[i]); } Utils::Stream::ClearPointer(&dest->notetrackSoundMapKeys); @@ -292,7 +292,7 @@ namespace Assets unsigned short* scriptStringTable = buffer->dest(); buffer->saveArray(def->notetrackSoundMapValues, 16); for (int i = 0; i < 16; i++) { - builder->mapScriptString(&scriptStringTable[i]); + builder->mapScriptString(scriptStringTable[i]); } Utils::Stream::ClearPointer(&dest->notetrackSoundMapValues); @@ -304,7 +304,7 @@ namespace Assets unsigned short* scriptStringTable = buffer->dest(); buffer->saveArray(def->notetrackRumbleMapKeys, 16); for (int i = 0; i < 16; i++) { - builder->mapScriptString(&scriptStringTable[i]); + builder->mapScriptString(scriptStringTable[i]); } Utils::Stream::ClearPointer(&dest->notetrackRumbleMapKeys); @@ -316,7 +316,7 @@ namespace Assets unsigned short* scriptStringTable = buffer->dest(); buffer->saveArray(def->notetrackRumbleMapValues, 16); for (int i = 0; i < 16; i++) { - builder->mapScriptString(&scriptStringTable[i]); + builder->mapScriptString(scriptStringTable[i]); } Utils::Stream::ClearPointer(&dest->notetrackRumbleMapValues); @@ -725,7 +725,7 @@ namespace Assets unsigned short* scriptStringTable = buffer->dest(); buffer->saveArray(asset->hideTags, 32); for (int i = 0; i < 32; i++) { - builder->mapScriptString(&scriptStringTable[i]); + builder->mapScriptString(scriptStringTable[i]); } Utils::Stream::ClearPointer(&dest->hideTags); diff --git a/src/Components/Modules/AssetInterfaces/IXAnimParts.cpp b/src/Components/Modules/AssetInterfaces/IXAnimParts.cpp index f9527de5..0bd5e2ce 100644 --- a/src/Components/Modules/AssetInterfaces/IXAnimParts.cpp +++ b/src/Components/Modules/AssetInterfaces/IXAnimParts.cpp @@ -264,7 +264,7 @@ namespace Assets for (char i = 0; i < asset->boneCount[Game::PART_TYPE_ALL]; ++i) { - builder->mapScriptString(&destTagnames[i]); + builder->mapScriptString(destTagnames[i]); } Utils::Stream::ClearPointer(&dest->names); @@ -280,7 +280,7 @@ namespace Assets for (char i = 0; i < asset->notifyCount; ++i) { - builder->mapScriptString(&destNotetracks[i].name); + builder->mapScriptString(destNotetracks[i].name); } Utils::Stream::ClearPointer(&dest->notify); diff --git a/src/Components/Modules/AssetInterfaces/IXModel.cpp b/src/Components/Modules/AssetInterfaces/IXModel.cpp index 386bc472..305a624c 100644 --- a/src/Components/Modules/AssetInterfaces/IXModel.cpp +++ b/src/Components/Modules/AssetInterfaces/IXModel.cpp @@ -1,7 +1,7 @@ #include #include "IXModel.hpp" -#define IW4X_MODEL_VERSION 5 +#define IW4X_MODEL_VERSION 8 namespace Assets { @@ -9,32 +9,32 @@ namespace Assets { if (entry->nodes) { - entry->nodes = reader->readArray(entry->nodeCount); + entry->nodes = reader->readArrayOnce(entry->nodeCount); } if (entry->leafs) { - entry->leafs = reader->readArray(entry->leafCount); + entry->leafs = reader->readArrayOnce(entry->leafCount); } } - void IXModel::loadXSurface(Game::XSurface* surf, Utils::Stream::Reader* reader, Components::ZoneBuilder::Zone* builder) + void IXModel::loadXSurface(Game::XSurface* surf, Utils::Stream::Reader* reader, [[maybe_unused]] Components::ZoneBuilder::Zone* builder) { if (surf->vertInfo.vertsBlend) { - surf->vertInfo.vertsBlend = reader->readArray(surf->vertInfo.vertCount[0] + (surf->vertInfo.vertCount[1] * 3) + (surf->vertInfo.vertCount[2] * 5) + (surf->vertInfo.vertCount[3] * 7)); + surf->vertInfo.vertsBlend = reader->readArrayOnce(surf->vertInfo.vertCount[0] + (surf->vertInfo.vertCount[1] * 3) + (surf->vertInfo.vertCount[2] * 5) + (surf->vertInfo.vertCount[3] * 7)); } // Access vertex block if (surf->verts0) { - surf->verts0 = reader->readArray(surf->vertCount); + surf->verts0 = reader->readArrayOnce(surf->vertCount); } // Save_XRigidVertListArray if (surf->vertList) { - surf->vertList = reader->readArray(surf->vertListCount); + surf->vertList = reader->readArrayOnce(surf->vertListCount); for (unsigned int i = 0; i < surf->vertListCount; ++i) { @@ -51,17 +51,7 @@ namespace Assets // Access index block if (surf->triIndices) { - void* oldPtr = surf->triIndices; - surf->triIndices = reader->readArray(surf->triCount * 3); - - if (builder->getAllocator()->isPointerMapped(oldPtr)) - { - surf->triIndices = builder->getAllocator()->getPointer(oldPtr); - } - else - { - builder->getAllocator()->mapPointer(oldPtr, surf->triIndices); - } + surf->triIndices = reader->readArrayOnce(surf->triCount * 3); } } @@ -74,7 +64,7 @@ namespace Assets if (asset->surfs) { - asset->surfs = reader->readArray(asset->numsurfs); + asset->surfs = reader->readArrayOnce(asset->numsurfs); for (int i = 0; i < asset->numsurfs; ++i) { @@ -110,11 +100,6 @@ namespace Assets Components::Logger::Error(Game::ERR_FATAL, "Reading model '{}' failed, expected version is {}, but it was {}!", name, IW4X_MODEL_VERSION, version); } - if (version == 4) - { - Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Model '{}' is in legacy format, please update it!\n", name); - } - Game::XModel* asset = reader.readObject(); if (asset->name) @@ -134,27 +119,27 @@ namespace Assets if (asset->parentList) { - asset->parentList = reader.readArray(asset->numBones - asset->numRootBones); + asset->parentList = reader.readArrayOnce(asset->numBones - asset->numRootBones); } if (asset->quats) { - asset->quats = reader.readArray((asset->numBones - asset->numRootBones) * 4); + asset->quats = reader.readArrayOnce((asset->numBones - asset->numRootBones) * 4); } if (asset->trans) { - asset->trans = reader.readArray((asset->numBones - asset->numRootBones) * 3); + asset->trans = reader.readArrayOnce((asset->numBones - asset->numRootBones) * 3); } if (asset->partClassification) { - asset->partClassification = reader.readArray(asset->numBones); + asset->partClassification = reader.readArrayOnce(asset->numBones); } if (asset->baseMat) { - asset->baseMat = reader.readArray(asset->numBones); + asset->baseMat = reader.readArrayOnce(asset->numBones); } if (asset->materialHandles) @@ -172,7 +157,7 @@ namespace Assets // Save_XModelLodInfoArray { - for (int i = 0; i < 4; ++i) + for (unsigned int i = 0; i < 4; ++i) { if (asset->lodInfo[i].modelSurfs) { @@ -247,60 +232,53 @@ namespace Assets if (asset->physCollmap) { - if (version == 4) + Game::PhysCollmap* collmap = reader.readObject(); + asset->physCollmap = collmap; + + if (collmap->name) { - asset->physCollmap = nullptr; + collmap->name = reader.readCString(); } - else + + if (collmap->geoms) { - Game::PhysCollmap* collmap = reader.readObject(); - asset->physCollmap = collmap; + collmap->geoms = reader.readArray(collmap->count); - if (collmap->name) + for (unsigned int i = 0; i < collmap->count; ++i) { - collmap->name = reader.readCString(); - } + Game::PhysGeomInfo* geom = &collmap->geoms[i]; - if (collmap->geoms) - { - collmap->geoms = reader.readArray(collmap->count); - - for (unsigned int i = 0; i < collmap->count; ++i) + if (geom->brushWrapper) { - Game::PhysGeomInfo* geom = &collmap->geoms[i]; - - if (geom->brushWrapper) + Game::BrushWrapper* brush = reader.readObject(); + geom->brushWrapper = brush; { - Game::BrushWrapper* brush = reader.readObject(); - geom->brushWrapper = brush; + if (brush->brush.sides) { - if (brush->brush.sides) + brush->brush.sides = reader.readArray(brush->brush.numsides); + for (unsigned short j = 0; j < brush->brush.numsides; ++j) { - brush->brush.sides = reader.readArray(brush->brush.numsides); - for (unsigned short j = 0; j < brush->brush.numsides; ++j) - { - Game::cbrushside_t* side = &brush->brush.sides[j]; + Game::cbrushside_t* side = &brush->brush.sides[j]; - // TODO: Add pointer support - if (side->plane) - { - side->plane = reader.readObject(); - } + // TODO: Add pointer support + if (side->plane) + { + side->plane = reader.readObject(); } } - - if (brush->brush.baseAdjacentSide) - { - brush->brush.baseAdjacentSide = reader.readArray(brush->totalEdgeCount); - } } - // TODO: Add pointer support - if (brush->planes) + if (brush->brush.baseAdjacentSide) { - brush->planes = reader.readArray(brush->brush.numsides); + brush->brush.baseAdjacentSide = reader.readArray(brush->totalEdgeCount); } } + + // TODO: Add pointer support + if (brush->planes) + { + brush->planes = reader.readArray(brush->brush.numsides); + } } } @@ -386,7 +364,7 @@ namespace Assets for (char i = 0; i < asset->numBones; ++i) { - builder->mapScriptString(&destBoneNames[i]); + builder->mapScriptString(destBoneNames[i]); } Utils::Stream::ClearPointer(&dest->boneNames); @@ -394,37 +372,77 @@ namespace Assets if (asset->parentList) { - buffer->save(asset->parentList, asset->numBones - asset->numRootBones); - Utils::Stream::ClearPointer(&dest->parentList); + if (builder->hasPointer(asset->parentList)) + { + dest->parentList = builder->getPointer(asset->parentList); + } + else + { + builder->storePointer(asset->parentList); + buffer->save(asset->parentList, asset->numBones - asset->numRootBones); + Utils::Stream::ClearPointer(&dest->parentList); + } } if (asset->quats) { - buffer->align(Utils::Stream::ALIGN_2); - buffer->saveArray(asset->quats, (asset->numBones - asset->numRootBones) * 4); - Utils::Stream::ClearPointer(&dest->quats); + if (builder->hasPointer(asset->quats)) + { + dest->quats = builder->getPointer(asset->quats); + } + else + { + buffer->align(Utils::Stream::ALIGN_2); + builder->storePointer(asset->quats); + buffer->saveArray(asset->quats, (asset->numBones - asset->numRootBones) * 4); + Utils::Stream::ClearPointer(&dest->quats); + } } if (asset->trans) { - buffer->align(Utils::Stream::ALIGN_4); - buffer->saveArray(asset->trans, (asset->numBones - asset->numRootBones) * 3); - Utils::Stream::ClearPointer(&dest->trans); + if (builder->hasPointer(asset->trans)) + { + dest->trans = builder->getPointer(asset->trans); + } + else + { + buffer->align(Utils::Stream::ALIGN_4); + builder->storePointer(asset->trans); + buffer->saveArray(asset->trans, (asset->numBones - asset->numRootBones) * 3); + Utils::Stream::ClearPointer(&dest->trans); + } } if (asset->partClassification) { - buffer->save(asset->partClassification, asset->numBones); - Utils::Stream::ClearPointer(&dest->partClassification); + if (builder->hasPointer(asset->partClassification)) + { + dest->partClassification = builder->getPointer(asset->partClassification); + } + else + { + builder->storePointer(asset->partClassification); + buffer->save(asset->partClassification, asset->numBones); + Utils::Stream::ClearPointer(&dest->partClassification); + } } if (asset->baseMat) { AssertSize(Game::DObjAnimMat, 32); + if (builder->hasPointer(asset->baseMat)) + { + dest->baseMat = builder->getPointer(asset->baseMat); + } + else + { + buffer->align(Utils::Stream::ALIGN_4); + builder->storePointer(asset->baseMat); + buffer->saveArray(asset->baseMat, asset->numBones); + Utils::Stream::ClearPointer(&dest->baseMat); + } - buffer->align(Utils::Stream::ALIGN_4); - buffer->saveArray(asset->baseMat, asset->numBones); - Utils::Stream::ClearPointer(&dest->baseMat); } if (asset->materialHandles) diff --git a/src/Components/Modules/AssetInterfaces/IXModelSurfs.cpp b/src/Components/Modules/AssetInterfaces/IXModelSurfs.cpp index bbe4b96a..15c4333a 100644 --- a/src/Components/Modules/AssetInterfaces/IXModelSurfs.cpp +++ b/src/Components/Modules/AssetInterfaces/IXModelSurfs.cpp @@ -37,9 +37,18 @@ namespace Assets if (surf->vertInfo.vertsBlend) { - buffer->align(Utils::Stream::ALIGN_2); - buffer->saveArray(surf->vertInfo.vertsBlend, surf->vertInfo.vertCount[0] + (surf->vertInfo.vertCount[1] * 3) + (surf->vertInfo.vertCount[2] * 5) + (surf->vertInfo.vertCount[3] * 7)); - Utils::Stream::ClearPointer(&destSurf->vertInfo.vertsBlend); + if (builder->hasPointer(surf->vertInfo.vertsBlend)) + { + destSurf->vertInfo.vertsBlend = builder->getPointer(surf->vertInfo.vertsBlend); + } + else + { + + buffer->align(Utils::Stream::ALIGN_2); + builder->storePointer(surf->vertInfo.vertsBlend); + buffer->saveArray(surf->vertInfo.vertsBlend, surf->vertInfo.vertCount[0] + (surf->vertInfo.vertCount[1] * 3) + (surf->vertInfo.vertCount[2] * 5) + (surf->vertInfo.vertCount[3] * 7)); + Utils::Stream::ClearPointer(&destSurf->vertInfo.vertsBlend); + } } // Access vertex block @@ -48,9 +57,17 @@ namespace Assets { AssertSize(Game::GfxPackedVertex, 32); - buffer->align(Utils::Stream::ALIGN_16); - buffer->saveArray(surf->verts0, surf->vertCount); - Utils::Stream::ClearPointer(&destSurf->verts0); + if (builder->hasPointer(surf->verts0)) + { + destSurf->verts0 = builder->getPointer(surf->verts0); + } + else + { + buffer->align(Utils::Stream::ALIGN_16); + builder->storePointer(surf->verts0); + buffer->saveArray(surf->verts0, surf->vertCount); + Utils::Stream::ClearPointer(&destSurf->verts0); + } } buffer->popBlock(); @@ -59,25 +76,40 @@ namespace Assets { AssertSize(Game::XRigidVertList, 12); - buffer->align(Utils::Stream::ALIGN_4); - - Game::XRigidVertList* destCt = buffer->dest(); - buffer->saveArray(surf->vertList, surf->vertListCount); - - for (unsigned int i = 0; i < surf->vertListCount; ++i) + if (builder->hasPointer(surf->vertList)) { - Game::XRigidVertList* destRigidVertList = &destCt[i]; - Game::XRigidVertList* rigidVertList = &surf->vertList[i]; - - if (rigidVertList->collisionTree) - { - buffer->align(Utils::Stream::ALIGN_4); - this->saveXSurfaceCollisionTree(rigidVertList->collisionTree, builder); - Utils::Stream::ClearPointer(&destRigidVertList->collisionTree); - } + destSurf->vertList = builder->getPointer(surf->vertList); } + else + { + buffer->align(Utils::Stream::ALIGN_4); + builder->storePointer(surf->vertList); - Utils::Stream::ClearPointer(&destSurf->vertList); + Game::XRigidVertList* destCt = buffer->dest(); + buffer->saveArray(surf->vertList, surf->vertListCount); + + for (unsigned int i = 0; i < surf->vertListCount; ++i) + { + Game::XRigidVertList* destRigidVertList = &destCt[i]; + Game::XRigidVertList* rigidVertList = &surf->vertList[i]; + + if (rigidVertList->collisionTree) + { + if (builder->hasPointer(rigidVertList->collisionTree)) + { + destRigidVertList->collisionTree = builder->getPointer(rigidVertList->collisionTree); + } + else { + buffer->align(Utils::Stream::ALIGN_4); + builder->storePointer(rigidVertList->collisionTree); + this->saveXSurfaceCollisionTree(rigidVertList->collisionTree, builder); + Utils::Stream::ClearPointer(&destRigidVertList->collisionTree); + } + } + } + + Utils::Stream::ClearPointer(&destSurf->vertList); + } } // Access index block @@ -89,6 +121,7 @@ namespace Assets else { buffer->align(Utils::Stream::ALIGN_16); + builder->storePointer(surf->triIndices); buffer->saveArray(surf->triIndices, surf->triCount * 3); Utils::Stream::ClearPointer(&destSurf->triIndices); } diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index fcb99cee..14183e85 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -564,7 +564,7 @@ namespace Components bool Maps::IsCustomMap() { Game::GfxWorld*& gameWorld = *reinterpret_cast(0x66DEE94); - if(gameWorld) return gameWorld->checksum == 0xDEADBEEF; + if (gameWorld) return (gameWorld->checksum & 0xFFFF0000) == 0xC0D40000; return false; } @@ -619,7 +619,7 @@ namespace Components for (unsigned int i = 0; i < gameWorld->dpvs.smodelCount; ++i) { - if (gameWorld->dpvs.smodelDrawInsts[i].model->name == model) + if (model == "all"s || gameWorld->dpvs.smodelDrawInsts[i].model->name == model) { gameWorld->dpvs.smodelVisData[0][i] = 0; gameWorld->dpvs.smodelVisData[1][i] = 0; @@ -641,86 +641,6 @@ namespace Components } } - Game::dvar_t* Maps::GetDistortionDvar() - { - Game::dvar_t*& r_distortion = *reinterpret_cast(0x69F0DCC); - - if(Maps::IsCustomMap()) - { - static Game::dvar_t noDistortion; - ZeroMemory(&noDistortion, sizeof noDistortion); - return &noDistortion; - } - - return r_distortion; - } - - __declspec(naked) void Maps::SetDistortionStub() - { - __asm - { - push eax - pushad - call Maps::GetDistortionDvar - - mov [esp + 20h], eax - popad - - pop eax - retn - } - } - - Game::dvar_t* Maps::GetSpecularDvar() - { - Game::dvar_t*& r_specular = *reinterpret_cast(0x69F0D94); - static Game::dvar_t* r_specularCustomMaps = Game::Dvar_RegisterBool("r_specularCustomMaps", false, Game::DVAR_ARCHIVE, "Allows shaders to use phong specular lighting on custom maps"); - - if (Maps::IsCustomMap()) - { - if (!r_specularCustomMaps->current.enabled) - { - static Game::dvar_t noSpecular; - ZeroMemory(&noSpecular, sizeof noSpecular); - return &noSpecular; - } - } - - return r_specular; - } - - __declspec(naked) void Maps::SetSpecularStub1() - { - __asm - { - push eax - pushad - call Maps::GetSpecularDvar - - mov [esp + 20h], eax - popad - - pop eax - retn - } - } - - __declspec(naked) void Maps::SetSpecularStub2() - { - __asm - { - push eax - pushad - call Maps::GetSpecularDvar - - mov [esp + 20h], eax - popad - - pop edx - retn - } - } - void Maps::G_SpawnTurretHook(Game::gentity_s* ent, int unk, int unk2) { if (Maps::CurrentMainZone == "mp_backlot_sh"s || Maps::CurrentMainZone == "mp_con_spring"s || @@ -842,16 +762,6 @@ namespace Components // Allow loading raw suns Utils::Hook(0x51B46A, Maps::LoadRawSun, HOOK_CALL).install()->quick(); - // Disable distortion on custom maps - //Utils::Hook(0x50AA47, Maps::SetDistortionStub, HOOK_CALL).install()->quick(); - - // Disable speculars on custom maps - Utils::Hook(0x525EA6, Maps::SetSpecularStub1, HOOK_CALL).install()->quick(); - Utils::Hook(0x51FBC7, Maps::SetSpecularStub2, HOOK_CALL).install()->quick(); - Utils::Hook(0x522A2E, Maps::SetSpecularStub2, HOOK_CALL).install()->quick(); - Utils::Hook::Nop(0x51FBCC, 1); - Utils::Hook::Nop(0x522A33, 1); - // Intercept map loading for usermap initialization Utils::Hook(0x6245E3, Maps::SpawnServerStub, HOOK_CALL).install()->quick(); Utils::Hook(0x62493E, Maps::SpawnServerStub, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index c601b8a7..7a4e302b 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -755,18 +755,6 @@ namespace Components Menus::CustomMenus.push_back(menu); } - void Menus::RegisterCustomMenusHook() - { - Utils::Hook::Call(0x401700)(); // call original load functions - -#ifdef _DEBUG - for (int i = 0; i < Game::uiContext->menuCount; i++) - { - OutputDebugStringA(Utils::String::VA("%s\n", Game::uiContext->Menus[i]->window.name)); - } -#endif - } - Menus::Menus() { if (ZoneBuilder::IsEnabled()) @@ -786,9 +774,6 @@ namespace Components // Don't open connect menu //Utils::Hook::Nop(0x428E48, 5); - // register custom menufiles if they exist - Utils::Hook(0x4A58C3, Menus::RegisterCustomMenusHook, HOOK_CALL).install()->quick(); - // Use the connect menu open call to update server motds Utils::Hook(0x428E48, []() { diff --git a/src/Components/Modules/Menus.hpp b/src/Components/Modules/Menus.hpp index fd13fe13..7e53759f 100644 --- a/src/Components/Modules/Menus.hpp +++ b/src/Components/Modules/Menus.hpp @@ -56,8 +56,6 @@ namespace Components static void RemoveMenuFromContext(Game::UiContext* dc, Game::menuDef_t* menu); - static void RegisterCustomMenusHook(); - // Ugly! static int KeywordHash(char* key); }; diff --git a/src/Components/Modules/Renderer.cpp b/src/Components/Modules/Renderer.cpp index 16bb5b66..71541cad 100644 --- a/src/Components/Modules/Renderer.cpp +++ b/src/Components/Modules/Renderer.cpp @@ -14,6 +14,7 @@ namespace Components Dvar::Var Renderer::r_drawModelNames; Dvar::Var Renderer::r_drawAABBTrees; Dvar::Var Renderer::r_playerDrawDebugDistance; + Dvar::Var Renderer::r_forceTechnique; float cyan[4] = { 0.0f, 0.5f, 0.5f, 1.0f }; float red[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; @@ -171,6 +172,32 @@ namespace Components return Utils::Hook::Call(0x005033E0)(a1, a2, a3, Utils::String::VA("%s (^3%s^7)", mat->info.name, mat->techniqueSet->name), color, a6); } + void ListSamplers() + { + static auto* source = reinterpret_cast(0x6CAF080); + + Game::Font_s* font = Game::R_RegisterFont("fonts/smallFont", 0); + auto height = Game::R_TextHeight(font); + auto scale = 1.0f; + float color[4] = {0.0f, 1.0f, 0.0f, 1.0f}; + + for (std::size_t i = 0; i < 27; ++i) + { + if (source->input.codeImages[i] == nullptr) + { + color[0] = 1.f; + } + else + { + color[0] = 0.f; + } + + std::stringstream str; + str << std::format("{}/{:#X} => ", i, i) << (source->input.codeImages[i] == nullptr ? "---" : source->input.codeImages[i]->name) << " " << std::to_string(source->input.codeImageSamplerStates[i]); + Game::R_AddCmdDrawText(str.str().data(), std::numeric_limits::max(), font, 15.0f, (height * scale + 1) * (i + 1) + 14.0f, scale, scale, 0.0f, color, Game::ITEM_TEXTSTYLE_NORMAL); + } + } + void Renderer::DebugDrawTriggers() { if (!r_drawTriggers.get()) return; @@ -326,21 +353,15 @@ namespace Components // Static models for (size_t i = 0; i < world->dpvs.smodelCount; i++) { - auto staticModel = world->dpvs.smodelDrawInsts[i]; + auto staticModel = &world->dpvs.smodelDrawInsts[i]; + Game::Bounds* b = &world->dpvs.smodelInsts[i].bounds; - if (Utils::Maths::Vec3SqrDistance(playerPosition, staticModel.placement.origin) < sqrDist) + if (Utils::Maths::Vec3SqrDistance(playerPosition, staticModel->placement.origin) < sqrDist) { - if (staticModel.model) + if (staticModel->model) { - Game::Bounds b = staticModel.model->bounds; - b.midPoint[0] += staticModel.placement.origin[0]; - b.midPoint[1] += staticModel.placement.origin[1]; - b.midPoint[2] += staticModel.placement.origin[2]; - b.halfSize[0] *= staticModel.placement.scale; - b.halfSize[1] *= staticModel.placement.scale; - b.halfSize[2] *= staticModel.placement.scale; - Game::R_AddDebugBounds(staticModelsColor, &b); + Game::R_AddDebugBounds(staticModelsColor, b); } } } @@ -447,6 +468,29 @@ namespace Components } } + void Renderer::ForceTechnique() + { + auto forceTechnique = r_forceTechnique.get(); + + if (forceTechnique > 0) + { + Utils::Hook::Set(0x6FABDF4, forceTechnique); + } + } + + int Renderer::FixSunShadowPartitionSize(Game::GfxCamera* camera, Game::GfxSunShadowMapMetrics* mapMetrics, Game::GfxSunShadow* sunShadow, Game::GfxSunShadowClip* clip, float* partitionFraction) + { + auto result = Utils::Hook::Call(0x5463B0)(camera, mapMetrics, sunShadow, clip, partitionFraction); + + if (Maps::IsCustomMap()) + { + // Fixes shadowmap viewport which fixes pixel adjustment shadowmap bug - partly, because the real problem lies within the way CoD4 shaders are programmed + sunShadow->partition[Game::SunShadowPartition::R_SUNSHADOW_FAR].viewportParms.viewport = sunShadow->partition[Game::SunShadowPartition::R_SUNSHADOW_NEAR].viewportParms.viewport; + } + + return result; + } + Renderer::Renderer() { if (Dedicated::IsEnabled()) return; @@ -460,9 +504,14 @@ namespace Components DebugDrawModelBoundingBoxes(); DebugDrawSceneModelCollisions(); DebugDrawTriggers(); + ForceTechnique(); } }, Scheduler::Pipeline::RENDERER); + // COD4 Map Fixes + // The day map porting is perfect we should be able to remove these + Utils::Hook(0x546A09, FixSunShadowPartitionSize, HOOK_CALL).install()->quick(); + // Log broken materials Utils::Hook(0x0054CAAA, Renderer::StoreGfxBufContextPtrStub1, HOOK_JUMP).install()->quick(); Utils::Hook(0x0054CF8D, Renderer::StoreGfxBufContextPtrStub2, HOOK_JUMP).install()->quick(); @@ -510,6 +559,7 @@ namespace Components Renderer::r_drawModelNames = Game::Dvar_RegisterEnum("r_drawModelNames", values, 0, Game::DVAR_CHEAT, "Draw all model names"); Renderer::r_drawAABBTrees = Game::Dvar_RegisterBool("r_drawAabbTrees", false, Game::DVAR_CHEAT, "Draw aabb trees"); Renderer::r_playerDrawDebugDistance = Game::Dvar_RegisterInt("r_drawDebugDistance", 1000, 0, 50000, Game::DVAR_ARCHIVE, "r_draw debug functions draw distance, relative to the player"); + Renderer::r_forceTechnique = Game::Dvar_RegisterInt("r_forceTechnique", 0, 0, 14, Game::DVAR_NONE, "Force a base technique on the renderer"); }, Scheduler::Pipeline::MAIN); } diff --git a/src/Components/Modules/Renderer.hpp b/src/Components/Modules/Renderer.hpp index 11c799cd..c856376e 100644 --- a/src/Components/Modules/Renderer.hpp +++ b/src/Components/Modules/Renderer.hpp @@ -39,6 +39,9 @@ namespace Components static void DebugDrawModelBoundingBoxes(); static void DebugDrawModelNames(); static void DebugDrawAABBTrees(); + static void ForceTechnique(); + + static int FixSunShadowPartitionSize(Game::GfxCamera* camera, Game::GfxSunShadowMapMetrics* mapMetrics, Game::GfxSunShadow* sunShadow, Game::GfxSunShadowClip* clip, float* partitionFraction); static Utils::Signal EndRecoverDeviceSignal; static Utils::Signal BeginRecoverDeviceSignal; @@ -52,5 +55,6 @@ namespace Components static Dvar::Var r_drawModelNames; static Dvar::Var r_drawAABBTrees; static Dvar::Var r_playerDrawDebugDistance; + static Dvar::Var r_forceTechnique; }; } diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index 2defb49b..88220c49 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -225,6 +225,9 @@ namespace Components // Sanitize name for empty assets if (name[0] == ',') name.erase(name.begin()); + // Fix forward slashes for FXEffectDef (and probably other assets) + std::replace(name.begin(), name.end(), '\\', '/'); + if (this->findAsset(type, name) != -1 || this->findSubAsset(type, name).data) return true; if (type == Game::XAssetType::ASSET_TYPE_INVALID || type >= Game::XAssetType::ASSET_TYPE_COUNT) @@ -245,6 +248,9 @@ namespace Components asset.type = type; asset.header = assetHeader; + // Handle script strings + AssetHandler::ZoneMark(asset, this); + if (isSubAsset) { this->loadedSubAssets.push_back(asset); @@ -254,8 +260,6 @@ namespace Components this->loadedAssets.push_back(asset); } - // Handle script strings - AssetHandler::ZoneMark(asset, this); return true; } @@ -447,38 +451,30 @@ namespace Components Utils::Stream::ClearPointer(&zoneHeader.assetList.assets); // Increment ScriptStrings count (for empty script string) if available - if (!this->scriptStrings.empty()) - { - zoneHeader.assetList.stringList.count = this->scriptStrings.size() + 1; - Utils::Stream::ClearPointer(&zoneHeader.assetList.stringList.strings); - } + zoneHeader.assetList.stringList.count = this->scriptStrings.size() + 1; + Utils::Stream::ClearPointer(&zoneHeader.assetList.stringList.strings); // Write header this->buffer.save(&zoneHeader, sizeof(Game::ZoneHeader)); this->buffer.pushBlock(Game::XFILE_BLOCK_VIRTUAL); // Push main stream onto the stream stack // Write ScriptStrings, if available - if (!this->scriptStrings.empty()) + this->buffer.saveNull(4); + // Empty script string? + // This actually represents a NULL string, but as scriptString. + // So scriptString loading for NULL scriptStrings from fastfile results in a NULL scriptString. + // That's the reason why the count is incremented by 1, if scriptStrings are available. + + // Write ScriptString pointer table + for (std::size_t i = 0; i < this->scriptStrings.size(); ++i) { - this->buffer.saveNull(4); - // Empty script string? - // This actually represents a NULL string, but as scriptString. - // So scriptString loading for NULL scriptStrings from fastfile results in a NULL scriptString. - // That's the reason why the count is incremented by 1, if scriptStrings are available. + this->buffer.saveMax(4); + } - // Write ScriptString pointer table - for (std::size_t i = 0; i < this->scriptStrings.size(); ++i) - { - this->buffer.saveMax(4); - } - - this->buffer.align(Utils::Stream::ALIGN_4); - - // Write ScriptStrings - for (auto ScriptString : this->scriptStrings) - { - this->buffer.saveString(ScriptString.data()); - } + // Write ScriptStrings + for (auto ScriptString : this->scriptStrings) + { + this->buffer.saveString(ScriptString.data()); } // Align buffer (4 bytes) to get correct offsets for pointers @@ -530,7 +526,7 @@ namespace Components constexpr auto* data = "Built using the IW4x Zone:B:uilder Version 4"; auto dataLen = std::strlen(data); // + 1 is added by the save code - this->branding = { this->zoneName.data(), 0, static_cast(dataLen), data }; + this->branding = {this->zoneName.data(), 0, static_cast(dataLen), data}; if (this->findAsset(Game::XAssetType::ASSET_TYPE_RAWFILE, this->branding.name) != -1) { @@ -641,9 +637,9 @@ namespace Components } // Remap a scriptString to it's corresponding value in the local scriptString table. - void ZoneBuilder::Zone::mapScriptString(unsigned short* gameIndex) + void ZoneBuilder::Zone::mapScriptString(unsigned short& gameIndex) { - *gameIndex = 0xFFFF & this->scriptStringMap[*gameIndex]; + gameIndex = 0xFFFF & this->scriptStringMap[gameIndex]; } // Store a new name for a given asset @@ -1006,6 +1002,19 @@ namespace Components return ""; } + void ZoneBuilder::ReallocateLoadedSounds(void*& data, [[maybe_unused]] void* a2) + { + assert(data); + auto* sound = Utils::Hook::Get(0x112AE04); + auto length = sound->info.data_len; + auto allocatedSpace = Utils::Memory::AllocateArray(length); + memcpy_s(allocatedSpace, length, data, length); + + data = allocatedSpace; + sound->data = allocatedSpace; + sound->info.data_ptr = allocatedSpace; + } + ZoneBuilder::ZoneBuilder() { // ReSharper disable CppStaticAssertFailure @@ -1048,7 +1057,7 @@ namespace Components //Utils::Hook::Nop(0x5BB632, 5); // Don't load sounds - //Utils::Hook::Set(0x413430, 0xC3); + Utils::Hook(0x492EFC, ReallocateLoadedSounds, HOOK_CALL).install()->quick(); // Don't display errors when assets are missing (we might manually build those) Utils::Hook::Nop(0x5BB3F2, 5); @@ -1228,6 +1237,41 @@ namespace Components } }); + + AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, [[maybe_unused]] const std::string& name, [[maybe_unused]] bool* restrict) + { + if (type != Game::ASSET_TYPE_SOUND) + { + return; + } + + auto sound = asset.sound; + + for (size_t i = 0; i < sound->count; i++) + { + auto thisSound = sound->head[i]; + + if (thisSound.soundFile->type == Game::SAT_LOADED) + { + if (thisSound.soundFile->u.loadSnd->sound.data == nullptr) + { + // ouch + // This should never happen and will cause a memory leak + // Let's change it to a streamed sound instead + thisSound.soundFile->type = Game::SAT_STREAMED; + + auto virtualPath = std::filesystem::path(thisSound.soundFile->u.loadSnd->name); + + thisSound.soundFile->u.streamSnd.filename.info.raw.name = Utils::Memory::DuplicateString(virtualPath.filename().string()); + + auto dir = virtualPath.remove_filename().string(); + dir = dir.substr(0, dir.size() - 1); // remove / + thisSound.soundFile->u.streamSnd.filename.info.raw.dir = Utils::Memory::DuplicateString(dir); + } + } + } + }); + Command::Add("buildtechsets", [](Command::Params*) { Utils::IO::CreateDir("zone_source/techsets"); diff --git a/src/Components/Modules/ZoneBuilder.hpp b/src/Components/Modules/ZoneBuilder.hpp index ea18ed1a..33e61cc6 100644 --- a/src/Components/Modules/ZoneBuilder.hpp +++ b/src/Components/Modules/ZoneBuilder.hpp @@ -60,7 +60,7 @@ namespace Components int findScriptString(const std::string& str); void addRawAsset(Game::XAssetType type, void* ptr); - void mapScriptString(unsigned short* gameIndex); + void mapScriptString(unsigned short& gameIndex); void renameAsset(Game::XAssetType type, const std::string& asset, const std::string& newName); std::string getAssetName(Game::XAssetType type, const std::string& asset); @@ -138,6 +138,7 @@ namespace Components static void ReleaseTexture(Game::XAssetHeader header); static std::string FindMaterialByTechnique(const std::string& name); + static void ReallocateLoadedSounds(void*& data, void* a2); static int __stdcall EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/); static void HandleError(Game::errorParm_t code, const char* fmt, ...); diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index 933a133a..6efd7be6 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -1456,7 +1456,7 @@ namespace Components { Game::MaterialShaderArgument* arg = &argument[i]; - if (arg->type != D3DSHADER_PARAM_REGISTER_TYPE::D3DSPR_TEXTURE && arg->type != D3DSHADER_PARAM_REGISTER_TYPE::D3DSPR_ATTROUT) + if (arg->type != Game::MaterialShaderArgumentType::MTL_ARG_CODE_VERTEX_CONST && arg->type != Game::MaterialShaderArgumentType::MTL_ARG_CODE_PIXEL_CONST) { continue; } @@ -1730,7 +1730,7 @@ namespace Components { Game::GfxImageLoadDef* texture; char mapType; - char semantic; + Game::TextureSemantic semantic; char category; char flags; int cardMemory; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index d82acd5a..8c27e020 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -323,6 +323,7 @@ namespace Game PhysPreset*** varPhysPresetPtr = reinterpret_cast(0x112B378); MaterialPass** varMaterialPass = reinterpret_cast(0x112A960); snd_alias_list_t*** varsnd_alias_list_name = reinterpret_cast(0x112AF38); + MaterialVertexShader** varMaterialVertexShader = reinterpret_cast(0x112B338); FxElemField* s_elemFields = reinterpret_cast(0x73B848); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index a477a018..5d045c06 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -646,6 +646,7 @@ namespace Game extern PhysPreset*** varPhysPresetPtr; extern MaterialPass** varMaterialPass; extern snd_alias_list_t*** varsnd_alias_list_name; + extern MaterialVertexShader** varMaterialVertexShader; extern FxElemField* s_elemFields; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index c804fb48..d477e789 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -2,7 +2,6 @@ #define PROTOCOL 0x96 #define NUM_CUSTOM_CLASSES 15 -#define SEMANTIC_WATER_MAP 11 #define FX_ELEM_FIELD_COUNT 90 // This allows us to compile our structures in IDA, for easier reversing :3 @@ -96,6 +95,164 @@ namespace Game ASSET_TYPE_INVALID = -1, }; + enum surfType_t + { + R_SMODEL_SURFTYPE_RIGID = 0x0, + R_SMODEL_SURFTYPE_SKINNED = 0x1, + R_SMODEL_SURFTYPE_CACHED = 0x2, + R_SMODEL_SURFTYPE_PRETESS = 0x3, + R_SMODEL_SURFTYPE_COUNT = 0x4, + }; + + enum ShaderCodeConstants + { + CONST_SRC_CODE_MAYBE_DIRTY_PS_BEGIN = 0x0, + CONST_SRC_CODE_LIGHT_POSITION = 0x0, + CONST_SRC_CODE_LIGHT_DIFFUSE = 0x1, + CONST_SRC_CODE_LIGHT_SPECULAR = 0x2, + CONST_SRC_CODE_LIGHT_SPOTDIR = 0x3, + CONST_SRC_CODE_LIGHT_SPOTFACTORS = 0x4, + CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT = 0x5, + CONST_SRC_CODE_PARTICLE_CLOUD_COLOR = 0x6, + CONST_SRC_CODE_GAMETIME = 0x7, + CONST_SRC_CODE_MAYBE_DIRTY_PS_END = 0x8, + CONST_SRC_CODE_ALWAYS_DIRTY_PS_BEGIN = 0x8, + CONST_SRC_CODE_PIXEL_COST_FRACS = 0x8, + CONST_SRC_CODE_PIXEL_COST_DECODE = 0x9, + CONST_SRC_CODE_FILTER_TAP_0 = 0xA, + CONST_SRC_CODE_FILTER_TAP_1 = 0xB, + CONST_SRC_CODE_FILTER_TAP_2 = 0xC, + CONST_SRC_CODE_FILTER_TAP_3 = 0xD, + CONST_SRC_CODE_FILTER_TAP_4 = 0xE, + CONST_SRC_CODE_FILTER_TAP_5 = 0xF, + CONST_SRC_CODE_FILTER_TAP_6 = 0x10, + CONST_SRC_CODE_FILTER_TAP_7 = 0x11, + CONST_SRC_CODE_COLOR_MATRIX_R = 0x12, + CONST_SRC_CODE_COLOR_MATRIX_G = 0x13, + CONST_SRC_CODE_COLOR_MATRIX_B = 0x14, + CONST_SRC_CODE_SHADOWMAP_POLYGON_OFFSET = 0x15, + CONST_SRC_CODE_RENDER_TARGET_SIZE = 0x16, + CONST_SRC_CODE_ALWAYS_DIRTY_PS_END = 0x17, + CONST_SRC_CODE_FIXED_PS_BEGIN = 0x17, + CONST_SRC_CODE_DOF_EQUATION_VIEWMODEL_AND_FAR_BLUR = 0x17, + CONST_SRC_CODE_DOF_EQUATION_SCENE = 0x18, + CONST_SRC_CODE_DOF_LERP_SCALE = 0x19, + CONST_SRC_CODE_DOF_LERP_BIAS = 0x1A, + CONST_SRC_CODE_DOF_ROW_DELTA = 0x1B, + CONST_SRC_CODE_MOTION_MATRIX_X = 0x1C, + CONST_SRC_CODE_MOTION_MATRIX_Y = 0x1D, + CONST_SRC_CODE_MOTION_MATRIX_W = 0x1E, + CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION = 0x1F, + CONST_SRC_CODE_SHADOWMAP_SCALE = 0x20, + CONST_SRC_CODE_ZNEAR = 0x21, + CONST_SRC_CODE_LIGHTING_LOOKUP_SCALE = 0x22, + CONST_SRC_CODE_DEBUG_BUMPMAP = 0x23, + CONST_SRC_CODE_MATERIAL_COLOR = 0x24, + CONST_SRC_CODE_FOG = 0x25, + CONST_SRC_CODE_FOG_COLOR_LINEAR = 0x26, + CONST_SRC_CODE_FOG_COLOR_GAMMA = 0x27, + CONST_SRC_CODE_FOG_SUN_CONSTS = 0x28, + CONST_SRC_CODE_FOG_SUN_COLOR_LINEAR = 0x29, + CONST_SRC_CODE_FOG_SUN_COLOR_GAMMA = 0x2A, + CONST_SRC_CODE_FOG_SUN_DIR = 0x2B, + CONST_SRC_CODE_GLOW_SETUP = 0x2C, + CONST_SRC_CODE_GLOW_APPLY = 0x2D, + CONST_SRC_CODE_COLOR_BIAS = 0x2E, + CONST_SRC_CODE_COLOR_TINT_BASE = 0x2F, + CONST_SRC_CODE_COLOR_TINT_DELTA = 0x30, + CONST_SRC_CODE_COLOR_TINT_QUADRATIC_DELTA = 0x31, + CONST_SRC_CODE_OUTDOOR_FEATHER_PARMS = 0x32, + CONST_SRC_CODE_ENVMAP_PARMS = 0x33, + CONST_SRC_CODE_SUN_SHADOWMAP_PIXEL_ADJUST = 0x34, + CONST_SRC_CODE_SPOT_SHADOWMAP_PIXEL_ADJUST = 0x35, + CONST_SRC_CODE_COMPOSITE_FX_DISTORTION = 0x36, + CONST_SRC_CODE_POSTFX_FADE_EFFECT = 0x37, + CONST_SRC_CODE_VIEWPORT_DIMENSIONS = 0x38, + CONST_SRC_CODE_FRAMEBUFFER_READ = 0x39, + CONST_SRC_CODE_FIXED_PS_END = 0x3A, + CONST_SRC_CODE_NON_PS_BEGIN = 0x3A, + CONST_SRC_CODE_BASE_LIGHTING_COORDS = 0x3A, + CONST_SRC_CODE_LIGHT_PROBE_AMBIENT = 0x3B, + CONST_SRC_CODE_NEARPLANE_ORG = 0x3C, + CONST_SRC_CODE_NEARPLANE_DX = 0x3D, + CONST_SRC_CODE_NEARPLANE_DY = 0x3E, + CONST_SRC_CODE_CLIP_SPACE_LOOKUP_SCALE = 0x3F, + CONST_SRC_CODE_CLIP_SPACE_LOOKUP_OFFSET = 0x40, + CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX0 = 0x41, + CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX1 = 0x42, + CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX2 = 0x43, + CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR0 = 0x44, + CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR1 = 0x45, + CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR2 = 0x46, + CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM0 = 0x47, + CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM1 = 0x48, + CONST_SRC_CODE_DEPTH_FROM_CLIP = 0x49, + CONST_SRC_CODE_CODE_MESH_ARG_0 = 0x4A, + CONST_SRC_CODE_CODE_MESH_ARG_1 = 0x4B, + CONST_SRC_CODE_CODE_MESH_ARG_LAST = 0x4B, + CONST_SRC_CODE_NON_PS_END = 0x4C, + CONST_SRC_CODE_COUNT_FLOAT4 = 0x4C, + CONST_SRC_FIRST_CODE_MATRIX = 0x4C, + CONST_SRC_CODE_VIEW_MATRIX = 0x4C, + CONST_SRC_CODE_INVERSE_VIEW_MATRIX = 0x4D, + CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX = 0x4E, + CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX = 0x4F, + CONST_SRC_CODE_PROJECTION_MATRIX = 0x50, + CONST_SRC_CODE_INVERSE_PROJECTION_MATRIX = 0x51, + CONST_SRC_CODE_TRANSPOSE_PROJECTION_MATRIX = 0x52, + CONST_SRC_CODE_INVERSE_TRANSPOSE_PROJECTION_MATRIX = 0x53, + CONST_SRC_CODE_VIEW_PROJECTION_MATRIX = 0x54, + CONST_SRC_CODE_INVERSE_VIEW_PROJECTION_MATRIX = 0x55, + CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX = 0x56, + CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX = 0x57, + CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX = 0x58, + CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX = 0x59, + CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX = 0x5A, + CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX = 0x5B, + CONST_SRC_CODE_WORLD_OUTDOOR_LOOKUP_MATRIX = 0x5C, + CONST_SRC_CODE_INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX = 0x5D, + CONST_SRC_CODE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX = 0x5E, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX = 0x5F, + CONST_SRC_CODE_WORLD_MATRIX0 = 0x60, + CONST_SRC_CODE_INVERSE_WORLD_MATRIX0 = 0x61, + CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX0 = 0x62, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX0 = 0x63, + CONST_SRC_CODE_WORLD_VIEW_MATRIX0 = 0x64, + CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX0 = 0x65, + CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX0 = 0x66, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX0 = 0x67, + CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX0 = 0x68, + CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX0 = 0x69, + CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0 = 0x6A, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0 = 0x6B, + CONST_SRC_CODE_WORLD_MATRIX1 = 0x6C, + CONST_SRC_CODE_INVERSE_WORLD_MATRIX1 = 0x6D, + CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX1 = 0x6E, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX1 = 0x6F, + CONST_SRC_CODE_WORLD_VIEW_MATRIX1 = 0x70, + CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX1 = 0x71, + CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX1 = 0x72, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX1 = 0x73, + CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX1 = 0x74, + CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX1 = 0x75, + CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1 = 0x76, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1 = 0x77, + CONST_SRC_CODE_WORLD_MATRIX2 = 0x78, + CONST_SRC_CODE_INVERSE_WORLD_MATRIX2 = 0x79, + CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX2 = 0x7A, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX2 = 0x7B, + CONST_SRC_CODE_WORLD_VIEW_MATRIX2 = 0x7C, + CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX2 = 0x7D, + CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX2 = 0x7E, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX2 = 0x7F, + CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX2 = 0x80, + CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX2 = 0x81, + CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2 = 0x82, + CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2 = 0x83, + CONST_SRC_TOTAL_COUNT = 0x84, + CONST_SRC_NONE = 0x85, + }; + enum FsThread { FS_THREAD_MAIN = 0x0, @@ -107,6 +264,23 @@ namespace Game FS_THREAD_INVALID = 0x6, }; + enum TextureSemantic : char + { + TS_2D = 0x0, + TS_FUNCTION = 0x1, + TS_COLOR_MAP = 0x2, + TS_DETAIL_MAP = 0x3, + TS_UNUSED_2 = 0x4, + TS_NORMAL_MAP = 0x5, + TS_UNUSED_3 = 0x6, + TS_UNUSED_4 = 0x7, + TS_SPECULAR_MAP = 0x8, + TS_UNUSED_5 = 0x9, + TS_UNUSED_6 = 0xA, + TS_WATER_MAP = 0xB, + }; + + enum materialSurfType_t { SURF_TYPE_DEFAULT, @@ -252,6 +426,19 @@ namespace Game SS_GAME = 0x2, }; + enum GfxLightType + { + GFX_LIGHT_TYPE_NONE = 0x0, + GFX_LIGHT_TYPE_DIR = 0x1, + GFX_LIGHT_TYPE_SPOT = 0x2, + GFX_LIGHT_TYPE_OMNI = 0x3, + GFX_LIGHT_TYPE_COUNT = 0x4, + GFX_LIGHT_TYPE_DIR_SHADOWMAP = 0x4, + GFX_LIGHT_TYPE_SPOT_SHADOWMAP = 0x5, + GFX_LIGHT_TYPE_OMNI_SHADOWMAP = 0x6, + GFX_LIGHT_TYPE_COUNT_WITH_SHADOWMAP_VERSIONS = 0x7, + }; + enum errorParm_t { ERR_FATAL = 0x0, @@ -924,11 +1111,11 @@ namespace Game unsigned __int64 packed; }; - struct /*__declspec(align(4))*/ MaterialInfo + struct MaterialInfo { const char* name; - char gameFlags; - char sortKey; + unsigned char gameFlags; + unsigned char sortKey; unsigned char textureAtlasRowCount; unsigned char textureAtlasColumnCount; GfxDrawSurf drawSurf; @@ -994,6 +1181,23 @@ namespace Game MaterialPixelShaderProgram prog; }; + + enum MaterialShaderArgumentType : unsigned __int16 + { + MTL_ARG_MATERIAL_VERTEX_CONST = 0x0, + MTL_ARG_LITERAL_VERTEX_CONST = 0x1, + MTL_ARG_MATERIAL_PIXEL_SAMPLER = 0x2, + MTL_ARG_CODE_PRIM_BEGIN = 0x3, + MTL_ARG_CODE_VERTEX_CONST = 0x3, + MTL_ARG_CODE_PIXEL_SAMPLER = 0x4, + MTL_ARG_CODE_PIXEL_CONST = 0x5, + MTL_ARG_CODE_PRIM_END = 0x6, + MTL_ARG_MATERIAL_PIXEL_CONST = 0x6, + MTL_ARG_LITERAL_PIXEL_CONST = 0x7, + MTL_ARG_COUNT = 0x8, + }; + + struct MaterialArgumentCodeConst { unsigned __int16 index; @@ -1003,7 +1207,7 @@ namespace Game union MaterialArgumentDef { - const float* literalConst; + float* literalConst; MaterialArgumentCodeConst codeConst; unsigned int codeSampler; unsigned int nameHash; @@ -1011,7 +1215,7 @@ namespace Game struct MaterialShaderArgument { - unsigned __int16 type; + MaterialShaderArgumentType type; unsigned __int16 dest; MaterialArgumentDef u; }; @@ -1089,8 +1293,6 @@ namespace Game int sprintStartMaxLength; }; - - /* 1018 */ struct MantleState { float yaw; @@ -1099,7 +1301,6 @@ namespace Game int flags; }; - /* 1019 */ struct PlayerActiveWeaponState { int weapAnim; @@ -1111,7 +1312,6 @@ namespace Game unsigned int weaponShotCount; }; - /* 1020 */ struct PlayerEquippedWeaponState { bool usedBefore; @@ -1120,14 +1320,12 @@ namespace Game bool needsRechamber[2]; }; - /* 1021 */ struct GlobalAmmo { int ammoType; int ammoCount; }; - /* 1022 */ struct ClipAmmo { int clipIndex; @@ -1142,7 +1340,6 @@ namespace Game WEAPON_HAND_DEFAULT = 0x0, }; - /* 1023 */ struct PlayerWeaponCommonState { int offHandIndex; @@ -1174,13 +1371,11 @@ namespace Game ACTIONSLOTTYPECOUNT = 0x4, }; - /* 1024 */ struct ActionSlotParam_SpecifyWeapon { unsigned int index; }; - /* 1025 */ struct ActionSlotParam { ActionSlotParam_SpecifyWeapon specifyWeapon; @@ -1197,7 +1392,6 @@ namespace Game OBJST_NUMSTATES = 0x6, }; - /* 1026 */ struct objective_t { objectiveState_t state; @@ -1207,8 +1401,6 @@ namespace Game int icon; }; - - /* 104 */ enum he_type_t { HE_TYPE_FREE = 0x0, @@ -1238,7 +1430,6 @@ namespace Game char a; }; - /* 1028 */ union hudelem_color_t { hud_color __s0; @@ -1941,7 +2132,7 @@ namespace Game { GfxTexture texture; char mapType; - char semantic; + TextureSemantic semantic; char category; bool useSrgbReads; Picmip picmip; @@ -1995,7 +2186,7 @@ namespace Game char nameStart; char nameEnd; char samplerState; - char semantic; + TextureSemantic semantic; MaterialTextureDefInfo u; }; @@ -2006,6 +2197,87 @@ namespace Game float literal[4]; }; + enum GfxSurfaceStatebitOp0 : unsigned int + { + GFXS0_SRCBLEND_RGB_SHIFT = 0x0, + GFXS0_SRCBLEND_RGB_MASK = 0xF, + GFXS0_DSTBLEND_RGB_SHIFT = 0x4, + GFXS0_DSTBLEND_RGB_MASK = 0xF0, + GFXS0_BLENDOP_RGB_SHIFT = 0x8, + GFXS0_BLENDOP_RGB_MASK = 0x700, + GFXS0_BLEND_RGB_MASK = 0x7FF, + GFXS0_ATEST_DISABLE = 0x800, + GFXS0_ATEST_GT_0 = 0x1000, + GFXS0_ATEST_LT_128 = 0x2000, + GFXS0_ATEST_GE_128 = 0x3000, + GFXS0_ATEST_MASK = 0x3000, + GFXS0_CULL_SHIFT = 0xE, + GFXS0_CULL_NONE = 0x4000, + GFXS0_CULL_BACK = 0x8000, + GFXS0_CULL_FRONT = 0xC000, + GFXS0_CULL_MASK = 0xC000, + GFXS0_SRCBLEND_ALPHA_SHIFT = 0x10, + GFXS0_SRCBLEND_ALPHA_MASK = 0xF0000, + GFXS0_DSTBLEND_ALPHA_SHIFT = 0x14, + GFXS0_DSTBLEND_ALPHA_MASK = 0xF00000, + GFXS0_BLENDOP_ALPHA_SHIFT = 0x18, + GFXS0_BLENDOP_ALPHA_MASK = 0x7000000, + GFXS0_BLEND_ALPHA_MASK = 0x7FF0000, + GFXS0_COLORWRITE_RGB = 0x8000000, + GFXS0_COLORWRITE_ALPHA = 0x10000000, + GFXS0_COLORWRITE_MASK = 0x18000000, + GFXS0_GAMMAWRITE = 0x40000000, + GFXS0_POLYMODE_LINE = 0x80000000 + }; + + enum GfxSurfaceStatebitOp1 : unsigned int + { + GFXS1_DEPTHWRITE = 0x1, + GFXS1_DEPTHTEST_DISABLE = 0x2, + GFXS1_DEPTHTEST_SHIFT = 0x2, + GFXS1_DEPTHTEST_ALWAYS = 0x0, + GFXS1_DEPTHTEST_LESS = 0x4, + GFXS1_DEPTHTEST_EQUAL = 0x8, + GFXS1_DEPTHTEST_LESSEQUAL = 0xC, + GFXS1_DEPTHTEST_MASK = 0xC, + GFXS1_POLYGON_OFFSET_SHIFT = 0x4, + GFXS1_POLYGON_OFFSET_0 = 0x0, + GFXS1_POLYGON_OFFSET_1 = 0x10, + GFXS1_POLYGON_OFFSET_2 = 0x20, + GFXS1_POLYGON_OFFSET_SHADOWMAP = 0x30, + GFXS1_POLYGON_OFFSET_MASK = 0x30, + GFXS1_STENCIL_FRONT_ENABLE = 0x40, + GFXS1_STENCIL_BACK_ENABLE = 0x80, + GFXS1_STENCIL_MASK = 0xC0, + GFXS1_STENCIL_FRONT_PASS_SHIFT = 0x8, + GFXS1_STENCIL_FRONT_FAIL_SHIFT = 0xB, + GFXS1_STENCIL_FRONT_ZFAIL_SHIFT = 0xE, + GFXS1_STENCIL_FRONT_FUNC_SHIFT = 0x11, + GFXS1_STENCIL_FRONT_MASK = 0xFFF00, + GFXS1_STENCIL_BACK_PASS_SHIFT = 0x14, + GFXS1_STENCIL_BACK_FAIL_SHIFT = 0x17, + GFXS1_STENCIL_BACK_ZFAIL_SHIFT = 0x1A, + GFXS1_STENCIL_BACK_FUNC_SHIFT = 0x1D, + GFXS1_STENCIL_BACK_MASK = 0xFFF00000, + GFXS1_STENCILFUNC_FRONTBACK_MASK = 0xE00E0000, + GFXS1_STENCILOP_FRONTBACK_MASK = 0x1FF1FF00, + }; + + enum GfxStencilOp + { + GFXS_STENCILOP_KEEP = 0x0, + GFXS_STENCILOP_ZERO = 0x1, + GFXS_STENCILOP_REPLACE = 0x2, + GFXS_STENCILOP_INCRSAT = 0x3, + GFXS_STENCILOP_DECRSAT = 0x4, + GFXS_STENCILOP_INVERT = 0x5, + GFXS_STENCILOP_INCR = 0x6, + GFXS_STENCILOP_DECR = 0x7, + + GFXS_STENCILOP_COUNT, + GFXS_STENCILOP_MASK = 0x7 + }; + struct GfxStateBits { unsigned int loadBits[2]; @@ -2066,24 +2338,24 @@ namespace Game struct XModel { const char* name; - char numBones; - char numRootBones; + unsigned char numBones; + unsigned char numRootBones; unsigned char numsurfs; - char lodRampType; + unsigned char lodRampType; float scale; unsigned int noScalePartBits[6]; unsigned __int16* boneNames; - char* parentList; - __int16* quats; + unsigned char *parentList; + short* quats; float* trans; - char* partClassification; + unsigned char* partClassification; DObjAnimMat* baseMat; Material** materialHandles; XModelLodInfo lodInfo[4]; - char maxLoadedLod; - char numLods; - char collLod; - char flags; + unsigned char maxLoadedLod; + unsigned char numLods; + unsigned char collLod; + unsigned char flags; XModelCollSurf_s* collSurfs; int numCollSurfs; int contents; @@ -2226,6 +2498,19 @@ namespace Game SpeakerMap* speakerMap; }; + struct Poly + { + float(*pts)[3]; + unsigned int ptCount; + }; + + enum SunShadowPartition + { + R_SUNSHADOW_NEAR = 0x0, + R_SUNSHADOW_FAR = 0x1, + R_SUNSHADOW_PARTITION_COUNT = 0x2, + }; + struct snd_alias_list_t { const char* aliasName; @@ -2364,7 +2649,7 @@ namespace Game TriggerSlab* slabs; }; - struct /*__declspec(align(2))*/ Stage + struct Stage { const char* name; float origin[3]; @@ -2910,7 +3195,7 @@ namespace Game unsigned int segmentCount; }; - struct /*__declspec(align(2))*/ G_GlassPiece + struct G_GlassPiece { unsigned __int16 damageTaken; unsigned __int16 collapseTime; @@ -3242,6 +3527,13 @@ namespace Game GfxLightGridColors* colors; }; + struct GfxSModelSurfVisDataHeader + { + XSurface* surfs; + unsigned __int16 smodelCount; + unsigned __int16 smodelIndexes[1]; + }; + struct GfxBrushModelWritable { Bounds bounds; @@ -3359,10 +3651,10 @@ namespace Game struct GfxSurfaceLightingAndFlagsFields { - char lightmapIndex; - char reflectionProbeIndex; - char primaryLightIndex; - char flags; + unsigned char lightmapIndex; + unsigned char reflectionProbeIndex; + unsigned char primaryLightIndex; + unsigned char flags; }; union GfxSurfaceLightingAndFlags @@ -3396,10 +3688,10 @@ namespace Game XModel* model; unsigned __int16 cullDist; unsigned __int16 lightingHandle; - char reflectionProbeIndex; - char primaryLightIndex; - char flags; - char firstMtlSkinIndex; + unsigned char reflectionProbeIndex; + unsigned char primaryLightIndex; + unsigned char flags; + unsigned char firstMtlSkinIndex; GfxColor groundLighting; unsigned __int16 cacheId[4]; }; @@ -3419,18 +3711,87 @@ namespace Game unsigned int emissiveSurfsEnd; unsigned int smodelVisDataCount; unsigned int surfaceVisDataCount; - char* smodelVisData[3]; - char* surfaceVisData[3]; + unsigned char* smodelVisData[3]; + unsigned char* surfaceVisData[3]; unsigned __int16* sortedSurfIndex; GfxStaticModelInst* smodelInsts; GfxSurface* surfaces; GfxSurfaceBounds* surfacesBounds; GfxStaticModelDrawInst* smodelDrawInsts; GfxDrawSurf* surfaceMaterials; - unsigned int* surfaceCastsSunShadow; + unsigned int* surfaceCastsSunShadow; volatile int usageCount; }; + struct GfxSModelSurfHeaderFields + { + char reflectionProbeIndex; + char sceneLightIndex; + unsigned __int16 materialSortedIndex : 12; + unsigned __int16 visDataRefCountLessOne : 4; + }; + + union GfxSModelSurfHeader + { + GfxSModelSurfHeaderFields fields; + unsigned int packed; + unsigned __int16 array[2]; + }; + + struct GfxSModelSurfVisDataRefFields + { + unsigned __int16 surfIndex : 4; + unsigned __int16 visDataIndexPacked : 12; + }; + + union GfxSModelSurfVisDataRef + { + GfxSModelSurfVisDataRefFields fields; + unsigned __int16 packed; + }; + + struct GfxSModelSurf + { + GfxSModelSurfHeader header; + GfxSModelSurfVisDataRef visDataRefs[1]; + }; + + struct GfxSModelSurfDelaySortFields + { + unsigned __int16 unused; + GfxSModelSurfVisDataRef visDataRef; + GfxSModelSurfHeader header; + }; + + union GfxSModelSurfDelaySort + { + GfxSModelSurfDelaySortFields fields; + unsigned __int64 packed; + }; + + struct GfxSModelSurfBuildList + { + GfxSModelSurfHeader lastSurfHeader; + GfxSModelSurf* lastSModelSurf; + unsigned int visDataRefCount; + char* surfDataBegin; + char* surfDataPos; + char* surfDataEnd; + GfxSModelSurfHeader minDelaySortKey; + GfxSModelSurfDelaySort* delaySurfList; + unsigned int delaySurfCount; + unsigned int delaySurfLimit; + }; + + struct GfxSModelSurfDrawData + { + unsigned int shadowCasterMaterialIndex; + char* visData; + unsigned int visDataUsed; + unsigned int visDataLimit; + GfxSModelSurfBuildList buildList[4][4]; + }; + struct GfxWorldDpvsDynamic { unsigned int dynEntClientWordCount[2]; @@ -5162,7 +5523,6 @@ namespace Game AddonMapEnts* addonMapEnts; }; - /* 9210 */ struct weaponParms { float forward[3]; @@ -5318,6 +5678,27 @@ namespace Game XNKEY keyExchangeKey; }; + struct GfxSunShadowMapMetrics + { + unsigned int pixelsPerTile; + unsigned int tilesPerTexture; + unsigned int usefulSize; + unsigned int minCoord; + float nearClip; + float farClip; + }; + + struct GfxSunShadowProjectionSetup + { + float sunAxis[3][3]; + float nearShadowMinDist; + float frustumRayDistToEdgeOfNearMap; + float shadowOrg[2]; + float shadowOrgPixelCenter[2]; + float snappedShadowOrg[2][2]; + float sampleSize[2]; + }; + struct mapArena_t { char uiName[32]; @@ -6926,7 +7307,7 @@ namespace Game R_RENDERTARGET_NONE = 0xD, }; - struct /*__declspec(align(16))*/ GfxCmdBufState + struct GfxCmdBufState { char refSamplerState[16]; unsigned int samplerState[16]; @@ -6962,10 +7343,44 @@ namespace Game MaterialTechniqueType origTechType; }; + enum MaterialTextureSource : unsigned int + { + TEXTURE_SRC_CODE_BLACK = 0x0, + TEXTURE_SRC_CODE_WHITE = 0x1, + TEXTURE_SRC_CODE_IDENTITY_NORMAL_MAP = 0x2, + TEXTURE_SRC_CODE_MODEL_LIGHTING = 0x3, + TEXTURE_SRC_CODE_LIGHTMAP_PRIMARY = 0x4, + TEXTURE_SRC_CODE_LIGHTMAP_SECONDARY = 0x5, + TEXTURE_SRC_CODE_SHADOWMAP_SUN = 0x6, + TEXTURE_SRC_CODE_SHADOWMAP_SPOT = 0x7, + TEXTURE_SRC_CODE_FEEDBACK = 0x8, + TEXTURE_SRC_CODE_RESOLVED_POST_SUN = 0x9, + TEXTURE_SRC_CODE_RESOLVED_SCENE = 0xA, + TEXTURE_SRC_CODE_POST_EFFECT_0 = 0xB, + TEXTURE_SRC_CODE_POST_EFFECT_1 = 0xC, + TEXTURE_SRC_CODE_LIGHT_ATTENUATION = 0xD, + TEXTURE_SRC_CODE_OUTDOOR = 0xE, + TEXTURE_SRC_CODE_FLOATZ = 0xF, + TEXTURE_SRC_CODE_PROCESSED_FLOATZ = 0x10, + TEXTURE_SRC_CODE_RAW_FLOATZ = 0x11, + TEXTURE_SRC_CODE_HALF_PARTICLES = 0x12, + TEXTURE_SRC_CODE_HALF_PARTICLES_Z = 0x13, + TEXTURE_SRC_CODE_CASE_TEXTURE = 0x14, + TEXTURE_SRC_CODE_CINEMATIC_Y = 0x15, + TEXTURE_SRC_CODE_CINEMATIC_CR = 0x16, + TEXTURE_SRC_CODE_CINEMATIC_CB = 0x17, + TEXTURE_SRC_CODE_CINEMATIC_A = 0x18, + TEXTURE_SRC_CODE_REFLECTION_PROBE = 0x19, + TEXTURE_SRC_CODE_ALTERNATE_SCENE = 0x1A, + TEXTURE_SRC_CODE_COUNT = 0x1B, + }; + + struct GfxCmdBufSourceState; + struct GfxCmdBufContext { - /*GfxCmdBufSourceState*/ void* source; - GfxCmdBufState* state; + GfxCmdBufSourceState *source; + GfxCmdBufState *state; }; struct GfxDrawGroupSetupFields @@ -7058,6 +7473,306 @@ namespace Game float sunShadowPixelAdjust[4]; }; + struct GfxMatrix + { + float m[4][4]; + }; + + struct GfxCodeMatrices + { + GfxMatrix matrix[56]; + }; + + struct GfxCamera + { + float origin[3]; + float axis[3][3]; + float subWindowMins[2]; + float subWindowMaxs[2]; + float tanHalfFovX; + float tanHalfFovY; + float zNear; + float depthHackNearClip; + }; + + struct GfxViewParms + { + GfxMatrix viewMatrix; + GfxMatrix projectionMatrix; + GfxMatrix viewProjectionMatrix; + GfxMatrix inverseViewProjectionMatrix; + GfxCamera camera; + }; + + struct GfxBackEndData; + struct GfxCmdBufInput + { + float consts[76][4]; + GfxImage* codeImages[27]; + char codeImageSamplerStates[27]; + GfxBackEndData* data; + }; + + + enum GfxViewMode + { + VIEW_MODE_NONE = 0x0, + VIEW_MODE_3D = 0x1, + VIEW_MODE_2D = 0x2, + VIEW_MODE_IDENTITY = 0x3, + }; + + enum GfxViewportBehavior + { + GFX_USE_VIEWPORT_FOR_VIEW = 0x0, + GFX_USE_VIEWPORT_FULL = 0x1, + }; + + enum ShadowType + { + SHADOW_NONE = 0x0, + SHADOW_MAP = 0x1, + }; + + struct GfxDepthOfField + { + float viewModelStart; + float viewModelEnd; + float nearStart; + float nearEnd; + float farStart; + float farEnd; + float nearBlur; + float farBlur; + }; + + struct GfxFilm + { + bool enabled; + float brightness; + float contrast; + float desaturation; + float desaturationDark; + bool invert; + float tintDark[3]; + float tintMedium[3]; + float tintLight[3]; + }; + + struct GfxGlow + { + bool enabled; + float bloomCutoff; + float bloomDesaturation; + float bloomIntensity; + float radius; + }; + + struct GfxLightScale + { + float diffuseScale; + float specularScale; + }; + + struct GfxStageInfo + { + Stage activeStage; + bool activeStageValid; + }; + + struct GfxCompositeFx + { + GfxFilm film; + float distortionScale[3]; + float blurRadius; + float distortionMagnitude; + float frameRate; + int lastUpdate; + int frame; + int startMSec; + int currentTime; + int duration; + bool enabled; + bool scriptEnabled; + }; + + struct GfxVertexBufferState + { + volatile int used; + int total; + IDirect3DVertexBuffer9* buffer; + char* verts; + }; + + struct GfxMeshData + { + unsigned int indexCount; + unsigned int totalIndexCount; + unsigned __int16* indices; + GfxVertexBufferState vb; + unsigned int vertSize; + }; + + struct GfxQuadMeshData + { + float x; + float y; + float width; + float height; + GfxMeshData meshData; + }; + + struct GfxSparkSurfList + { + GfxSparkSurf* surfs; + unsigned int count; + }; + + enum GfxCodeSurfListType + { + GFX_CODE_SURFLIST_INVALID = -1, + GFX_CODE_SURFLIST_TRANS = 0x0, + GFX_CODE_SURFLIST_EMISSIVE = 0x1, + GFX_CODE_SURFLIST_TYPE_COUNT = 0x2, + }; + + + struct GfxViewInfo; + + struct GfxDrawListInfo + { + MaterialTechniqueType baseTechType; + GfxViewInfo* viewInfo; + float eyeOffset[3]; + unsigned int sceneLightIndex; + int cameraView; + GfxCodeSurfListType codeSurfListType; + }; + + struct GfxBspSurfList + { + unsigned int count; + const unsigned __int16* stream; + }; + + struct GfxSModelSurfList + { + unsigned int surfDataBytes; + const char* surfData; + const char* visData; + }; + + struct GfxDrawSurfList + { + GfxDrawSurf* array; + unsigned int count; + }; + + struct GfxPreTessSurf + { + GfxDrawGroupSetup drawGroup; + char lightmapIndex; + char reflectionProbeIndex; + unsigned __int16 triCount; + unsigned int baseIndex; + unsigned int firstVertex; + IDirect3DVertexBuffer9* vb; + unsigned int vertexCount; + }; + + struct GfxPreTessSurfList + { + GfxPreTessSurf* surfs; + unsigned int count; + }; + + struct GfxCodeSurfList + { + GfxCodeSurf* surfs; + unsigned int count; + }; + + struct GfxMarkSurfList + { + GfxMarkSurf* surfs; + unsigned int count; + }; + + struct GfxGlassSurfList + { + GfxGlassSurf* surfs; + unsigned int count; + }; + + struct GfxScaledPlacement + { + GfxPlacement base; + float scale; + }; + + struct GfxParticleCloud + { + GfxScaledPlacement placement; + float endpos[3]; + GfxColor color; + float radius[2]; + unsigned int flags; + float timeOffset; + }; + + struct GfxCloudSurfList + { + GfxParticleCloud* particles; + GfxCloudSurf* surfs; + unsigned int count; + }; + + struct GfxDrawList + { + GfxBspSurfList bspSurfList; + GfxPreTessSurfList bspPreTessSurfList; + GfxSModelSurfList smodelSurfList[4]; + GfxDrawSurfList drawSurfList; + GfxCodeSurfList codeSurfList; + GfxMarkSurfList markSurfList; + GfxGlassSurfList glassSurfList; + GfxCloudSurfList cloudSurfList; + GfxSparkSurfList sparkSurfList; + GfxDrawListInfo info; + }; + + struct GfxViewInfo + { + GfxViewParms viewParms; + GfxViewport sceneViewport; + GfxViewport displayViewport; + GfxViewport scissorViewport; + GfxSceneDef sceneDef; + ShadowType dynamicShadowType; + char floatZUsage; + bool needsDistortionResolve; + bool viewModelHasDistortion; + char forceSunShadowsGenerate; + unsigned int sceneLightCount; + float blurRadius; + float frustumPlanes[4][4]; + GfxDepthOfField dof; + GfxFilm film; + GfxGlow glow; + GfxLightScale charPrimaryLightScale; + GfxStageInfo stageInfo; + GfxCompositeFx waterSheetingFx; + const void* displayCmds; + GfxQuadMeshData* fullSceneViewMesh; + GfxDrawList drawList[10]; + //__declspec(align(16)) GfxCmdBufInput input; + GfxRenderTargetId renderTargetId; + bool useShadows; + unsigned int sunShadowResolution; + GfxRenderTargetId sunShadowRenderTargetId; + unsigned int sunShadowTileCount; + }; + struct GfxLight { char type; @@ -7149,10 +7864,31 @@ namespace Game char reflectionProbeIndex; }; - struct GfxScaledPlacement + struct GfxCmdBufSourceState { - GfxPlacement base; - float scale; + GfxCodeMatrices matrices; + GfxCmdBufInput input; + GfxViewParms viewParms; + float eyeOffset[4]; + GfxMatrix shadowLookupMatrix; + unsigned __int16 constVersions[132]; + unsigned __int16 matrixVersions[14]; + unsigned int sceneLightForShadowLookupMatrix; + GfxPlacement* objectPlacement[3]; + GfxViewParms* viewParms3D; + unsigned int depthHackFlags; + GfxScaledPlacement skinnedPlacement; + int cameraView; + GfxViewMode viewMode; + GfxSceneDef sceneDef; + GfxViewport sceneViewport; + float materialTime; + GfxViewportBehavior viewportBehavior; + int renderTargetWidth; + int renderTargetHeight; + bool viewportIsDirty; + unsigned int sceneLightIndex; + bool useHeroLighting; }; struct GfxSceneModel @@ -9179,6 +9915,398 @@ namespace Game ET_EVENTS = 0x12, }; + struct GfxBackEndPrimitiveData + { + int hasSunDirChanged; + }; + + struct GfxFog + { + int startTime; + int finishTime; + GfxColor color; + float fogStart; + float density; + float fogMaxOpacity; + bool sunFogEnabled; + GfxColor sunColor; + float sunDir[3]; + float sunBeginFadeAngle; + float sunEndFadeAngle; + float sunFogScale; + }; + + struct GfxCmdHeader + { + unsigned __int16 id; + unsigned __int16 byteCount; + }; + + struct GfxCmdArray + { + char* cmds; + int usedTotal; + int usedCritical; + GfxCmdHeader* lastCmd; + }; + + struct GfxCmdBuf + { + IDirect3DDevice9* device; + }; + + struct GfxDrawCallOutput + { + GfxCmdBuf cmdBuf; + }; + + struct __declspec(align(4)) GfxDebugPoly + { + float color[4]; + int firstVert; + int vertCount; + bool outline; + }; + + struct GfxDebugPlume + { + float origin[3]; + float color[4]; + int score; + int startTime; + int duration; + }; + + struct DebugGlobals + { + float(*verts)[3]; + int vertCount; + int vertLimit; + GfxDebugPoly* polys; + int polyCount; + int polyLimit; + trDebugString_t* strings; + int stringCount; + int stringLimit; + trDebugString_t* externStrings; + int externStringCount; + int externMaxStringCount; + trDebugLine_t* lines; + int lineCount; + int lineLimit; + trDebugLine_t* externLines; + int externLineCount; + int externMaxLineCount; + GfxDebugPlume* plumes; + int plumeCount; + int plumeLimit; + }; + + struct GfxSunShadowProjection + { + float switchPartition[4]; + float shadowmapScale[4]; + }; + + struct GfxSunShadowOverlaySetup + { + float shadowOrg[2]; + float frustumShadowRays[4][2]; + unsigned int clipPlaneCount[2]; + float clipPlanes[2][8][3]; + }; + + struct GfxViewportParms + { + GfxViewport viewport; + GfxViewParms viewParms; + }; + + struct GfxSunShadowPartition + { + GfxViewportParms viewportParms; + }; + + struct GfxSunShadow + { + GfxMatrix lookupMatrix; + GfxSunShadowProjection sunProj; + GfxSunShadowPartition partition[2]; + GfxSunShadowOverlaySetup overlaySetup; + }; + + struct GfxSpotShadowSceneLight + { + GfxMatrix lookupMatrix; + float fade; + GfxImage* image; + }; + + struct GfxDrawSurfIter + { + GfxDrawSurf* current; + GfxDrawSurf* end; + GfxDrawSurf* mark; + }; + + struct GfxCodeSurfIter + { + GfxCodeSurf* current; + GfxCodeSurf* end; + GfxCodeSurf* mark; + }; + + struct GfxMarkSurfIter + { + GfxMarkSurf* current; + GfxMarkSurf* end; + GfxMarkSurf* mark; + }; + + struct GfxGlassSurfIter + { + GfxGlassSurf* current; + GfxGlassSurf* end; + GfxGlassSurf* mark; + }; + + struct GfxCloudSurfIter + { + GfxCloudSurf* current; + GfxCloudSurf* end; + GfxCloudSurf* mark; + }; + + struct GfxSparkSurfIter + { + GfxSparkSurf* current; + GfxSparkSurf* end; + GfxSparkSurf* mark; + }; + + struct GfxSModelSurfIter + { + const char* visData; + unsigned __int16* current; + const char* end; + const char* mark; + }; + + struct GfxBspSurfIter + { + const unsigned __int16* current; + const unsigned __int16* end; + const unsigned __int16* mark; + }; + + struct GfxBspLightMapSurfIter : GfxBspSurfIter + { + }; + + struct GfxPreTessSurfIter + { + GfxPreTessSurf* current; + GfxPreTessSurf* end; + GfxPreTessSurf* mark; + }; + + struct GfxSunShadowClip + { + unsigned int planeCount[2]; + unsigned int frustumPlaneCount[2]; + DpvsPlane planes[2][10]; + }; + + struct GfxSModelCachedSurfIter : GfxSModelSurfIter + { + }; + + struct GfxSModelRigidSurfIter : GfxSModelSurfIter + { + }; + + struct GfxSModelSkinnedSurfIter : GfxSModelSurfIter + { + }; + + struct GfxSModelPreTessSurfIter : GfxSModelSurfIter + { + }; + + struct GfxCmdRingBuf + { + struct GfxDrawListIter* drawListIter; + unsigned int memoryPos; + unsigned int maxMemoryPos; + char* memoryPool; + unsigned int fencePosIndex; + volatile unsigned int fenceIndex; + unsigned int availIndex; + unsigned int availMemoryPos; + unsigned int reserveMemoryPos0; + unsigned int reserveMemoryPos1; + unsigned int fencePos[64]; + unsigned int fence[64]; + unsigned int checkMemoryPos; + }; + + struct GfxDrawListIter + { + GfxBspSurfIter bspSurfIter; + GfxPreTessSurfIter bspPreTessSurfIter; + GfxSModelRigidSurfIter smodelRigidSurfIter; + GfxSModelSkinnedSurfIter smodelSkinnedSurfIter; + GfxSModelCachedSurfIter smodelCachedSurfIter; + GfxSModelPreTessSurfIter smodelPreTessSurfIter; + GfxDrawSurfIter drawSurfIter; + GfxCodeSurfIter codeSurfIter; + GfxMarkSurfIter markSurfIter; + GfxGlassSurfIter glassSurfIter; + GfxCloudSurfIter cloudSurfIter; + GfxSparkSurfIter sparkSurfIter; + }; + + union GfxSurfsIteratorSortKey + { + struct + { + unsigned int spliceIndex; + unsigned int sortKey; + } fields; + unsigned __int64 packed; + }; + + struct GfxSpotShadow + { + GfxSpotShadowSceneLight sceneLight; + GfxViewportParms viewportParms; + char sceneLightIndex; + char pad[3]; + GfxLight* light; + GfxRenderTargetId renderTargetId; + float pixelAdjust[4]; + int clearScreen; + GfxMeshData* clearMesh; + }; + + struct GfxDrawListArgs + { + GfxCmdBufContext context; + GfxDrawListInfo* listInfo; + }; + + struct GfxSurfsIterator + { + GfxSurfsIteratorSortKey key; + unsigned int(__cdecl* GetSortKeyCallback)(GfxDrawListIter*); + bool(__cdecl* RenderDrawGroupCallback)(GfxDrawListArgs*, GfxDrawListIter*); + }; + + struct GfxSurfsIterGroup + { + unsigned int iteratorBegin; + unsigned int iteratorCount; + GfxDrawListIter drawListIter; + GfxSurfsIterator iteratorPool[11]; + }; + + struct GfxSpliceSurfs + { + unsigned int iteratorBegin; + unsigned int iteratorCount; + unsigned int spliceCount; + GfxDrawListIter drawListIter[5]; + GfxViewport scissorViewport[5]; + int isSceneScissorViewport[5]; + GfxDrawListInfo* dynLightDrawListInfo[5]; + GfxSurfsIterator iteratorPool[55]; + }; + + struct GfxStaticModelDrawStream + { + GfxSModelSurfIter* smodelSurfIter; + GfxSModelSurfHeader smodelSurfHeader; + const char* smodelSurfVisData; + GfxTexture* reflectionProbeTexture; + unsigned int customSamplerFlags; + XSurface* localSurf; + unsigned int smodelCount; + const unsigned __int16* smodelList; + }; + + struct FxSparkMeshData + { + unsigned int triCount; + unsigned __int16* indices; + unsigned int baseVertex; + char pad[4]; + GfxParticleCloud cloud; + }; + + struct GfxBackEndData + { + char sceneLightTechType[13][256]; + GfxSparkSurf sparkSurfs[64]; + GfxViewParms viewParms[4]; + GfxMeshData mesh[5]; + int localClientNum; + GfxBackEndPrimitiveData prim; + volatile int bspSurfDataUsed; + volatile int smodelSurfDataUsed; + volatile int smodelSurfVisDataUsed; + unsigned int sceneLightHasShadowMap[8]; + int drawSurfCount; + volatile int surfPos; + volatile int gfxEntCount; + unsigned int codeSurfCount[2]; + unsigned int codeSurfArgsCount[2]; + volatile int cloudDataCount; + unsigned int glassSurfCount; + unsigned int markSurfCount; + volatile int sparkSurfCount; + GfxVertexBufferState* skinnedCacheVb; + unsigned int endFence; + unsigned int endFrameFence; + int viewParmCount; + GfxFog fogSettings; + GfxCmdArray* commands; + unsigned int viewInfoIndex; + unsigned int viewInfoCount; + GfxViewInfo* viewInfo; + const void* cmds; + float sunShadowLightDir[3]; + int hasApproxSunDirChanged; + int cmdBufValid[18]; + GfxDrawCallOutput drawOutput[18]; + DebugGlobals debugGlobals; + unsigned int imageRendered[112]; + unsigned int drawType; + GfxDrawList dynLightDrawList[4]; + unsigned int dynLightCount; + GfxDrawList* emissiveSpotShadowDrawList[1]; + unsigned int emissiveSpotLightCount; + GfxSunShadow sunShadow; + unsigned int spotShadowCount; + GfxSpotShadow spotShadows[4]; + GfxSurfsIterGroup prepassIterGroup[5]; + GfxSpliceSurfs litTransSpliceSurfs; + char surfsBuffer[131072]; + float codeSurfArgs[288][4]; + GfxCodeSurf codeEmissiveSurfs[2048]; + GfxCodeSurf codeTransSurfs[640]; + GfxMarkSurf markSurfs[1536]; + GfxGlassSurf glassSurfs[768]; + unsigned __int16 bspSurfData[35328]; + char smodelSurfData[35840]; + char smodelSurfVisData[45056]; + GfxCloudSurf cloudSurfs[256]; + GfxEntity gfxEnts[128]; + FxSparkMeshData sparkData[64]; + GfxParticleCloud cloudData[256]; + GfxDrawSurf drawSurfs[16384]; + GfxLight sceneLights[253]; + }; + #pragma endregion #ifndef IDA diff --git a/src/Utils/Compression.cpp b/src/Utils/Compression.cpp index a26fd668..adf5aefd 100644 --- a/src/Utils/Compression.cpp +++ b/src/Utils/Compression.cpp @@ -11,8 +11,15 @@ namespace Utils::Compression // Make sure the buffer is large enough if (length < 100) length *= 10; - char* buffer = allocator.allocateArray(length); - if (compress2(reinterpret_cast(buffer), &length, reinterpret_cast(const_cast(data.data())), data.size(), Z_BEST_COMPRESSION) != Z_OK) + auto* buffer = allocator.allocateArray(length); + +#ifdef _DEBUG + constexpr auto compression = Z_NO_COMPRESSION; +#else + constexpr auto compression = Z_BEST_COMPRESSION; +#endif + + if (compress2((Bytef*)(buffer), &length, (const Bytef*)(data.data()), data.size(), compression) != Z_OK) { return {}; } @@ -34,13 +41,13 @@ namespace Utils::Compression int ret; Memory::Allocator allocator; - std::uint8_t* dest = allocator.allocateArray(CHUNK); - const char* dataPtr = data.data(); + auto* dest = allocator.allocateArray(CHUNK); + const auto* dataPtr = data.data(); do { - stream.avail_in = std::min(static_cast(CHUNK), data.size() - (dataPtr - data.data())); - stream.next_in = reinterpret_cast(dataPtr); + stream.avail_in = std::min(static_cast(CHUNK), data.size() - (dataPtr - data.data())); + stream.next_in = reinterpret_cast(dataPtr); dataPtr += stream.avail_in; do diff --git a/src/Utils/Entities.cpp b/src/Utils/Entities.cpp index 5c31dfbe..baf3962e 100644 --- a/src/Utils/Entities.cpp +++ b/src/Utils/Entities.cpp @@ -35,7 +35,9 @@ namespace Utils { const auto& model = itr->second; - if (!model.empty() && model[0] != '*' && model[0] != '?') // Skip brushmodels + if (!model.empty() && model[0] != '*' && model[0] != '?' && // Skip brushmodels + model != "com_plasticcase_green_big_us_dirt"s // Team zones + ) { if (std::find(models.begin(), models.end(), model) == models.end()) { diff --git a/src/Utils/Json.cpp b/src/Utils/Json.cpp index cbf963e3..eb36fff6 100644 --- a/src/Utils/Json.cpp +++ b/src/Utils/Json.cpp @@ -1,4 +1,5 @@ #include +#include namespace Utils::Json { @@ -31,4 +32,32 @@ namespace Utils::Json return "null"; } } + + unsigned long ReadFlags(const std::string binaryFlags, size_t size) + { + std::bitset<64> input; + const auto binarySize = size * 8; + + if (binaryFlags.size() > binarySize) + { + Components::Logger::Print("Flag {} might not be properly translated, it seems to contain an error (invalid length)\n", binaryFlags); + return 0; + } + + auto i = binarySize - 1; + for (char bit : binaryFlags) + { + if (i < 0) + { + Components::Logger::Print("Flag {} might not be properly translated, it seems to contain an error (invalid length)\n", binaryFlags); + break; + } + + bool isOne = bit == '1'; + input.set(i--, isOne); + } + + return input.to_ulong(); + } + } diff --git a/src/Utils/Json.hpp b/src/Utils/Json.hpp index 854811e1..415309e7 100644 --- a/src/Utils/Json.hpp +++ b/src/Utils/Json.hpp @@ -3,4 +3,6 @@ namespace Utils::Json { std::string TypeToString(nlohmann::json::value_t type); + + unsigned long ReadFlags(const std::string binaryFlags, size_t size); } diff --git a/src/Utils/Stream.hpp b/src/Utils/Stream.hpp index e9f7ae96..3739cc3a 100644 --- a/src/Utils/Stream.hpp +++ b/src/Utils/Stream.hpp @@ -39,10 +39,44 @@ namespace Utils { return readArray(1); } + + template T* readArrayOnce(std::size_t count = 1) + { + constexpr auto POINTER = 255; + constexpr auto FOLLOWING = 254; + + auto b = static_cast(readByte()); + switch (b) + { + case POINTER: + { + auto ptr = read(); + auto* voidPtr = reinterpret_cast(ptr); + + if (allocator->isPointerMapped(voidPtr)) + { + return allocator->getPointer(voidPtr); + } + + throw std::runtime_error("Bad data: missing ptr"); + } + case FOLLOWING: + { + auto filePosition = position; + auto data = readArray(count); + allocator->mapPointer(reinterpret_cast(filePosition), data); + return data; + } + default: + throw std::runtime_error("Bad data"); + } + } + template T* readArray(std::size_t count = 1) { return static_cast(this->read(sizeof(T), count)); } + template T read() { T obj;