diff --git a/.gitmodules b/.gitmodules index 7230acd8..e92c76fd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,19 +28,20 @@ [submodule "deps/stb"] path = deps/stb url = https://github.com/nothings/stb.git + branch = develop [submodule "deps/libtomcrypt"] path = deps/libtomcrypt - url = git://github.com/libtom/libtomcrypt.git - branch = develop -[submodule "deps/zlib"] - path = deps/zlib - url = git://github.com/madler/zlib.git + url = https://github.com/libtom/libtomcrypt.git branch = develop [submodule "deps/libtommath"] path = deps/libtommath - url = git://github.com/libtom/libtommath.git + url = https://github.com/libtom/libtommath.git branch = develop [submodule "deps/protobuf"] path = deps/protobuf - url = git://github.com/protocolbuffers/protobuf.git + url = https://github.com/protocolbuffers/protobuf.git branch = 3.17.x +[submodule "deps/zlib"] + path = deps/zlib + url = https://github.com/madler/zlib.git + branch = develop diff --git a/deps/asmjit b/deps/asmjit index 6efd4d56..f1a399c4 160000 --- a/deps/asmjit +++ b/deps/asmjit @@ -1 +1 @@ -Subproject commit 6efd4d563dee6832224295fa3bbf1647964246c4 +Subproject commit f1a399c4fe74d1535a4190a2b8727c51045cc914 diff --git a/src/client/component/materials.cpp b/src/client/component/materials.cpp new file mode 100644 index 00000000..287238c0 --- /dev/null +++ b/src/client/component/materials.cpp @@ -0,0 +1,172 @@ +#include +#include "loader/component_loader.hpp" + +#include "materials.hpp" +#include "console.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include +#include +#include +#include +#include + +namespace materials +{ + namespace + { + utils::hook::detour db_material_streaming_fail_hook; + utils::hook::detour material_register_handle_hook; + + struct material_data_t + { + std::unordered_map materials; + std::unordered_map images; + }; + + utils::concurrency::container material_data; + + game::GfxImage* setup_image(game::GfxImage* image, const utils::image& raw_image) + { + image->imageFormat = 0x1000003; + image->resourceSize = -1; + + D3D11_SUBRESOURCE_DATA data{}; + data.SysMemPitch = raw_image.get_width() * 4; + data.SysMemSlicePitch = data.SysMemPitch * raw_image.get_height(); + data.pSysMem = raw_image.get_buffer(); + + game::Image_Setup(image, raw_image.get_width(), raw_image.get_height(), image->depth, image->numElements, + image->imageFormat, DXGI_FORMAT_R8G8B8A8_UNORM, image->name, &data); + + return image; + } + + game::Material* create_material(const std::string& name, const std::string& data) + { + const auto white = *reinterpret_cast(SELECT_VALUE(0x141F3D860, 0x14282C330)); + + const auto material = utils::memory::get_allocator()->allocate(); + const auto texture_table = utils::memory::get_allocator()->allocate(); + const auto image = utils::memory::get_allocator()->allocate(); + + std::memcpy(material, white, sizeof(game::Material)); + std::memcpy(texture_table, white->textureTable, sizeof(game::MaterialTextureDef)); + std::memcpy(image, white->textureTable->u.image, sizeof(game::GfxImage)); + + material->name = utils::memory::get_allocator()->duplicate_string(name); + image->name = material->name; + + material->textureTable = texture_table; + material->textureTable->u.image = setup_image(image, data); + + return material; + } + + game::Material* load_material(const std::string& name) + { + return material_data.access([&](material_data_t& data_) -> game::Material* + { + if (const auto i = data_.materials.find(name); i != data_.materials.end()) + { + return i->second; + } + + std::string data{}; + if (const auto i = data_.images.find(name); i != data_.images.end()) + { + data = i->second; + } + + if (data.empty() + && !utils::io::read_file(utils::string::va("h1-mod/materials/%s.png", name.data()), &data) + && !utils::io::read_file(utils::string::va("data/materials/%s.png", name.data()), &data)) + { + return nullptr; + } + + const auto material = create_material(name, data); + data_.materials[name] = material; + + return material; + }); + } + + game::Material* try_load_material(const std::string& name) + { + if (name == "white") + { + return nullptr; + } + + try + { + return load_material(name); + } + catch (const std::exception& e) + { + console::error("Failed to load material %s: %s\n", name.data(), e.what()); + } + + return nullptr; + } + + game::Material* material_register_handle_stub(const char* name) + { + auto result = try_load_material(name); + if (result == nullptr) + { + result = material_register_handle_hook.invoke(name); + } + return result; + } + + bool db_material_streaming_fail_stub(game::Material* material) + { + const auto found = material_data.access([material](material_data_t& data_) + { + if (data_.materials.find(material->name) != data_.materials.end()) + { + return true; + } + + return false; + }); + + if (found) + { + return false; + } + + return db_material_streaming_fail_hook.invoke(material); + } + } + + void add(const std::string& name, const std::string& data) + { + material_data.access([&](material_data_t& data_) + { + data_.images[name] = data; + }); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + material_register_handle_hook.create(game::Material_RegisterHandle, material_register_handle_stub); + db_material_streaming_fail_hook.create(SELECT_VALUE(0x1401D3180, 0x1402C6260), db_material_streaming_fail_stub); + } + }; +} + +REGISTER_COMPONENT(materials::component) diff --git a/src/client/component/materials.hpp b/src/client/component/materials.hpp new file mode 100644 index 00000000..ac58b511 --- /dev/null +++ b/src/client/component/materials.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace materials +{ + void add(const std::string& name, const std::string& data); +} diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 3437a026..bb7c3aec 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1101,11 +1101,90 @@ namespace game int forceTechType; }; + struct GfxImage; + + union MaterialTextureDefInfo + { + GfxImage* image; + void* water; + }; + + struct MaterialTextureDef + { + unsigned int nameHash; + char nameStart; + char nameEnd; + char samplerState; + char semantic; + MaterialTextureDefInfo u; + }; + + struct MaterialPass + { + void* vertexShader; + void* vertexDecl; + void* hullShader; + void* domainShader; + void* pixelShader; + char pixelOutputMask; + char perPrimArgCount; + char perObjArgCount; + char stableArgCount; + unsigned __int16 perPrimArgSize; + unsigned __int16 perObjArgSize; + unsigned __int16 stableArgSize; + char zone; + char perPrimConstantBuffer; + char perObjConstantBuffer; + char stableConstantBuffer; + unsigned int customBufferFlags; + char customSamplerFlags; + char precompiledIndex; + char stageConfig; + void* args; + }; + + struct MaterialTechnique + { + const char* name; + unsigned __int16 flags; + unsigned __int16 passCount; + MaterialPass passArray[1]; + }; + + struct MaterialTechniqueSet + { + const char* name; + unsigned __int16 flags; + char worldVertFormat; + char preDisplacementOnlyCount; + MaterialTechnique* techniques[309]; + }; + + struct GfxStateBits + { + unsigned int loadBits[3]; + char zone; + char depthStencilState[11]; + char blendState; + char rasterizerState; + }; + struct Material { const char* name; + char __pad0[0x118]; + char textureCount; + char __pad1[7]; + MaterialTechniqueSet* techniqueSet; + MaterialTextureDef* textureTable; + void* constantTable; + GfxStateBits* stateBitsTable; + char __pad2[0x108]; }; + static_assert(sizeof(Material) == 0x250); + struct Glyph { unsigned short letter; @@ -1252,7 +1331,6 @@ namespace game GfxImageLoadDef* loadDef; }; - struct GfxTexture { $3FA29451CE6F1FA138A5ABAB84BE9676 ___u0; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 257bbf15..9381150a 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -121,6 +121,9 @@ namespace game #define R_AddCmdDrawTextWithCursor(TXT, MC, F, UNK, X, Y, XS, YS, R, C, S, CP, CC) \ H1_AddBaseDrawTextCmd(TXT, MC, F, game::R_GetFontHeight(F), X, Y, XS, YS, R, C, S, CP, CC, game::R_DrawSomething(S)) + WEAK symbol Image_Setup{0x1404D7D50, 0x1405DCF90}; + WEAK symbol VM_Execute{0x140376360, 0x140444350}; @@ -138,7 +141,7 @@ namespace game WEAK symbol DB_EnumXAssets_Internal{0x1401C9C10, 0x1402BA830}; - WEAK symbol DB_GetXAssetName{0x14019A390, 0x14028BE50}; + WEAK symbol DB_GetXAssetName{0x14019A390, 0x14028BE50}; WEAK symbol DB_GetXAssetTypeSize{0x14019A3B0, 0x14028BE70}; WEAK symbol