ShaderPatch: add patch config, copy lyb's toon shader improvements
This commit is contained in:
@@ -1,3 +1,33 @@
|
||||
blinn_per_vert\.0010010[23]00[01]\.fp=arch:GP,TU,GV,GM||from:TEX tex_col, a_tex_color0, texture\[0\], 2D; ALIAS||to:TEX tex_col, a_tex_color0, texture[0], 2D; MUL tex_col, 1, tex_col; ALIAS
|
||||
esm_gauss\.0\.fp=arch:TU||from:RCP sum.y, sum.y;(\r?\n) MUL||to:RCP sum.y, sum.y; ADD sum.x, sum.x, 0.000300;$1 MUL
|
||||
cloth_npr1\.fp=arch:TU||from:SSG _tmp0.yw, ybr.xxzz;||to:TEMP _tmpForSSG; SGE _tmpForSSG.xz, ybr.xxzz, 0; SUB _tmpForSSG.xz, _tmpForSSG.xxzz, 1; SGT _tmpForSSG.yw, ybr.xxzz, 0; ADD _tmp0.yw, _tmpForSSG.xxzz, _tmpForSSG.yyww;
|
||||
[Config]
|
||||
# Patches to remove glitching with modern GPUs.
|
||||
# Appropriate patches will automatically be selected based on your GPU.
|
||||
Compat=1
|
||||
|
||||
# Lyb's toon shader improvements (24 sept 2019)
|
||||
# Toon: Set to `0.9, -0.5` (or another pair of values) to use
|
||||
Toon=0
|
||||
# Toon_Eyes: Set to anything except 0 to use
|
||||
Toon_Eyes=0
|
||||
# Toon_Hair: Set to `1.25` (or another value) to use
|
||||
Toon_Hair=0
|
||||
# Toon_Lines1: Set to `0.75` (or another value) to use
|
||||
Toon_Lines1=0
|
||||
# Toon_Lines2: Set to `0.75, 0.75` (or another pair of values) to use
|
||||
Toon_Lines2=0
|
||||
|
||||
[Patches]
|
||||
# Compatibility patches:
|
||||
# Star Story (and etc.) stage corruption (Maxwell+)
|
||||
blinn_per_vert\.0010010[23]00[01]\.fp=arch:GP,TU,GV,GM||cfg:compat||from:TEX tex_col, a_tex_color0, texture\[0\], 2D; ALIAS||to:TEX tex_col, a_tex_color0, texture[0], 2D; MUL tex_col, 1, tex_col; ALIAS
|
||||
# Turing shading lines
|
||||
esm_gauss\.0\.fp=arch:TU||cfg:compat||from:RCP sum.y, sum.y;(\r?\n) MUL||to:RCP sum.y, sum.y; ADD sum.x, sum.x, 0.000300;$1 MUL
|
||||
# Turing NPR cloth noise
|
||||
cloth_npr1\.fp=arch:TU||cfg:compat||from:SSG _tmp0.yw, ybr.xxzz;||to:TEMP _tmpForSSG; SGE _tmpForSSG.xz, ybr.xxzz, 0; SUB _tmpForSSG.xz, _tmpForSSG.xxzz, 1; SGT _tmpForSSG.yw, ybr.xxzz, 0; ADD _tmp0.yw, _tmpForSSG.xxzz, _tmpForSSG.yyww;
|
||||
|
||||
# Lyb's toon shader improvements:
|
||||
.*cloth_npr.*=cfg:toon||from:MAD tmp.y, lc.z, 1.2, -0.5;||to:MAD tmp.y, lc.z, <cfg>;
|
||||
.*skin_default.*=cfg:toon||from:MAD diff.xyz, spec, spec_ratio, diff;||to:
|
||||
.*eye.*=cfg:toon_eyes||from:ADD o_color_f0.w, diff.x, diff.y;||to:
|
||||
.*hair_npr1.*=cfg:toon_hair||from:MUL spec.x, tmp.x, 0.7;||to:MUL spec.x, tmp.x, 0.7; MUL diff, diff, <cfg>;
|
||||
.*tone_map_npr1.*=cfg:toon_lines1||from:MUL density.y, density.y, 0.25;||to:MUL density.y, density.y, <cfg>;
|
||||
.*tone_map_npr1.*=cfg:toon_lines2||from:MAD density.w, density.x, 0.7, 0.25;||to:MAD density.w, density.x, <cfg>;
|
||||
@@ -29,6 +29,139 @@ void NopBytes(void* address, unsigned int num)
|
||||
}
|
||||
|
||||
|
||||
void loadGpuName()
|
||||
{
|
||||
NvAPI_QueryInterface = (void*(*)(unsigned int offset))GetProcAddress(LoadLibrary("nvapi64.dll"), "nvapi_QueryInterface");
|
||||
|
||||
if (NvAPI_QueryInterface == nullptr)
|
||||
{
|
||||
gpuName = "Other";
|
||||
return;
|
||||
}
|
||||
|
||||
NvAPI_Initialize = (int(*)())NvAPI_QueryInterface(0x0150E828);
|
||||
NvAPI_Unload = (int(*)()) NvAPI_QueryInterface(0xD22BDD7E);
|
||||
NvAPI_EnumPhysicalGPUs = (int(*)(int64_t** handle, int* count))NvAPI_QueryInterface(0xE5AC921F);
|
||||
NvAPI_GPU_GetShortName = (int(*)(int64_t* handle, char* name))NvAPI_QueryInterface(0xD988F0F3);
|
||||
|
||||
if (NvAPI_Initialize == nullptr ||
|
||||
NvAPI_Unload == nullptr ||
|
||||
NvAPI_EnumPhysicalGPUs == nullptr ||
|
||||
NvAPI_GPU_GetShortName == nullptr)
|
||||
{
|
||||
gpuName = "Unknown";
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t* hdlGpu[64] = { 0 };
|
||||
int nGpu = 0;
|
||||
|
||||
NvAPI_Initialize();
|
||||
NvAPI_EnumPhysicalGPUs(hdlGpu, &nGpu);
|
||||
|
||||
//printf("[ShaderPatch] nGpu: %d\n", nGpu);
|
||||
if (nGpu < 1)
|
||||
{
|
||||
gpuName = "Unknown";
|
||||
NvAPI_Unload();
|
||||
return;
|
||||
}
|
||||
|
||||
char nameBuf[64];
|
||||
NvAPI_GPU_GetShortName(hdlGpu[0], nameBuf);
|
||||
NvAPI_Unload();
|
||||
|
||||
gpuName = nameBuf;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void LoadConfig()
|
||||
{
|
||||
std::ifstream fileStream(CONFIG_FILE_STRING);
|
||||
|
||||
if (!fileStream.is_open())
|
||||
return;
|
||||
|
||||
std::string line;
|
||||
std::string section = "patches";
|
||||
|
||||
// check for BOM
|
||||
std::getline(fileStream, line);
|
||||
if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0)
|
||||
fileStream.seekg(3);
|
||||
else
|
||||
fileStream.seekg(0);
|
||||
|
||||
while (std::getline(fileStream, line))
|
||||
{
|
||||
if (line.size() <= 0 || line[0] == '#' || (line.size() >= 2 && line.rfind("//", 0) == 0))
|
||||
continue;
|
||||
|
||||
if (line[0] == '[') // section name
|
||||
{
|
||||
size_t endIdx = line.find(']');
|
||||
section = line.substr(1, endIdx - 1);
|
||||
std::transform(section.begin(), section.end(), section.begin(), ::tolower);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::string> equalSplit = SplitString(line, "=");
|
||||
if (equalSplit.size() < 2) continue;
|
||||
|
||||
if (section == "patches")
|
||||
{
|
||||
ShaderPatchInfo patch = ShaderPatchInfo();
|
||||
|
||||
patch.fileRegex = equalSplit[0];
|
||||
|
||||
std::vector<std::string> rules = SplitString(equalSplit[1], "||");
|
||||
if (rules.size() < 1) continue; // probably will never trigger but whatever
|
||||
|
||||
for (std::string &rule : rules)
|
||||
{
|
||||
if (rule.size() >= 5 && rule.rfind("arch:", 0) == 0)
|
||||
{
|
||||
rule.erase(0, 5);
|
||||
patch.archs = SplitString(rule, ",");
|
||||
}
|
||||
else if (rule.size() >= 4 && rule.rfind("cfg:", 0) == 0)
|
||||
{
|
||||
rule.erase(0, 4);
|
||||
// force cfg key to lower because ini shouldn't be case sensitive
|
||||
std::transform(rule.begin(), rule.end(), rule.begin(), ::tolower);
|
||||
patch.cfg = rule;
|
||||
}
|
||||
else if (rule.size() >= 5 && rule.rfind("from:", 0) == 0)
|
||||
{
|
||||
rule.erase(0, 5);
|
||||
patch.dataRegex = rule;
|
||||
}
|
||||
else if (rule.size() >= 3 && rule.rfind("to:", 0) == 0)
|
||||
{
|
||||
rule.erase(0, 3);
|
||||
patch.dataReplace = rule;
|
||||
}
|
||||
}
|
||||
|
||||
patchesVec.push_back(patch);
|
||||
}
|
||||
else if (section == "config")
|
||||
{
|
||||
equalSplit[1] = TrimString(equalSplit[1], " \t");
|
||||
if (equalSplit[1] != "0") // ignore when == 0 to allow disabling via checkbox
|
||||
{
|
||||
// force cfg key to lower because ini shouldn't be case sensitive
|
||||
std::transform(equalSplit[0].begin(), equalSplit[0].end(), equalSplit[0].begin(), ::tolower);
|
||||
configMap.insert(std::pair<std::string, std::string>(equalSplit[0], equalSplit[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileStream.close();
|
||||
}
|
||||
|
||||
|
||||
void hookedLoadFromFarcThunk(FArchivedFile** ppFile)
|
||||
{
|
||||
loadFromFarcThunk(ppFile);
|
||||
@@ -46,22 +179,39 @@ void hookedLoadFromFarcThunk(FArchivedFile** ppFile)
|
||||
for (ShaderPatchInfo &patch : patchesVec)
|
||||
{
|
||||
bool archMatches = false;
|
||||
|
||||
for (std::string &arch : patch.archs)
|
||||
if (patch.archs.size() > 0)
|
||||
{
|
||||
if (gpuName.size() >= arch.size() && gpuName.rfind(arch, 0) == 0)
|
||||
for (std::string &arch : patch.archs)
|
||||
{
|
||||
archMatches = true;
|
||||
break;
|
||||
if (gpuName.size() >= arch.size() && gpuName.rfind(arch, 0) == 0)
|
||||
{
|
||||
archMatches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
archMatches = true;
|
||||
}
|
||||
|
||||
if (archMatches && std::regex_match(file.fileName.GetCharBuf(), patch.fileRegex))
|
||||
bool cfgMatches = false;
|
||||
if (patch.cfg.length() == 0 || configMap.find(patch.cfg) != configMap.end())
|
||||
{
|
||||
cfgMatches = true;
|
||||
}
|
||||
|
||||
if (archMatches && cfgMatches && std::regex_match(file.fileName.GetCharBuf(), patch.fileRegex))
|
||||
{
|
||||
if (modifiedStr.length() == 0)
|
||||
modifiedStr = std::string(file.data, file.dataSize);
|
||||
|
||||
modifiedStr = std::regex_replace(modifiedStr, patch.dataRegex, patch.dataReplace);
|
||||
|
||||
if (patch.cfg.length() > 0)
|
||||
{
|
||||
modifiedStr = StringReplace(modifiedStr, "<cfg>", configMap[patch.cfg]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <stdint.h>
|
||||
#include <fstream>
|
||||
@@ -13,10 +14,13 @@ struct ShaderPatchInfo {
|
||||
std::regex dataRegex;
|
||||
std::string dataReplace;
|
||||
std::vector<std::string> archs;
|
||||
std::string cfg;
|
||||
};
|
||||
|
||||
std::vector<ShaderPatchInfo> patchesVec;
|
||||
|
||||
std::map<std::string, std::string> configMap;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct MsString {
|
||||
union {
|
||||
@@ -57,52 +61,6 @@ int(*NvAPI_Unload)() = NULL;
|
||||
int(*NvAPI_EnumPhysicalGPUs)(int64_t** handle, int* count) = NULL;
|
||||
int(*NvAPI_GPU_GetShortName)(int64_t* handle, char* name) = NULL;
|
||||
|
||||
void loadGpuName()
|
||||
{
|
||||
NvAPI_QueryInterface = (void*(*)(unsigned int offset))GetProcAddress(LoadLibrary("nvapi64.dll"), "nvapi_QueryInterface");
|
||||
|
||||
if (NvAPI_QueryInterface == nullptr)
|
||||
{
|
||||
gpuName = "Other";
|
||||
return;
|
||||
}
|
||||
|
||||
NvAPI_Initialize = (int(*)())NvAPI_QueryInterface(0x0150E828);
|
||||
NvAPI_Unload = (int(*)()) NvAPI_QueryInterface(0xD22BDD7E);
|
||||
NvAPI_EnumPhysicalGPUs = (int(*)(int64_t** handle, int* count))NvAPI_QueryInterface(0xE5AC921F);
|
||||
NvAPI_GPU_GetShortName = (int(*)(int64_t* handle, char* name))NvAPI_QueryInterface(0xD988F0F3);
|
||||
|
||||
if (NvAPI_Initialize == nullptr ||
|
||||
NvAPI_Unload == nullptr ||
|
||||
NvAPI_EnumPhysicalGPUs == nullptr ||
|
||||
NvAPI_GPU_GetShortName == nullptr)
|
||||
{
|
||||
gpuName = "Unknown";
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t* hdlGpu[64] = { 0 };
|
||||
int nGpu = 0;
|
||||
|
||||
NvAPI_Initialize();
|
||||
NvAPI_EnumPhysicalGPUs(hdlGpu, &nGpu);
|
||||
|
||||
//printf("[ShaderPatch] nGpu: %d\n", nGpu);
|
||||
if (nGpu < 1)
|
||||
{
|
||||
gpuName = "Unknown";
|
||||
NvAPI_Unload();
|
||||
return;
|
||||
}
|
||||
|
||||
char nameBuf[64];
|
||||
NvAPI_GPU_GetShortName(hdlGpu[0], nameBuf);
|
||||
NvAPI_Unload();
|
||||
|
||||
gpuName = nameBuf;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string> SplitString(const std::string& str, const std::string& delim)
|
||||
@@ -126,6 +84,36 @@ std::vector<std::string> SplitString(const std::string& str, const std::string&
|
||||
return tokens;
|
||||
}
|
||||
|
||||
std::string TrimString(const std::string& str, const std::string& whitespace)
|
||||
{
|
||||
const size_t strBegin = str.find_first_not_of(whitespace);
|
||||
|
||||
if (strBegin == std::string::npos)
|
||||
return "";
|
||||
|
||||
const size_t strEnd = str.find_last_not_of(whitespace);
|
||||
const size_t strRange = strEnd - strBegin + 1;
|
||||
|
||||
return str.substr(strBegin, strRange);
|
||||
}
|
||||
|
||||
std::string StringReplace(const std::string& str, const std::string& srch, const std::string& repl)
|
||||
{
|
||||
size_t pos = 0;
|
||||
std::string outstr = str;
|
||||
|
||||
while (true)
|
||||
{
|
||||
pos = outstr.find(srch, pos);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
outstr.replace(pos, srch.length(), repl);
|
||||
}
|
||||
|
||||
return outstr;
|
||||
}
|
||||
|
||||
|
||||
std::wstring ExePath() {
|
||||
WCHAR buffer[MAX_PATH];
|
||||
@@ -142,64 +130,3 @@ std::wstring DirPath() {
|
||||
std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\ShaderPatch.ini";
|
||||
LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str();
|
||||
|
||||
void LoadConfig()
|
||||
{
|
||||
std::ifstream fileStream(CONFIG_FILE_STRING);
|
||||
|
||||
if (!fileStream.is_open())
|
||||
return;
|
||||
|
||||
std::string line;
|
||||
|
||||
// check for BOM
|
||||
std::getline(fileStream, line);
|
||||
if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0)
|
||||
fileStream.seekg(3);
|
||||
else
|
||||
fileStream.seekg(0);
|
||||
|
||||
while (std::getline(fileStream, line))
|
||||
{
|
||||
try {
|
||||
if (line.size() <= 0 || line[0] == '#' || line[0] == '[' || (line.size() >= 2 && line.rfind("//", 0) == 0))
|
||||
continue;
|
||||
|
||||
std::vector<std::string> equalSplit = SplitString(line, "=");
|
||||
if (equalSplit.size() < 2) continue;
|
||||
|
||||
ShaderPatchInfo patch = ShaderPatchInfo();
|
||||
|
||||
patch.fileRegex = equalSplit[0];
|
||||
|
||||
std::vector<std::string> rules = SplitString(equalSplit[1], "||");
|
||||
if (rules.size() < 1) continue; // probably will never trigger but whatever
|
||||
|
||||
for (std::string &rule : rules)
|
||||
{
|
||||
if (rule.size() >= 5 && rule.rfind("arch:", 0) == 0)
|
||||
{
|
||||
rule.erase(0, 5);
|
||||
patch.archs = SplitString(rule, ",");
|
||||
}
|
||||
else if (rule.size() >= 5 && rule.rfind("from:", 0) == 0)
|
||||
{
|
||||
rule.erase(0, 5);
|
||||
patch.dataRegex = rule;
|
||||
}
|
||||
else if (rule.size() >= 3 && rule.rfind("to:", 0) == 0)
|
||||
{
|
||||
rule.erase(0, 3);
|
||||
patch.dataReplace = rule;
|
||||
}
|
||||
}
|
||||
|
||||
patchesVec.push_back(patch);
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fileStream.close();
|
||||
}
|
||||
Reference in New Issue
Block a user