diff --git a/source-code/PD-Loader.sln b/source-code/PD-Loader.sln index 1d85914..baa3962 100644 --- a/source-code/PD-Loader.sln +++ b/source-code/PD-Loader.sln @@ -25,6 +25,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DivaWig", "source\plugins\D EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DSCRemote", "source\plugins\DSCRemote\DSCRemote.vcxproj", "{8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Novidia", "source\plugins\Novidia\Novidia.vcxproj", "{47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -75,6 +77,10 @@ Global {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.Build.0 = Debug|x64 {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.ActiveCfg = Release|x64 {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.Build.0 = Release|x64 + {47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}.Debug|x64.ActiveCfg = Debug|x64 + {47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}.Debug|x64.Build.0 = Debug|x64 + {47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}.Release|x64.ActiveCfg = Release|x64 + {47181A1D-C22C-4C9C-B4E0-CB6CE886A1D8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source-code/source/plugins/Novidia/Novidia.vcxproj b/source-code/source/plugins/Novidia/Novidia.vcxproj new file mode 100644 index 0000000..38198d6 --- /dev/null +++ b/source-code/source/plugins/Novidia/Novidia.vcxproj @@ -0,0 +1,98 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {47181a1d-c22c-4c9c-b4e0-cb6ce886a1d8} + Novidia + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + true + .dva + + + false + .dva + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\detours\include; + + + Console + true + ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) + opengl32.lib;detours.lib;syelog.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\..\..\dependencies\PluginConfigApi;..\..\..\dependencies\detours\include; + + + Console + true + true + true + ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) + opengl32.lib;detours.lib;syelog.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + \ No newline at end of file diff --git a/source-code/source/plugins/Novidia/Novidia.vcxproj.filters b/source-code/source/plugins/Novidia/Novidia.vcxproj.filters new file mode 100644 index 0000000..9917580 --- /dev/null +++ b/source-code/source/plugins/Novidia/Novidia.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/source-code/source/plugins/Novidia/src/dllmain.cpp b/source-code/source/plugins/Novidia/src/dllmain.cpp new file mode 100644 index 0000000..08db2bb --- /dev/null +++ b/source-code/source/plugins/Novidia/src/dllmain.cpp @@ -0,0 +1,163 @@ +#include "framework.h" +#include "glStuff.h" +#include + + + +// upload to the SSBO instead after processing +void h_uploadModelTransformBuf(DWORD* a1, int a2) +{ + uploadModelTransformBuf(a1, a2); + + glActiveTexture(GL_TEXTURE8); + glBindTexture(GL_TEXTURE_1D, buf_tex); + //glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 0x3000 / sizeof(float) / 4, 0, GL_RGBA, GL_FLOAT, *(float**)0x1411a3330); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 0x3000 / sizeof(float) / 4, GL_RGBA, GL_FLOAT, *(float**)0x1411a3330); + glActiveTexture(GL_TEXTURE0); + //glFinish(); +} + +/* +void h_glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) +{ + if (performTransform) + { + glActiveTexture(GL_TEXTURE8); + glBindTexture(GL_TEXTURE_1D, buf_tex); + //glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 0x3000 / sizeof(float) / 4, 0, GL_RGBA, GL_FLOAT, *(float**)0x1411a3330); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 0x3000 / sizeof(float) / 4, GL_RGBA, GL_FLOAT, *(float**)0x1411a3330); + //glActiveTexture(GL_TEXTURE0); + } + glDrawElements(mode, count, type, indices); +} + +void h_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) +{ + if (performTransform) + { + glActiveTexture(GL_TEXTURE8); + glBindTexture(GL_TEXTURE_1D, buf_tex); + //glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 0x3000 / sizeof(float) / 4, 0, GL_RGBA, GL_FLOAT, *(float**)0x1411a3330); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 0x3000 / sizeof(float) / 4, GL_RGBA, GL_FLOAT, *(float**)0x1411a3330); + //glActiveTexture(GL_TEXTURE0); + } + glDrawRangeElements(mode,start, end, count, type, indices); +} +*/ + +// just a crash fix +void h_glBindBuffer(GLenum target, GLuint buffer) +{ + // if not okay, it's param buffer data + if (!checkBufferTargetOk(target)) + { + return; + } + + glBindBuffer(target, buffer); +} + +// just a crash fix +void h_glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) +{ + // if not okay, it's param buffer data + if (!checkBufferTargetOk(target)) + { + return; + } + + glBufferData(target, size, data, usage); +} + +PROC h_wglGetProcAddress(LPCSTR Arg1) +{ + PROC res = wGlGetProcAddress_forhook(Arg1); + if (res == nullptr) + return (PROC)stub; + return res; +} + +// used as an entry point after GL context is created +void h_glutSetCursor(int cursor) +{ + if (!loadGlAddresses()) + { + printf("[Novidia] Aborting loading\n"); + //MessageBoxA(NULL, "!", NULL, NULL); + } + else + { + + struct { + void* target; + void* hook; + } hookFuncs[] = { + {&glBindBuffer, h_glBindBuffer}, + {&glBindBufferARB, h_glBindBuffer}, + {&glBufferData, h_glBufferData}, + {&glBufferDataARB, h_glBufferData}, + //{&glDrawElements, h_glDrawElements}, + //{&glDrawRangeElements, h_glDrawRangeElements}, + }; + + for (auto fn : hookFuncs) + { + hookGlFunc((PROC*)fn.target, fn.hook); + } + + //glActiveTexture(GL_TEXTURE8); + glGenTextures(1, &buf_tex); + glBindTexture(GL_TEXTURE_1D, buf_tex); + glTexStorage1D(GL_TEXTURE_1D, 1, GL_RGBA32F, 0x3000 / sizeof(float) / 4); + //glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 0x3000 / sizeof(float) / 4, 0, GL_RGBA, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + } + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + printf("[Novidia] Unhooking glutSetCursor\n"); + DetourDetach(&(PVOID&)glutSetCursor, h_glutSetCursor); + DetourTransactionCommit(); + + glutSetCursor(cursor); +} + + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + + if (ul_reason_for_call == DLL_PROCESS_ATTACH) + { + //loadConfig(); + + DisableThreadLibraryCalls(hModule); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + printf("[Novidia] Hooking glutSetCursor\n"); + DetourAttach(&(PVOID&)glutSetCursor, h_glutSetCursor); + printf("[Novidia] Hooking uploadModelTransformBuf\n"); + DetourAttach(&(PVOID&)uploadModelTransformBuf, h_uploadModelTransformBuf); + printf("[Novidia] Hooking wglGetProcAddress\n"); + DetourAttach(&(PVOID&)wGlGetProcAddress_forhook, h_wglGetProcAddress); + DetourTransactionCommit(); + } + + return TRUE; +} + + + +using namespace PluginConfig; + +extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) +{ + return L"Novidia"; +} + +extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) +{ + return L"Novidia by somewhatlurker\n\nPerforms some model skinning transformations in an alternate way to enable functionality on non-Nvidia hardware.\nAlso fixes crashing on non-Nvidia hardware.\n\nRequires patched shaders and GLIntercept installed to work."; +} \ No newline at end of file diff --git a/source-code/source/plugins/Novidia/src/framework.h b/source-code/source/plugins/Novidia/src/framework.h new file mode 100644 index 0000000..07fa0b5 --- /dev/null +++ b/source-code/source/plugins/Novidia/src/framework.h @@ -0,0 +1,49 @@ +#pragma once + +#include "glStuff.h" + +// use this as a hook to perform initialisation +void(__cdecl* glutSetCursor)(int cursor) = *(void(__cdecl**)(int))0x140966068; +void(__cdecl* uploadModelTransformBuf)(DWORD* a1, int a2) = (void(__cdecl*)(DWORD * a1, int a2))0x140444fa0; +PROC(*wGlGetProcAddress_forhook)(LPCSTR) = (PROC(*)(LPCSTR))(GetProcAddress(GetModuleHandle(L"opengl32.dll"), "wglGetProcAddress"));; + +bool& performTransform = *(bool*)0x14cc57bb0; + +// vars that will contain the requiered info about GL buffers to perform the transform +GLuint buf_tex; + + +// check if a buffer target is okay to allow on non-Nvidia platforms +// (used to prevent crashes in glBindBuffer and glBufferData) +// only parameter buffer NV targets cause issues +bool checkBufferTargetOk(GLenum target) +{ + return !(target == GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV || target == GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV); +} + + +int __stdcall stub() { return 1; } + + +/* +std::wstring ExePath() { + WCHAR buffer[MAX_PATH]; + GetModuleFileNameW(NULL, buffer, MAX_PATH); + return std::wstring(buffer); +} + +std::wstring DirPath() { + std::wstring exepath = ExePath(); + std::wstring::size_type pos = exepath.find_last_of(L"\\/"); + return exepath.substr(0, pos); +} + +std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\Novidia.ini"; +LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); + + +void loadConfig() +{ + +} +*/ \ No newline at end of file diff --git a/source-code/source/plugins/Novidia/src/glStuff.h b/source-code/source/plugins/Novidia/src/glStuff.h new file mode 100644 index 0000000..f494ab4 --- /dev/null +++ b/source-code/source/plugins/Novidia/src/glStuff.h @@ -0,0 +1,136 @@ +#pragma once + +#include +#include +#include + + +// should probably just use GL.h, but I'm avoiding it to let me call hooked stuff as normal +typedef uint32_t GLenum, GLuint, GLsizei, GLbitfield; +typedef int32_t GLint; +typedef uint64_t GLsizeiptr; +typedef int64_t GLintptr, GLint64; +typedef bool GLboolean; +typedef char GLchar; + +#define GL_FALSE 0 +#define GL_NO_ERROR 0 +#define GL_TEXTURE_1D 0x0de0 +#define GL_FLOAT 0x1406 +#define GL_RGBA 0x1908 +#define GL_NEAREST 0x2600 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_CLAMP_TO_BORDER 0x812d +#define GL_CLAMP_TO_EDGE 0x812f +#define GL_TEXTURE0 0x84c0 +#define GL_TEXTURE8 0x84c8 +#define GL_BUFFER_SIZE 0x8764 +#define GL_RGBA32F 0x8814 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_READ_ONLY 0x88b8 +#define GL_STREAM_DRAW 0x88e0 +#define GL_STREAM_COPY 0x88e2 +#define GL_COMPILE_STATUS 0x8b81 +#define GL_LINK_STATUS 0x8b82 +#define GL_CURRENT_PROGRAM 0x8b8d +#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8da2 +#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8da4 +#define GL_SHADER_STORAGE_BUFFER 0x90d2 +#define GL_COMPUTE_SHADER 0x91b9 +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 + + +//void(__cdecl** p_glActiveTexture)(GLenum texture) = (void(__cdecl**)(GLenum texture))0x1411a3db8; +//void(__cdecl* glGenTextures)(GLsizei n, GLuint* textures) = *(void(__cdecl**)(GLsizei n, GLuint * textures))0x140965ad8; +//void(__cdecl* glBindTexture)(GLenum target, GLuint texture) = *(void(__cdecl**)(GLenum target, GLuint texture))0x140965bf8; +//void(__cdecl* glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void* indices) = *(void(__cdecl**)(GLenum mode, GLsizei count, GLenum type, const void* indices))0x140965a48; + +// these are all dynamic imports and can't be initialised until after the OpenGL context is created +void(__cdecl* glActiveTexture)(GLenum texture); +void(__cdecl* glGenTextures)(GLsizei n, GLuint* textures); +void(__cdecl* glBindTexture)(GLenum target, GLuint texture); +void(__cdecl* glTexStorage1D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +//void(__cdecl* glTexImage1D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void* pixels); +void(__cdecl* glTexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels); +void(__cdecl* glTexParameteri)(GLenum target, GLenum pname, GLint param); +//void(__cdecl* glDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); +void(__cdecl* glBindBuffer)(GLenum target, GLuint buffer); +void(__cdecl* glBindBufferARB)(GLenum target, GLuint buffer); +void(__cdecl* glBufferData)(GLenum target, GLsizeiptr size, const void* data, GLenum usage); +void(__cdecl* glBufferDataARB)(GLenum target, GLsizeiptr size, const void* data, GLenum usage); +void(__cdecl* glFinish)(); + +// just used for a nicer time getting addresses and hooking +struct { + void* ptr; + const char* name; + bool dynamic; +} glFuncs[] = { + //{&glDrawElements, "glDrawElements", false}, + {&glActiveTexture, "glActiveTexture", true}, + {&glGenTextures, "glGenTextures", true}, + {&glBindTexture, "glBindTexture", true}, + {&glTexStorage1D, "glTexStorage1D", true}, + //{&glTexImage1D, "glTexImage1D", true}, + {&glTexSubImage1D, "glTexSubImage1D", true}, + {&glTexParameteri, "glTexParameteri", true}, + //{&glDrawRangeElements, "glDrawRangeElements", true}, + {&glBindBuffer, "glBindBuffer", true}, + {&glBindBufferARB, "glBindBufferARB", true}, + {&glBufferData, "glBufferData", true}, + {&glBufferDataARB, "glBufferDataARB", true}, + {&glFinish, "glFinish", true}, +}; + +bool loadGlAddresses() +{ + bool ret = true; + for (auto fn : glFuncs) + { + if (fn.dynamic) + { + *(PROC*)(fn.ptr) = wglGetProcAddress(fn.name); + if (*(PROC*)(fn.ptr) == nullptr) + { + printf("[Novidia] Failed to load address of %s\n", fn.name); + ret = false; + } + } + } + return ret; +} + +const char* getGlFuncName(void* func) +{ + const char* name = NULL; + for (auto fn : glFuncs) + { + if (func == *(PROC*)(fn.ptr)) + name = fn.name; + } + + return name; +} + +bool hookGlFunc(PROC* target, void* hook) +{ + const char* name = getGlFuncName(*target); + + if (name == nullptr) + { + printf("[Novidia] Invalid hook target at %p\n", *target); + return false; + } + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + printf("[Novidia] Hooking %s\n", name); + DetourAttach(&(PVOID&)*target, hook); + DetourTransactionCommit(); + + return true; +} \ No newline at end of file