Files
sfall/sfall/Modules/ScriptShaders.cpp
T
NovaRain 0dd8ea5335 Added loading multiple shader files for GlobalShaderFile option
Added a sharpen filter file as a global shader example.
Set TextureFilter to be enabled by default.
2020-09-21 12:54:42 +08:00

233 lines
6.8 KiB
C++

/*
* sfall
* Copyright (C) 2008-2019 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
#include "Graphics.h"
#include "LoadGameHook.h"
#include "ScriptShaders.h"
namespace sfall
{
#define SAFERELEASE(a) { if (a) { a->Release(); a = nullptr; } }
static size_t shadersSize;
static bool globalShadersActive = false;
struct GlobalShader {
std::string gShaderFile;
bool badShader = false;
GlobalShader(std::string file) {
gShaderFile = std::move(file);
}
};
struct sShader {
ID3DXEffect* Effect;
D3DXHANDLE ehTicks;
DWORD mode;
DWORD mode2;
bool Active;
sShader() : Effect(0), ehTicks(0), mode(0), mode2(0), Active(false) {}
};
static std::vector<GlobalShader> gShaderFiles;
static std::vector<sShader> shaders;
static std::vector<IDirect3DTexture9*> shaderTextures;
size_t ScriptShaders::Count() {
return shadersSize;
}
void __stdcall SetShaderMode(DWORD d, DWORD mode) {
if (d >= shadersSize || !shaders[d].Effect) return;
if (mode & 0x80000000) {
shaders[d].mode2 = mode ^ 0x80000000;
} else {
shaders[d].mode = mode;
}
}
int __stdcall LoadShader(const char* file) {
if (!Graphics::mode || strstr(file, "..") || strstr(file, ":")) return -1;
char buf[MAX_PATH];
sprintf_s(buf, "%s\\shaders\\%s", fo::var::master_db_handle->path, file); // fo::var::patches
for (DWORD d = 0; d < shadersSize; d++) {
if (!shaders[d].Effect) {
if (FAILED(D3DXCreateEffectFromFile(d3d9Device, buf, 0, 0, 0, 0, &shaders[d].Effect, 0))) {
return -1;
} else {
return d;
}
}
}
sShader shader = sShader();
if (FAILED(D3DXCreateEffectFromFile(d3d9Device, buf, 0, 0, 0, 0, &shader.Effect, 0))) return -1;
shader.Effect->SetFloatArray("rcpres", Graphics::rcpresGet(), 2);
for (int i = 1; i < 128; i++) {
const char* name;
IDirect3DTexture9* tex;
sprintf(buf, "texname%d", i);
if (FAILED(shader.Effect->GetString(buf, &name))) break;
sprintf_s(buf, "%s\\art\\stex\\%s", fo::var::master_db_handle->path, name); // fo::var::patches
if (FAILED(D3DXCreateTextureFromFileA(d3d9Device, buf, &tex))) continue;
sprintf(buf, "tex%d", i);
shader.Effect->SetTexture(buf, tex);
shaderTextures.push_back(tex);
}
shader.ehTicks = shader.Effect->GetParameterByName(0, "tickcount");
shaders.push_back(shader);
shadersSize = shaders.size();
return shadersSize - 1;
}
void ScriptShaders::LoadGlobalShader() {
if (!globalShadersActive) return;
for (auto &shader : gShaderFiles) {
if (shader.badShader) continue;
long index = LoadShader(shader.gShaderFile.c_str());
if (index != -1) {
shaders[index].Effect->SetInt("w", Graphics::GetGameWidthRes());
shaders[index].Effect->SetInt("h", Graphics::GetGameHeightRes());
shaders[index].Active = true;
dlog_f("Global shader file %s is loaded.\n", DL_INIT, shader.gShaderFile.c_str());
} else {
shader.badShader = true;
}
}
}
void __stdcall ActivateShader(DWORD d) {
if (d < shadersSize && shaders[d].Effect) shaders[d].Active = true;
}
void __stdcall DeactivateShader(DWORD d) {
if (d < shadersSize) shaders[d].Active = false;
}
int __stdcall GetShaderTexture(DWORD d, DWORD id) {
if (id < 1 || id > 128 || d >= shadersSize || !shaders[d].Effect) return -1;
IDirect3DBaseTexture9* tex = 0;
char buf[8] = "tex";
_itoa_s(id, &buf[3], 4, 10);
if (FAILED(shaders[d].Effect->GetTexture(buf, &tex)) || !tex) return -1;
tex->Release();
for (DWORD i = 0; i < shaderTextures.size(); i++) {
if (shaderTextures[i] == tex) return i;
}
return -1;
}
void __stdcall FreeShader(DWORD d) {
if (d < shadersSize) {
SAFERELEASE(shaders[d].Effect);
shaders[d].Active = false;
}
}
void __stdcall SetShaderInt(DWORD d, const char* param, int value) {
if (d >= shadersSize || !shaders[d].Effect) return;
shaders[d].Effect->SetInt(param, value);
}
void __stdcall SetShaderFloat(DWORD d, const char* param, float value) {
if (d >= shadersSize || !shaders[d].Effect) return;
shaders[d].Effect->SetFloat(param, value);
}
void __stdcall SetShaderVector(DWORD d, const char* param, float f1, float f2, float f3, float f4) {
if (d >= shadersSize || !shaders[d].Effect) return;
shaders[d].Effect->SetFloatArray(param, &f1, 4);
}
void __stdcall SetShaderTexture(DWORD d, const char* param, DWORD value) {
if (d >= shadersSize || !shaders[d].Effect || value >= shaderTextures.size()) return;
shaders[d].Effect->SetTexture(param, shaderTextures[value]);
}
static void ResetShaders() {
for (DWORD d = 0; d < shadersSize; d++) SAFERELEASE(shaders[d].Effect);
shaders.clear();
shadersSize = 0;
ScriptShaders::LoadGlobalShader();
}
void ScriptShaders::Refresh(IDirect3DSurface9* sSurf1, IDirect3DSurface9* sSurf2, IDirect3DTexture9* sTex2) {
for (int i = shadersSize - 1; i >= 0; i--) {
if (!shaders[i].Effect || !shaders[i].Active) continue;
if (shaders[i].mode2 && !(shaders[i].mode2 & GetLoopFlags())) continue;
if (shaders[i].mode & GetLoopFlags()) continue;
if (shaders[i].ehTicks) shaders[i].Effect->SetInt(shaders[i].ehTicks, GetTickCount());
UINT passes;
shaders[i].Effect->Begin(&passes, 0);
for (DWORD pass = 0; pass < passes; pass++) {
shaders[i].Effect->BeginPass(pass);
d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
shaders[i].Effect->EndPass();
d3d9Device->StretchRect(sSurf1, 0, sSurf2, 0, D3DTEXF_NONE); // copy sSurf1 to sSurf2
d3d9Device->SetTexture(0, sTex2);
}
shaders[i].Effect->End();
d3d9Device->SetTexture(0, sTex2);
}
}
void ScriptShaders::OnResetDevice() {
for (DWORD d = 0; d < shadersSize; d++) {
if (shaders[d].Effect) shaders[d].Effect->OnResetDevice();
}
}
void ScriptShaders::OnLostDevice() {
for (DWORD d = 0; d < shadersSize; d++) {
if (shaders[d].Effect) shaders[d].Effect->OnLostDevice();
}
}
void ScriptShaders::Release() {
globalShadersActive = false;
ResetShaders();
for (DWORD d = 0; d < shaderTextures.size(); d++) shaderTextures[d]->Release();
shaderTextures.clear();
}
void ScriptShaders::init() {
if (Graphics::mode) {
for each (const auto& shaderFile in GetConfigList("Graphics", "GlobalShaderFile", "", 1024)) {
if (shaderFile.length() > 3) gShaderFiles.push_back(GlobalShader(shaderFile));
}
globalShadersActive = !gShaderFiles.empty();
LoadGameHook::OnGameReset() += ResetShaders;
}
}
}