Custom textures
This commit is contained in:
parent
e552146bda
commit
c84d4c0dcc
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -16,3 +16,6 @@
|
||||
[submodule "deps/discord-rpc"]
|
||||
path = deps/discord-rpc
|
||||
url = https://github.com/discord/discord-rpc.git
|
||||
[submodule "deps/stb"]
|
||||
path = deps/stb
|
||||
url = https://github.com/nothings/stb.git
|
||||
|
19
deps/premake/stb.lua
vendored
Normal file
19
deps/premake/stb.lua
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
stb = {
|
||||
source = path.join(dependencies.basePath, "stb"),
|
||||
}
|
||||
|
||||
function stb.import()
|
||||
stb.includes()
|
||||
end
|
||||
|
||||
function stb.includes()
|
||||
includedirs {
|
||||
stb.source
|
||||
}
|
||||
end
|
||||
|
||||
function stb.project()
|
||||
|
||||
end
|
||||
|
||||
table.insert(dependencies, stb)
|
@ -239,9 +239,14 @@ namespace game_console
|
||||
con.globals.left_x = con.globals.x;
|
||||
con.globals.auto_complete_choice[0] = 0;
|
||||
|
||||
/*
|
||||
game::R_AddCmdDrawTextWithCursor(con.buffer, 0x7FFFFFFF, console_font, 18, con.globals.x,
|
||||
con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0, color_white, 0,
|
||||
con.cursor, '|');
|
||||
*/
|
||||
|
||||
game::R_AddCmdDrawText(con.buffer, 0x7FFF, console_font, con.globals.x,
|
||||
con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0.0f, color_white, 0);
|
||||
|
||||
// check if using a prefixed '/' or not
|
||||
const auto input = con.buffer[1] && (con.buffer[0] == '/' || con.buffer[0] == '\\')
|
||||
@ -428,21 +433,16 @@ namespace game_console
|
||||
|
||||
bool console_char_event(const int localClientNum, const int key)
|
||||
{
|
||||
if (key == '`' || key == '~')
|
||||
if (key == '`' || key == '~' || key == '|' || key == '\\')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key > 255)
|
||||
if (key > 127)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == '|' || key == '\\')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*game::keyCatchers & 1)
|
||||
{
|
||||
if (key == game::keyNum_t::K_TAB) // tab (auto complete)
|
||||
|
137
src/component/images.cpp
Normal file
137
src/component/images.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "images.hpp"
|
||||
#include "game_console.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/image.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace images
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour load_texture_hook;
|
||||
utils::hook::detour setup_texture_hook;
|
||||
utils::concurrency::container<std::unordered_map<std::string, std::string>> overriden_textures;
|
||||
|
||||
static_assert(sizeof(game::GfxImage) == 104);
|
||||
static_assert(offsetof(game::GfxImage, name) == (sizeof(game::GfxImage) - sizeof(void*)));
|
||||
static_assert(offsetof(game::GfxImage, pixelData) == 56);
|
||||
static_assert(offsetof(game::GfxImage, width) == 44);
|
||||
static_assert(offsetof(game::GfxImage, height) == 46);
|
||||
static_assert(offsetof(game::GfxImage, depth) == 48);
|
||||
static_assert(offsetof(game::GfxImage, numElements) == 50);
|
||||
|
||||
std::optional<std::string> load_image(game::GfxImage* image)
|
||||
{
|
||||
std::string data{};
|
||||
overriden_textures.access([&](const std::unordered_map<std::string, std::string>& textures)
|
||||
{
|
||||
if (const auto i = textures.find(image->name); i != textures.end())
|
||||
{
|
||||
data = i->second;
|
||||
}
|
||||
});
|
||||
|
||||
if (data.empty() && !utils::io::read_file(utils::string::va("images/%s.png", image->name), &data))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return { std::move(data) };
|
||||
}
|
||||
|
||||
std::optional<utils::image> load_raw_image_from_file(game::GfxImage* image)
|
||||
{
|
||||
const auto image_file = load_image(image);
|
||||
if (!image_file)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return utils::image(*image_file);
|
||||
}
|
||||
|
||||
bool load_custom_texture(game::GfxImage* image)
|
||||
{
|
||||
auto raw_image = load_raw_image_from_file(image);
|
||||
if (!raw_image)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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, 0, image->name, &data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, bool> image_list;
|
||||
|
||||
void load_texture_stub(game::GfxImage* image, void* a2, int* a3)
|
||||
{
|
||||
if (image_list.find(image->name) == image_list.end())
|
||||
{
|
||||
//printf("Loading: %s\n", image->name);
|
||||
image_list[image->name] = true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (load_custom_texture(image))
|
||||
{
|
||||
printf("Loaded custom image for: %s\n", image->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Failed to load image %s: %s\n", image->name, e.what());
|
||||
}
|
||||
|
||||
load_texture_hook.invoke<void>(image, a2, a3);
|
||||
}
|
||||
|
||||
int setup_texture_stub(game::GfxImage* image, void* a2, void* a3)
|
||||
{
|
||||
if (image->resourceSize == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return setup_texture_hook.invoke<bool>(image, a2, a3);
|
||||
}
|
||||
}
|
||||
|
||||
void override_texture(std::string name, std::string data)
|
||||
{
|
||||
overriden_textures.access([&](std::unordered_map<std::string, std::string>& textures)
|
||||
{
|
||||
textures[std::move(name)] = std::move(data);
|
||||
});
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
setup_texture_hook.create(game::base_address + 0x74A390, setup_texture_stub);
|
||||
load_texture_hook.create(game::base_address + 0x2A7940, load_texture_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(images::component)
|
6
src/component/images.hpp
Normal file
6
src/component/images.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace images
|
||||
{
|
||||
void override_texture(std::string name, std::string data);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
|
||||
namespace game
|
||||
{
|
||||
@ -20,6 +21,36 @@ namespace game
|
||||
char __pad0[13508];
|
||||
};
|
||||
|
||||
enum $219904913BC1E6DB920C78C8CC0BD8F1
|
||||
{
|
||||
FL_GODMODE = 0x1,
|
||||
FL_DEMI_GODMODE = 0x2,
|
||||
FL_NOTARGET = 0x4,
|
||||
FL_NO_KNOCKBACK = 0x8,
|
||||
FL_NO_RADIUS_DAMAGE = 0x10,
|
||||
FL_SUPPORTS_LINKTO = 0x20,
|
||||
FL_NO_AUTO_ANIM_UPDATE = 0x40,
|
||||
FL_GRENADE_TOUCH_DAMAGE = 0x80,
|
||||
FL_STABLE_MISSILES = 0x100,
|
||||
FL_REPEAT_ANIM_UPDATE = 0x200,
|
||||
FL_VEHICLE_TARGET = 0x400,
|
||||
FL_GROUND_ENT = 0x800,
|
||||
FL_CURSOR_HINT = 0x1000,
|
||||
FL_MISSILE_ATTRACTOR_OR_REPULSOR = 0x2000,
|
||||
FL_WEAPON_BEING_GRABBED = 0x4000,
|
||||
FL_DELETE = 0x8000,
|
||||
FL_BOUNCE = 0x10000,
|
||||
FL_MOVER_SLIDE = 0x20000,
|
||||
FL_MOVING = 0x40000,
|
||||
FL_DONT_AUTOBOLT_MISSILE_EFFECTS = 0x80000,
|
||||
FL_DISABLE_MISSILE_STICK = 0x100000,
|
||||
FL_NO_MELEE_TARGET = 0x2000000,
|
||||
FL_DYNAMICPATH = 0x8000000,
|
||||
FL_AUTO_BLOCKPATHS = 0x10000000,
|
||||
FL_OBSTACLE = 0x20000000,
|
||||
FL_BADPLACE_VOLUME = 0x80000000,
|
||||
};
|
||||
|
||||
struct EntityState
|
||||
{
|
||||
char entityNum;
|
||||
@ -33,7 +64,7 @@ namespace game
|
||||
gclient_s* client;
|
||||
char __pad2[0x4C];
|
||||
char flags;
|
||||
//char __pad3[392];
|
||||
char __pad3[392];
|
||||
}; // size = 760
|
||||
|
||||
struct Material
|
||||
@ -757,4 +788,66 @@ namespace game
|
||||
int emissiveTechType;
|
||||
int forceTechType;
|
||||
};
|
||||
|
||||
struct GfxImageLoadDef
|
||||
{
|
||||
char levelCount;
|
||||
char numElements;
|
||||
char pad[2];
|
||||
int flags;
|
||||
int format;
|
||||
int resourceSize;
|
||||
char data[1];
|
||||
};
|
||||
|
||||
union $3FA29451CE6F1FA138A5ABAB84BE9676
|
||||
{
|
||||
ID3D11Texture1D* linemap;
|
||||
ID3D11Texture2D* map;
|
||||
ID3D11Texture3D* volmap;
|
||||
ID3D11Texture2D* cubemap;
|
||||
GfxImageLoadDef* loadDef;
|
||||
};
|
||||
|
||||
struct GfxTexture
|
||||
{
|
||||
$3FA29451CE6F1FA138A5ABAB84BE9676 ___u0;
|
||||
ID3D11ShaderResourceView* shaderView;
|
||||
ID3D11ShaderResourceView* shaderViewAlternate;
|
||||
};
|
||||
|
||||
struct Picmip
|
||||
{
|
||||
char platform[2];
|
||||
};
|
||||
|
||||
struct CardMemory
|
||||
{
|
||||
int platform[2];
|
||||
};
|
||||
|
||||
struct GfxImage
|
||||
{
|
||||
GfxTexture textures;
|
||||
int flags;
|
||||
int imageFormat;
|
||||
int resourceSize;
|
||||
char mapType;
|
||||
char semantic;
|
||||
char category;
|
||||
char flags2;
|
||||
Picmip picmip;
|
||||
char track;
|
||||
//CardMemory cardMemory;
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
unsigned short depth;
|
||||
unsigned short numElements;
|
||||
char pad3[4];
|
||||
void* pixelData;
|
||||
//GfxImageLoadDef *loadDef;
|
||||
uint64_t streams[4];
|
||||
const char* name;
|
||||
};
|
||||
|
||||
}
|
@ -22,6 +22,9 @@ namespace game
|
||||
DB_EnumXAssets_Internal{0x4129F0};
|
||||
WEAK symbol<const char*(const XAsset* asset)> DB_GetXAssetName{0x3E4090};
|
||||
WEAK symbol<void(XZoneInfo* zoneInfo, unsigned int zoneCount, DBSyncMode syncMode)> DB_LoadXAssets{0x414FF0};
|
||||
WEAK symbol<XAssetHeader(XAssetType type, const char* name, int allowCreateDefault)> DB_FindXAssetHeader{0x412F60};
|
||||
WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x413D80};
|
||||
WEAK symbol<int(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x413C40};
|
||||
|
||||
WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x618F90};
|
||||
WEAK symbol<void(char* buffer, int index)> Dvar_GetCombinedString{0x5A75D0};
|
||||
@ -51,6 +54,9 @@ namespace game
|
||||
|
||||
WEAK symbol<char*(char* string)> I_CleanStr{0x620660};
|
||||
|
||||
WEAK symbol<char* (GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount,
|
||||
uint32_t imageFlags, DXGI_FORMAT imageFormat, int a8, const char* name, const void* initData)> Image_Setup{0x74B2A0};
|
||||
|
||||
WEAK symbol<void(int clientNum, const char* menu, int a3, int a4, unsigned int a5)> LUI_OpenMenu{0x5F0EE0};
|
||||
|
||||
WEAK symbol<Material*(const char* material)> Material_RegisterHandle{0x759BA0};
|
||||
@ -70,6 +76,8 @@ namespace game
|
||||
WEAK symbol<Font_s*(const char* font, int size)> R_RegisterFont{0x746FE0};
|
||||
WEAK symbol<int(const char* text, int maxChars, Font_s* font)> R_TextWidth{0x7472A0};
|
||||
WEAK symbol<void()> R_SyncRenderThread{0x76E7D0};
|
||||
WEAK symbol<void(const void* obj, void* pose, unsigned int entnum, unsigned int renderFxFlags, float* lightingOrigin,
|
||||
float materialTime, __int64 a7, __int64 a8)> R_AddDObjToScene{0x775C40};
|
||||
|
||||
WEAK symbol<ScreenPlacement* ()> ScrPlace_GetViewPlacement{0x3E16A0};
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <unordered_set>
|
||||
#include <csetjmp>
|
||||
#include <deque>
|
||||
#include <optional>
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
|
53
src/utils/image.cpp
Normal file
53
src/utils/image.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "image.hpp"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
image::image(const std::string& image_data)
|
||||
{
|
||||
int channels{};
|
||||
auto* rgb_image = stbi_load_from_memory(reinterpret_cast<const uint8_t*>(image_data.data()), static_cast<int>(image_data.size()), &this->width, &this->height, &channels, 4);
|
||||
if(!rgb_image)
|
||||
{
|
||||
throw std::runtime_error("Unable to load image");
|
||||
}
|
||||
|
||||
auto _ = gsl::finally([rgb_image]()
|
||||
{
|
||||
stbi_image_free(rgb_image);
|
||||
});
|
||||
|
||||
const auto size = this->width * this->height * 4;
|
||||
this->data.resize(size);
|
||||
|
||||
std::memmove(this->data.data(), rgb_image, size);
|
||||
}
|
||||
|
||||
int image::get_width() const
|
||||
{
|
||||
return this->width;
|
||||
}
|
||||
|
||||
int image::get_height() const
|
||||
{
|
||||
return this->height;
|
||||
}
|
||||
|
||||
const void* image::get_buffer() const
|
||||
{
|
||||
return this->data.data();
|
||||
}
|
||||
|
||||
size_t image::get_size() const
|
||||
{
|
||||
return this->data.size();
|
||||
}
|
||||
|
||||
const std::string& image::get_data() const
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
}
|
24
src/utils/image.hpp
Normal file
24
src/utils/image.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class image
|
||||
{
|
||||
public:
|
||||
image(const std::string& data);
|
||||
|
||||
int get_width() const;
|
||||
int get_height() const;
|
||||
const void* get_buffer() const;
|
||||
size_t get_size() const;
|
||||
|
||||
const std::string& get_data() const;
|
||||
|
||||
private:
|
||||
int width{};
|
||||
int height{};
|
||||
std::string data{};
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user