diff --git a/README.md b/README.md index 1410047c..c0982843 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,4 @@ | `--disable-node-log` | Disable debugging messages for Nodes in Debug builds. | | `--disable-base128` | Disable base128 encoding for minidumps. | | `--no-new-structure` | Do not use new virtual path structure (separating headers and source files). | +| `--enable-dxsdk` | Enable DirectX SDK (required for GfxMap exporting). | diff --git a/premake5.lua b/premake5.lua index 30022a67..b8c74ac2 100644 --- a/premake5.lua +++ b/premake5.lua @@ -83,6 +83,11 @@ newoption { description = "Disable base128 encoding for minidumps." } +newoption { + trigger = "enable-dxsdk", + description = "Enable DirectX SDK (required for GfxMap exporting)." +} + newaction { trigger = "version", description = "Returns the version string for the current commit of the source code.", @@ -333,6 +338,12 @@ workspace "iw4x" if _OPTIONS["disable-base128"] then defines { "DISABLE_BASE128" } end + + if _OPTIONS["enable-dxsdk"] then + defines { "ENABLE_DXSDK" } + includedirs { "%DXSDK_DIR%Include" } + libdirs { "%DXSDK_DIR%Lib/x86" } + end -- Pre-compiled header pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index a121848e..00eaa136 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -134,7 +134,7 @@ namespace Components if (type == 5 && name == "wc/codo_ui_viewer_black_decal3"s) { - std::memcpy(&asset->material->gameFlags, &(*reinterpret_cast(0xA7FFE8))->gameFlags, sizeof(Game::Material) - 4); + asset->material->sortKey = 0xE; } if (Flags::HasFlag("entries")) diff --git a/src/Components/Modules/AssetInterfaces/IGfxImage.cpp b/src/Components/Modules/AssetInterfaces/IGfxImage.cpp index 84523d2b..258e7b45 100644 --- a/src/Components/Modules/AssetInterfaces/IGfxImage.cpp +++ b/src/Components/Modules/AssetInterfaces/IGfxImage.cpp @@ -19,8 +19,8 @@ namespace Assets image->category = 0; image->cardMemory = 0; - image->texture = builder->GetAllocator()->Allocate(); - if (!image->texture) + image->loadDef = builder->GetAllocator()->Allocate(); + if (!image->loadDef) { Components::Logger::Error("Failed to allocate GfxImageLoadDef structure!"); return; @@ -48,39 +48,39 @@ namespace Assets return; } - std::memcpy(image->texture->dimensions, iwiHeader->dimensions, 6); - image->texture->flags = 0; - image->texture->mipLevels = 0; + std::memcpy(image->loadDef->dimensions, iwiHeader->dimensions, 6); + image->loadDef->flags = 0; + image->loadDef->mipLevels = 0; switch (iwiHeader->format) { case Game::IWI_COMPRESSION::IWI_ARGB: { - image->texture->format = 21; + image->loadDef->format = 21; break; } case Game::IWI_COMPRESSION::IWI_RGB8: { - image->texture->format = 20; + image->loadDef->format = 20; break; } case Game::IWI_COMPRESSION::IWI_DXT1: { - image->texture->format = 0x31545844; + image->loadDef->format = 0x31545844; break; } case Game::IWI_COMPRESSION::IWI_DXT3: { - image->texture->format = 0x33545844; + image->loadDef->format = 0x33545844; break; } case Game::IWI_COMPRESSION::IWI_DXT5: { - image->texture->format = 0x35545844; + image->loadDef->format = 0x35545844; break; } } diff --git a/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp b/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp index 5d725f76..8ae7af5e 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp @@ -74,13 +74,15 @@ namespace Assets buffer->Save(technique, 8); // Save_MaterialPassArray + Game::MaterialPass* destPasses = buffer->Dest(); + buffer->SaveArray(technique->passes, technique->numPasses); + for (short j = 0; j < technique->numPasses; ++j) { Assert_Size(Game::MaterialPass, 20); - Game::MaterialPass* destPass = buffer->Dest(); + Game::MaterialPass* destPass = &destPasses[j]; Game::MaterialPass* pass = &technique->passes[j]; - buffer->Save(pass); if (pass->vertexDecl) { diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index eb3badcf..485e8f78 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -180,21 +180,26 @@ namespace Components return (Utils::String::StartsWith(entity, "dyn_") || Utils::String::StartsWith(entity, "node_") || Utils::String::StartsWith(entity, "actor_")); } -#ifdef DEBUG +#if defined(DEBUG) && defined(ENABLE_DXSDK) // Credit to SE2Dev, as we shouldn't share the code, keep that in debug mode! void Maps::ExportMap(Game::GfxWorld* world) { Utils::Memory::Allocator allocator; + if (!world) return; + + Logger::Print("Exporting '%s'...\n", world->baseName); std::string mtl; - mtl.append("# SE2Dev MTL File: \n"); - mtl.append("# Material Count: 0"); + mtl.append("# IW4x MTL File\n"); + mtl.append("# Credit to SE2Dev for his D3DBSP Tool\n"); std::string map; - map.append("# Generated by SE2Dev's D3DBSP Tool\n"); + map.append("# Generated by IW4x\n"); + map.append("# Credit to SE2Dev for his D3DBSP Tool\n"); map.append(fmt::sprintf("o %s\n", world->baseName)); map.append(fmt::sprintf("mtllib %s.mtl\n", world->baseName)); + Logger::Print("Writing vertices...\n"); for (unsigned int i = 0; i < world->worldDraw.vertexCount; i++) { // Y/Z need to be inverted @@ -205,11 +210,13 @@ namespace Components map.append(fmt::sprintf("v %.6f %.6f %.6f\n", x,y, z)); } + Logger::Print("Writing texture coordinates...\n"); for (unsigned int i = 0; i < world->worldDraw.vertexCount; i++) { map.append(fmt::sprintf("vt %.6f %.6f\n", world->worldDraw.vd.vertices[i].texCoord[0], world->worldDraw.vd.vertices[i].texCoord[1])); } + Logger::Print("Searching materials...\n"); int materialCount = 0; Game::Material** materials = allocator.AllocateArray(world->dpvs.staticSurfaceCount); @@ -232,6 +239,10 @@ namespace Components } } + Utils::IO::CreateDirectory(fmt::sprintf("raw/mapdump/%s/textures", world->baseName)); + mtl.append(fmt::sprintf("# Material Count: %d\n", materialCount)); + + Logger::Print("Exporting materials and faces...\n"); for (int m = 0; m < materialCount; m++) { std::string name = materials[m]->name; @@ -245,6 +256,29 @@ namespace Components map.append(fmt::sprintf("usemtl %s\n", name.data())); map.append("s off\n"); + Game::GfxImage* image = materials[m]->textureTable[0].info.image; + + for (char l = 0; l < materials[m]->textureCount; ++l) + { + if (materials[m]->textureTable[l].nameStart == 'c') + { + if (materials[m]->textureTable[l].nameEnd == 'p') + { + image = materials[m]->textureTable[l].info.image; // Hopefully our colorMap + } + } + } + + std::string _name = fmt::sprintf("raw/mapdump/%s/textures/%s.png", world->baseName, image->name); + D3DXSaveTextureToFile(std::wstring(_name.begin(), _name.end()).data(), D3DXIFF_PNG, image->texture, NULL); + + mtl.append(fmt::sprintf("newmtl %s\n", name.data())); + mtl.append("Ka 1.0000 1.0000 1.0000\n"); + mtl.append("Kd 1.0000 1.0000 1.0000\n"); + mtl.append("illum 1\n"); + mtl.append(fmt::sprintf("map_Ka textures/%s.png\n", image->name)); + mtl.append(fmt::sprintf("map_Kd textures/%s.png\n", image->name)); + for (unsigned int i = 0; i < world->dpvs.staticSurfaceCount; i++) { if (world->dpvs.surfaces[i].material != materials[m]) @@ -263,8 +297,9 @@ namespace Components } } - Utils::IO::WriteFile(fmt::sprintf("raw/mapdump/%s.mtl", world->baseName), mtl); - Utils::IO::WriteFile(fmt::sprintf("raw/mapdump/%s.obj", world->baseName), map); + Logger::Print("Writing final files...\n"); + Utils::IO::WriteFile(fmt::sprintf("raw/mapdump/%s/%s.mtl", world->baseName, world->baseName), mtl); + Utils::IO::WriteFile(fmt::sprintf("raw/mapdump/%s/%s.obj", world->baseName, world->baseName), map); } #endif @@ -365,12 +400,18 @@ namespace Components Maps::AddDependency("mp_cargoship_sh", "iw4x_dependencies_mp"); Maps::AddDependency("mp_firingrange", "iw4x_dependencies_mp"); Maps::AddDependency("mp_shipment_long", "iw4x_dependencies_mp"); + Maps::AddDependency("mp_firingrange", "iw4x_dependencies_mp"); -#ifdef DEBUG +#if defined(DEBUG) && defined(ENABLE_DXSDK) Command::Add("dumpmap", [] (Command::Params) { - Game::GfxWorld* world = nullptr; + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) + { + Logger::Print("DirectX needs to be enabled, please start a client to use this command!\n"); + return; + } + Game::GfxWorld* world = nullptr; Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_GFX_MAP, [] (Game::XAssetHeader header, void* world) { *reinterpret_cast(world) = header.gfxMap; @@ -386,7 +427,6 @@ namespace Components Logger::Print("No map loaded, unable to dump anything!\n"); } }); - #endif } diff --git a/src/Components/Modules/Maps.hpp b/src/Components/Modules/Maps.hpp index 10bbdb03..a8ffdf2c 100644 --- a/src/Components/Modules/Maps.hpp +++ b/src/Components/Modules/Maps.hpp @@ -26,7 +26,7 @@ namespace Components static int IgnoreEntityStub(const char* entity); -#ifdef DEBUG +#if defined(DEBUG) && defined(ENABLE_DXSDK) static void ExportMap(Game::GfxWorld* world); #endif diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index c267b963..ac82b664 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -108,6 +108,8 @@ namespace Game Load_XStringCustom_t Load_XStringCustom = (Load_XStringCustom_t)0x4E0DD0; Load_FxEffectDefHandle_t Load_FxEffectDefHandle = (Load_FxEffectDefHandle_t)0x4D9B90; Load_FxElemDef_t Load_FxElemDef = (Load_FxElemDef_t)0x45AD90; + Load_Texture_t Load_Texture = (Load_Texture_t)0x51F4E0; + Load_GfxTextureLoad_t Load_GfxTextureLoad = (Load_GfxTextureLoad_t)0x4D3210; Load_SndAliasCustom_t Load_SndAliasCustom = (Load_SndAliasCustom_t)0x49B6B0; Load_MaterialHandle_t Load_MaterialHandle = (Load_MaterialHandle_t)0x403960; Load_PhysCollmapPtr_t Load_PhysCollmapPtr = (Load_PhysCollmapPtr_t)0x47E990; diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index f6735aec..35b56638 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -260,6 +260,12 @@ namespace Game typedef void(__cdecl *Load_FxElemDef_t)(bool atStreamStart); extern Load_FxElemDef_t Load_FxElemDef; + typedef void(__cdecl *Load_GfxTextureLoad_t)(bool atStreamStart); + extern Load_GfxTextureLoad_t Load_GfxTextureLoad; + + typedef int(__cdecl *Load_Texture_t)(GfxImageLoadDef **loadDef, GfxImage *image); + extern Load_Texture_t Load_Texture; + typedef void(__cdecl * Load_SndAliasCustom_t)(snd_alias_list_t** var); extern Load_SndAliasCustom_t Load_SndAliasCustom; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 0ad064b6..9015ed86 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -216,7 +216,12 @@ namespace Game struct GfxImage { - GfxImageLoadDef * /*Direct3DTexture9**/ texture; + union + { + GfxImageLoadDef* loadDef; + IDirect3DTexture9* texture; + }; + char mapType; // 5 is cube, 4 is 3d, 3 is 2d char semantic; char category; @@ -2509,7 +2514,6 @@ namespace Game char *smodelVisData[3]; char *surfaceVisData[3]; unsigned __int16 *sortedSurfIndex; - GfxStaticModelInst *smodelInsts; GfxSurface *surfaces; GfxCullGroup *cullGroups; // actually GfxSurfaceBounds (24), but not important right now diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index e37b628c..c7cee0e0 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -39,6 +39,11 @@ #include #include +#ifdef ENABLE_DXSDK +#include +#pragma comment(lib, "D3dx9.lib") +#endif + // Usefull for debugging template class Sizer { }; #define BindNum(x, y) Sizer y;