Custom material stupport
This commit is contained in:
parent
87bec471dc
commit
60a0062dfd
167
src/client/component/materials.cpp
Normal file
167
src/client/component/materials.cpp
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "materials.hpp"
|
||||||
|
#include "console.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/memory.hpp>
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
#include <utils/image.hpp>
|
||||||
|
#include <utils/concurrency.hpp>
|
||||||
|
|
||||||
|
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<std::string, game::Material*> materials;
|
||||||
|
std::unordered_map<std::string, std::string> images;
|
||||||
|
};
|
||||||
|
|
||||||
|
utils::concurrency::container<material_data_t> 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<game::Material**>(SELECT_VALUE(0x141F3D860, 0x14282C330));
|
||||||
|
|
||||||
|
const auto material = utils::memory::get_allocator()->allocate<game::Material>();
|
||||||
|
const auto texture_table = utils::memory::get_allocator()->allocate<game::MaterialTextureDef>();
|
||||||
|
const auto image = utils::memory::get_allocator()->allocate<game::GfxImage>();
|
||||||
|
|
||||||
|
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<game::Material*>([&](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)
|
||||||
|
{
|
||||||
|
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<game::Material*>(name);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool db_material_streaming_fail_stub(game::Material* material)
|
||||||
|
{
|
||||||
|
const auto found = material_data.access<bool>([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<bool>(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)
|
6
src/client/component/materials.hpp
Normal file
6
src/client/component/materials.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace materials
|
||||||
|
{
|
||||||
|
void add(const std::string& name, const std::string& data);
|
||||||
|
}
|
@ -1101,11 +1101,91 @@ namespace game
|
|||||||
int forceTechType;
|
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;
|
||||||
|
char pad[1000];
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
struct Material
|
||||||
{
|
{
|
||||||
const char* name;
|
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
|
struct Glyph
|
||||||
{
|
{
|
||||||
unsigned short letter;
|
unsigned short letter;
|
||||||
@ -1252,7 +1332,6 @@ namespace game
|
|||||||
GfxImageLoadDef* loadDef;
|
GfxImageLoadDef* loadDef;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct GfxTexture
|
struct GfxTexture
|
||||||
{
|
{
|
||||||
$3FA29451CE6F1FA138A5ABAB84BE9676 ___u0;
|
$3FA29451CE6F1FA138A5ABAB84BE9676 ___u0;
|
||||||
|
@ -121,6 +121,9 @@ namespace game
|
|||||||
#define R_AddCmdDrawTextWithCursor(TXT, MC, F, UNK, X, Y, XS, YS, R, C, S, CP, CC) \
|
#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))
|
H1_AddBaseDrawTextCmd(TXT, MC, F, game::R_GetFontHeight(F), X, Y, XS, YS, R, C, S, CP, CC, game::R_DrawSomething(S))
|
||||||
|
|
||||||
|
WEAK symbol<char* (GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount,
|
||||||
|
uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const D3D11_SUBRESOURCE_DATA* initData)> Image_Setup{0x1404D7D50, 0x1405DCF90};
|
||||||
|
|
||||||
WEAK symbol<unsigned int(unsigned int localId, const char* pos,
|
WEAK symbol<unsigned int(unsigned int localId, const char* pos,
|
||||||
unsigned int paramcount)> VM_Execute{0x140376360, 0x140444350};
|
unsigned int paramcount)> VM_Execute{0x140376360, 0x140444350};
|
||||||
|
|
||||||
@ -138,7 +141,7 @@ namespace game
|
|||||||
|
|
||||||
WEAK symbol<void(XAssetType type, void(__cdecl* func)(XAssetHeader, void*), const void* inData, bool includeOverride)>
|
WEAK symbol<void(XAssetType type, void(__cdecl* func)(XAssetHeader, void*), const void* inData, bool includeOverride)>
|
||||||
DB_EnumXAssets_Internal{0x1401C9C10, 0x1402BA830};
|
DB_EnumXAssets_Internal{0x1401C9C10, 0x1402BA830};
|
||||||
WEAK symbol<const char* (const XAsset* asset)> DB_GetXAssetName{0x14019A390, 0x14028BE50};
|
WEAK symbol<const char*(const XAsset* asset)> DB_GetXAssetName{0x14019A390, 0x14028BE50};
|
||||||
WEAK symbol<int(XAssetType type)> DB_GetXAssetTypeSize{0x14019A3B0, 0x14028BE70};
|
WEAK symbol<int(XAssetType type)> DB_GetXAssetTypeSize{0x14019A3B0, 0x14028BE70};
|
||||||
|
|
||||||
WEAK symbol<void(int clientNum, const char* menu,
|
WEAK symbol<void(int clientNum, const char* menu,
|
||||||
|
Loading…
Reference in New Issue
Block a user