mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-05-27 07:37:24 -04:00
New Depth of Field implementation (#1773)
This commit is contained in:
committed by
GitHub
parent
0504f1dda7
commit
af162bbd0a
+13
-1
@@ -15,6 +15,12 @@ enum class BloomMode : int {
|
||||
Dusk = 2,
|
||||
};
|
||||
|
||||
enum class DepthOfFieldMode : int {
|
||||
Off = 0,
|
||||
Classic = 1,
|
||||
Dusk = 2,
|
||||
};
|
||||
|
||||
enum class Resampler : int {
|
||||
Bilinear = 0,
|
||||
Area = 1,
|
||||
@@ -58,6 +64,12 @@ struct ConfigEnumRange<BloomMode> {
|
||||
static constexpr auto max = BloomMode::Dusk;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ConfigEnumRange<DepthOfFieldMode> {
|
||||
static constexpr auto min = DepthOfFieldMode::Off;
|
||||
static constexpr auto max = DepthOfFieldMode::Dusk;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ConfigEnumRange<Resampler> {
|
||||
static constexpr auto min = Resampler::Bilinear;
|
||||
@@ -160,13 +172,13 @@ struct UserSettings {
|
||||
// Graphics
|
||||
ConfigVar<BloomMode> bloomMode;
|
||||
ConfigVar<float> bloomMultiplier;
|
||||
ConfigVar<DepthOfFieldMode> depthOfFieldMode;
|
||||
ConfigVar<bool> disableWaterRefraction;
|
||||
ConfigVar<bool> enableTextureReplacements;
|
||||
ConfigVar<FrameInterpMode> enableFrameInterpolation;
|
||||
ConfigVar<int> internalResolutionScale;
|
||||
ConfigVar<int> shadowResolutionMultiplier;
|
||||
ConfigVar<Resampler> resampler;
|
||||
ConfigVar<bool> enableDepthOfField;
|
||||
ConfigVar<bool> enableMapBackground;
|
||||
ConfigVar<bool> disableCutscenePillarboxing;
|
||||
|
||||
|
||||
@@ -750,7 +750,7 @@ void dMenuMapCommon_c::debugIcon() {
|
||||
|
||||
#if TARGET_PC
|
||||
static constexpr struct {
|
||||
std::string stagename;
|
||||
std::string_view stagename;
|
||||
u8 switch_no;
|
||||
s8 region_id;
|
||||
u8 save_id;
|
||||
|
||||
@@ -172,6 +172,7 @@ namespace dusk::config {
|
||||
template class ConfigImpl<f64>;
|
||||
template class ConfigImpl<std::string>;
|
||||
template class ConfigImpl<dusk::BloomMode>;
|
||||
template class ConfigImpl<dusk::DepthOfFieldMode>;
|
||||
template class ConfigImpl<dusk::DiscVerificationState>;
|
||||
template class ConfigImpl<dusk::GameLanguage>;
|
||||
template class ConfigImpl<dusk::GyroMode>;
|
||||
|
||||
@@ -60,13 +60,13 @@ UserSettings g_userSettings = {
|
||||
// Graphics
|
||||
.bloomMode {"game.bloomMode", BloomMode::Dusk},
|
||||
.bloomMultiplier {"game.bloomMultiplier", 1.0f},
|
||||
.depthOfFieldMode{"game.depthOfFieldMode", DepthOfFieldMode::Dusk},
|
||||
.disableWaterRefraction {"game.disableWaterRefraction", false},
|
||||
.enableTextureReplacements {"game.enableTextureReplacements", true},
|
||||
.enableFrameInterpolation {"game.enableFrameInterpolation", FrameInterpMode::Off},
|
||||
.internalResolutionScale {"game.internalResolutionScale", 0},
|
||||
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
|
||||
.resampler {"game.resampler", Resampler::Bilinear},
|
||||
.enableDepthOfField {"game.enableDepthOfField", true},
|
||||
.enableMapBackground {"game.enableMapBackground", true},
|
||||
.disableCutscenePillarboxing {"game.disableCutscenePillarboxing", false},
|
||||
|
||||
@@ -225,12 +225,12 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.enableDiscordPresence);
|
||||
Register(g_userSettings.game.bloomMode);
|
||||
Register(g_userSettings.game.bloomMultiplier);
|
||||
Register(g_userSettings.game.depthOfFieldMode);
|
||||
Register(g_userSettings.game.disableWaterRefraction);
|
||||
Register(g_userSettings.game.enableTextureReplacements);
|
||||
Register(g_userSettings.game.internalResolutionScale);
|
||||
Register(g_userSettings.game.resampler);
|
||||
Register(g_userSettings.game.shadowResolutionMultiplier);
|
||||
Register(g_userSettings.game.enableDepthOfField);
|
||||
Register(g_userSettings.game.enableMapBackground);
|
||||
Register(g_userSettings.game.disableCutscenePillarboxing);
|
||||
Register(g_userSettings.game.enableFastIronBoots);
|
||||
|
||||
@@ -52,6 +52,8 @@ int get_value(GraphicsOption option) {
|
||||
return std::clamp(
|
||||
static_cast<int>(getSettings().game.bloomMultiplier.getValue() * 100.0f + 0.5f), 0,
|
||||
100);
|
||||
case GraphicsOption::DepthOfFieldMode:
|
||||
return static_cast<int>(getSettings().game.depthOfFieldMode.getValue());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -85,6 +87,10 @@ void set_value(GraphicsOption option, int value) {
|
||||
getSettings().game.bloomMode.setValue(static_cast<BloomMode>(std::clamp(
|
||||
value, static_cast<int>(BloomMode::Off), static_cast<int>(BloomMode::Dusk))));
|
||||
break;
|
||||
case GraphicsOption::DepthOfFieldMode:
|
||||
getSettings().game.depthOfFieldMode.setValue(static_cast<DepthOfFieldMode>(std::clamp(
|
||||
value, static_cast<int>(DepthOfFieldMode::Off), static_cast<int>(DepthOfFieldMode::Dusk))));
|
||||
break;
|
||||
case GraphicsOption::BloomMultiplier:
|
||||
getSettings().game.bloomMultiplier.setValue(std::clamp(value, 0, 100) / 100.0f);
|
||||
break;
|
||||
@@ -214,6 +220,16 @@ Rml::String format_graphics_setting_value(GraphicsOption option, int value) {
|
||||
return "Dusklight";
|
||||
}
|
||||
break;
|
||||
case GraphicsOption::DepthOfFieldMode:
|
||||
switch (static_cast<DepthOfFieldMode>(value)) {
|
||||
case DepthOfFieldMode::Off:
|
||||
return "Off";
|
||||
case DepthOfFieldMode::Classic:
|
||||
return "Classic";
|
||||
case DepthOfFieldMode::Dusk:
|
||||
return "Dusklight";
|
||||
}
|
||||
break;
|
||||
case GraphicsOption::BloomMultiplier:
|
||||
return fmt::format("{}%", value);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ enum class GraphicsOption {
|
||||
Resampler,
|
||||
BloomMode,
|
||||
BloomMultiplier,
|
||||
DepthOfFieldMode,
|
||||
};
|
||||
|
||||
Rml::String format_graphics_setting_value(GraphicsOption option, int value);
|
||||
|
||||
@@ -14,6 +14,7 @@ void applyPresetClassic() {
|
||||
auto& s = getSettings();
|
||||
s.video.lockAspectRatio.setValue(true);
|
||||
s.game.bloomMode.setValue(BloomMode::Classic);
|
||||
s.game.depthOfFieldMode.setValue(DepthOfFieldMode::Classic);
|
||||
s.game.enableAchievementToasts.setValue(false);
|
||||
s.game.enableControllerToasts.setValue(false);
|
||||
s.game.internalResolutionScale.setValue(1);
|
||||
@@ -44,6 +45,7 @@ void applyPresetDusk() {
|
||||
s.game.enableFrameInterpolation.setValue(FrameInterpMode::Unlimited);
|
||||
s.game.sunsSong.setValue(true);
|
||||
s.game.bloomMode.setValue(BloomMode::Dusk);
|
||||
s.game.depthOfFieldMode.setValue(DepthOfFieldMode::Dusk);
|
||||
s.game.internalResolutionScale.setValue(0);
|
||||
s.game.shadowResolutionMultiplier.setValue(4);
|
||||
s.game.enableGyroAim.setValue(true);
|
||||
|
||||
@@ -370,6 +370,9 @@ const Rml::String kBloomHelpText =
|
||||
"a higher-quality bloom pass.";
|
||||
const Rml::String kBloomBrightnessHelpText =
|
||||
"Configure bloom intensity. Higher values make bright areas glow more strongly.";
|
||||
const Rml::String kDepthOfFieldHelpText =
|
||||
"Configure the post-processing depth-of-field effect. Classic uses the original depth-of-field pass;"
|
||||
" Dusklight uses a higher-quality depth-of-field pass.";
|
||||
const Rml::String kUnlockFramerateHelpText =
|
||||
"<br/>Uses inter-frame interpolation to enable higher frame rates.<br/><br/>May introduce minor "
|
||||
"visual artifacts or animation glitches.";
|
||||
@@ -842,7 +845,18 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.valueMax = 100,
|
||||
.defaultValue = 100,
|
||||
.step = 10,
|
||||
}, mPrelaunch);
|
||||
},
|
||||
mPrelaunch);
|
||||
graphics_tuner_control(*this, leftPane, rightPane, getSettings().game.depthOfFieldMode,
|
||||
GraphicsTunerProps{
|
||||
.option = GraphicsOption::DepthOfFieldMode,
|
||||
.title = "Depth of Field",
|
||||
.helpText = kDepthOfFieldHelpText,
|
||||
.valueMin = static_cast<int>(DepthOfFieldMode::Off),
|
||||
.valueMax = static_cast<int>(DepthOfFieldMode::Dusk),
|
||||
.defaultValue = static_cast<int>(DepthOfFieldMode::Classic),
|
||||
},
|
||||
mPrelaunch);
|
||||
|
||||
leftPane.add_section("Rendering");
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.enableTextureReplacements,
|
||||
@@ -884,11 +898,6 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
config_int_select(leftPane, rightPane, getSettings().video.maxFrameRate,
|
||||
"Framerate Cap", "Limit the framerate to the specified value.", 30, 540, 1,
|
||||
[] { return getSettings().game.enableFrameInterpolation.getValue() != FrameInterpMode::Capped; });
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.enableDepthOfField,
|
||||
{
|
||||
.key = "Enable Depth of Field",
|
||||
.helpText = "Render a blurring effect for out-of-focus areas in some situations. May impact performance."
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.enableMapBackground,
|
||||
{
|
||||
.key = "Enable Mini-Map Shadows",
|
||||
|
||||
+132
-26
@@ -928,6 +928,103 @@ void mDoGph_drawFilterQuad(s8 param_0, s8 param_1) {
|
||||
GXTexCoord2s8(0, 1);
|
||||
GXEnd();
|
||||
}
|
||||
|
||||
static void CopyToTexObj(GXTexObj* pDst, uintptr_t texID, u16 dstWidth, u16 dstHeight, GXTexFmt dstFmt = GX_TF_RGBA8) {
|
||||
GXSetTexCopyDst(dstWidth, dstHeight, dstFmt, FALSE);
|
||||
GXCopyTex((void*)texID, false);
|
||||
GXInitTexObj(pDst, (void*)texID, dstWidth, dstHeight, dstFmt, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObjLOD(pDst, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1);
|
||||
}
|
||||
|
||||
static void drawDepth_blurTex(TGXTexObj &dst) {
|
||||
u32 hw = u32(JUTVideo::getManager()->getRenderWidth()) >> 1;
|
||||
u32 hh = u32(JUTVideo::getManager()->getRenderHeight()) >> 1;
|
||||
|
||||
Mtx44 ortho;
|
||||
C_MTXOrtho(ortho, 0.0f, hh, 0.0f, hw, 0.0f, 10.0f);
|
||||
GXLoadPosMtxImm(cMtx_getIdentity(), GX_PNMTX0);
|
||||
GXSetProjection(ortho, GX_ORTHOGRAPHIC);
|
||||
GXSetCurrentMtx(GX_PNMTX0);
|
||||
GXClearVtxDesc();
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S8, 0);
|
||||
|
||||
GXCreateFrameBuffer(hw, hh);
|
||||
|
||||
auto divCopySrc = [&](int divNo) {
|
||||
u32 w = u32(hw) >> divNo, h = u32(hh) >> divNo;
|
||||
GXSetTexCopySrc(0, 0, w, h);
|
||||
};
|
||||
|
||||
enum { MaxTexNum = 4 };
|
||||
TGXTexObj tmpTex[MaxTexNum];
|
||||
auto divCopyTex = [&](uintptr_t texNo, int divNo) -> GXTexObj* {
|
||||
u32 w = u32(hw) >> divNo, h = u32(hh) >> divNo;
|
||||
CopyToTexObj(&tmpTex[texNo], texNo, w, h);
|
||||
return &tmpTex[texNo];
|
||||
};
|
||||
|
||||
auto divQuad = [&](int divNo) {
|
||||
u32 w = u32(hw) >> divNo, h = u32(hh) >> divNo;
|
||||
f32 x0 = 0.0f, y0 = 0.0f;
|
||||
f32 x1 = w, y1 = h;
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
|
||||
GXPosition3f32(x0, y0, -5);
|
||||
GXTexCoord2s8(0, 0);
|
||||
GXPosition3f32(x1, y0, -5);
|
||||
GXTexCoord2s8(1, 0);
|
||||
GXPosition3f32(x1, y1, -5);
|
||||
GXTexCoord2s8(1, 1);
|
||||
GXPosition3f32(x0, y1, -5);
|
||||
GXTexCoord2s8(0, 1);
|
||||
GXEnd();
|
||||
};
|
||||
|
||||
u32 texMtxID = GX_TEXMTX0;
|
||||
int angle = 0;
|
||||
float blurScale = 0.003f;
|
||||
GXSetNumTexGens(8);
|
||||
GXSetNumTevStages(8);
|
||||
for (int stage = 0; stage < 8; stage++) {
|
||||
GXSetTexCoordGen((GXTexCoordID)stage, GX_TG_MTX2x4, GX_TG_TEX0, texMtxID);
|
||||
mDoMtx_stack_c::transS(
|
||||
(blurScale * cM_scos(angle)) * mDoGph_gInf_c::getInvScale(), blurScale * cM_ssin(angle), 0.0f);
|
||||
GXLoadTexMtxImm(mDoMtx_stack_c::get(), texMtxID, GX_MTX2x4);
|
||||
texMtxID += 3;
|
||||
angle += 0x2000;
|
||||
|
||||
GXTevStageID tevStage = (GXTevStageID)stage;
|
||||
GXSetTevOrder(tevStage, (GXTexCoordID)stage, GX_TEXMAP1, GX_COLOR_NULL);
|
||||
GXSetTevColorIn(tevStage, GX_CC_ZERO, GX_CC_TEXC, GX_CC_A1, stage == 0 ? GX_CC_ZERO : GX_CC_CPREV);
|
||||
GXSetTevColorOp(tevStage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
GXSetTevAlphaIn(tevStage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
|
||||
GXSetTevAlphaOp(tevStage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
}
|
||||
GXSetTevColor(GX_TEVREG1, {0, 0, 0, 256 / 8});
|
||||
|
||||
// assume the input tex obj is in GX_TEXMAP1
|
||||
int divNum = 3;
|
||||
for (int i = 0; i < divNum; i++) {
|
||||
// Apply blur filter.
|
||||
divQuad(i);
|
||||
|
||||
// Copy to next layer.
|
||||
divCopySrc(i);
|
||||
|
||||
// Set up for the next pass down.
|
||||
GXTexObj* blurTex = divCopyTex(i, i + 1);
|
||||
GXLoadTexObj(blurTex, GX_TEXMAP1);
|
||||
}
|
||||
|
||||
// upsample back to half-res buffer 0
|
||||
divQuad(0);
|
||||
divCopySrc(0);
|
||||
CopyToTexObj(&dst, 100, hw, hh);
|
||||
|
||||
GXRestoreFrameBuffer();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void drawDepth2(view_class* param_0, view_port_class* param_1, int param_2) {
|
||||
@@ -1081,6 +1178,21 @@ static void drawDepth2(view_class* param_0, view_port_class* param_1, int param_
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.depthOfFieldMode.getValue() == dusk::DepthOfFieldMode::Off)
|
||||
return;
|
||||
|
||||
if (!(l_tevColor0.a > -255 && sp8 == 1))
|
||||
return;
|
||||
|
||||
TGXTexObj blurTex;
|
||||
if (dusk::getSettings().game.depthOfFieldMode.getValue() == dusk::DepthOfFieldMode::Dusk)
|
||||
{
|
||||
drawDepth_blurTex(blurTex);
|
||||
GXLoadTexObj(&blurTex, GX_TEXMAP1);
|
||||
}
|
||||
#endif
|
||||
|
||||
GXSetTevColorS10(GX_TEVREG0, l_tevColor0);
|
||||
GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_ALPHA, GX_CH_GREEN, GX_CH_BLUE, GX_CH_RED);
|
||||
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP3);
|
||||
@@ -1129,37 +1241,42 @@ static void drawDepth2(view_class* param_0, view_port_class* param_1, int param_
|
||||
param_1->x_orig + param_1->width, 0.0f, 10.0f);
|
||||
GXLoadPosMtxImm(cMtx_getIdentity(), 0);
|
||||
|
||||
#if DEBUG
|
||||
#if DEBUG
|
||||
mDoMtx_stack_c::transS(g_kankyoHIO.navy.demo_focus_offset_x, g_kankyoHIO.navy.demo_focus_offset_y, 0.0f);
|
||||
#else
|
||||
#else
|
||||
mDoMtx_stack_c::transS(0.0025f, 0.0025f, 0.0f);
|
||||
#endif
|
||||
GXLoadTexMtxImm(mDoMtx_stack_c::get(), 0x1e, GX_MTX2x4);
|
||||
#endif
|
||||
GXLoadTexMtxImm(mDoMtx_stack_c::get(), GX_TEXMTX0, GX_MTX2x4);
|
||||
|
||||
#if DEBUG
|
||||
#if DEBUG
|
||||
mDoMtx_stack_c::transS(-g_kankyoHIO.navy.demo_focus_offset_x, -g_kankyoHIO.navy.demo_focus_offset_y, 0.0f);
|
||||
#else
|
||||
#else
|
||||
mDoMtx_stack_c::transS(-0.0025f, -0.0025f, 0.0f);
|
||||
#endif
|
||||
GXLoadTexMtxImm(mDoMtx_stack_c::get(), 0x21, GX_MTX2x4);
|
||||
#endif
|
||||
GXLoadTexMtxImm(mDoMtx_stack_c::get(), GX_TEXMTX1, GX_MTX2x4);
|
||||
|
||||
GXClearVtxDesc();
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_POS_XYZ, GX_S8, 0);
|
||||
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3c);
|
||||
GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, 0x1e);
|
||||
GXSetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX0, 0x21);
|
||||
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
||||
GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
|
||||
GXSetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX1);
|
||||
GXSetNumChans(0);
|
||||
GXSetNumTexGens(3);
|
||||
GXSetNumTevStages(4);
|
||||
GXSetProjection(ortho, GX_ORTHOGRAPHIC);
|
||||
GXSetCurrentMtx(0);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::getSettings().game.enableDepthOfField)
|
||||
GXSetProjection(ortho, GX_ORTHOGRAPHIC);
|
||||
GXSetCurrentMtx(GX_PNMTX0);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.depthOfFieldMode.getValue() == dusk::DepthOfFieldMode::Dusk) {
|
||||
GXSetNumTevStages(3);
|
||||
GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR_NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (l_tevColor0.a > -255 && sp8 == 1) {
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
|
||||
GXPosition3s16(x_orig, y_orig_pos, -5);
|
||||
@@ -1334,19 +1451,8 @@ void mDoGph_gInf_c::bloom_c::remove() {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static void CopyToTexObj(GXTexObj* pDst, uintptr_t texID, u16 dstWidth, u16 dstHeight, GXTexFmt dstFmt = GX_TF_RGBA8) {
|
||||
GXSetTexCopyDst(dstWidth, dstHeight, dstFmt, FALSE);
|
||||
GXCopyTex((void*)texID, false);
|
||||
GXInitTexObj(pDst, (void*)texID, dstWidth, dstHeight, dstFmt, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObjLOD(pDst, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1);
|
||||
}
|
||||
|
||||
void mDoGph_gInf_c::bloom_c::draw2() {
|
||||
ZoneScoped;
|
||||
// if (!dusk::getSettings().game.enableBloom) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
bool enabled = mEnable;
|
||||
if (mMonoColor.a == 0 && !enabled)
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user