From 09dc15b02ba50c81033585c9710357af77b5c55c Mon Sep 17 00:00:00 2001
From: somewhatlurker <52014015+somewhatlurker@users.noreply.github.com>
Date: Wed, 22 Jul 2020 16:28:46 +1000
Subject: [PATCH] add Novidia (non-Nvidia chara skinning)
---
source-code/PD-Loader.sln | 6 +
.../source/plugins/Novidia/Novidia.vcxproj | 98 +++++++++++
.../plugins/Novidia/Novidia.vcxproj.filters | 30 ++++
.../source/plugins/Novidia/src/dllmain.cpp | 163 ++++++++++++++++++
.../source/plugins/Novidia/src/framework.h | 49 ++++++
.../source/plugins/Novidia/src/glStuff.h | 136 +++++++++++++++
6 files changed, 482 insertions(+)
create mode 100644 source-code/source/plugins/Novidia/Novidia.vcxproj
create mode 100644 source-code/source/plugins/Novidia/Novidia.vcxproj.filters
create mode 100644 source-code/source/plugins/Novidia/src/dllmain.cpp
create mode 100644 source-code/source/plugins/Novidia/src/framework.h
create mode 100644 source-code/source/plugins/Novidia/src/glStuff.h
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