Skip to content

Commit

Permalink
Merge pull request #549 from OFFTKP/fog
Browse files Browse the repository at this point in the history
Implement fog
  • Loading branch information
wheremyfoodat authored Jul 21, 2024
2 parents a8c68ba + b8712b3 commit cb2448a
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 33 deletions.
24 changes: 12 additions & 12 deletions .github/gles.patch
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ index 990e2f80..2e7842ac 100644

void main() {
diff --git a/src/host_shaders/opengl_fragment_shader.frag b/src/host_shaders/opengl_fragment_shader.frag
index 9f369e39..b4bb19d3 100644
index b9f9fe4c..f1cf286f 100644
--- a/src/host_shaders/opengl_fragment_shader.frag
+++ b/src/host_shaders/opengl_fragment_shader.frag
@@ -1,4 +1,5 @@
Expand All @@ -31,8 +31,8 @@ index 9f369e39..b4bb19d3 100644

in vec4 v_quaternion;
in vec4 v_colour;
@@ -164,11 +165,17 @@ float lutLookup(uint lut, int index) {
return texelFetch(u_tex_lighting_lut, ivec2(index, int(lut)), 0).r;
@@ -166,11 +167,17 @@ float lutLookup(uint lut, int index) {
return texelFetch(u_tex_luts, ivec2(index, int(lut)), 0).r;
}

+// some gles versions have bitfieldExtractCompat and complain if you redefine it, some don't and compile error, using this instead
Expand All @@ -50,7 +50,7 @@ index 9f369e39..b4bb19d3 100644
}

// Convert an arbitrary-width floating point literal to an f32
@@ -208,16 +215,16 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
@@ -210,16 +217,16 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light

bool current_sampler_enabled = isSamplerEnabled(environment_id, lut_id); // 7 luts per environment

Expand All @@ -70,7 +70,7 @@ index 9f369e39..b4bb19d3 100644
switch (input_id) {
case 0u: {
delta = dot(normal, normalize(half_vector));
@@ -239,11 +246,11 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
@@ -241,11 +248,11 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
int GPUREG_LIGHTi_SPOTDIR_LOW = int(readPicaReg(0x0146u + (light_id << 4u)));
int GPUREG_LIGHTi_SPOTDIR_HIGH = int(readPicaReg(0x0147u + (light_id << 4u)));

Expand All @@ -86,7 +86,7 @@ index 9f369e39..b4bb19d3 100644

if ((se_x & 0x1000) == 0x1000) se_x |= 0xffffe000;
if ((se_y & 0x1000) == 0x1000) se_y |= 0xffffe000;
@@ -270,9 +277,9 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
@@ -272,9 +279,9 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
}

// 0 = enabled
Expand All @@ -98,7 +98,7 @@ index 9f369e39..b4bb19d3 100644
delta = max(delta, 0.0);
} else {
delta = abs(delta);
@@ -296,7 +303,7 @@ vec3 rotateVec3ByQuaternion(vec3 v, vec4 q) {
@@ -298,7 +305,7 @@ vec3 rotateVec3ByQuaternion(vec3 v, vec4 q) {
// Implements the following algorthm: https://mathb.in/26766
void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
uint GPUREG_LIGHTING_ENABLE = readPicaReg(0x008Fu);
Expand All @@ -107,7 +107,7 @@ index 9f369e39..b4bb19d3 100644
primary_color = secondary_color = vec4(0.0);
return;
}
@@ -313,7 +320,7 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
@@ -315,7 +322,7 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
GPUREG_LIGHTING_LUTINPUT_ABS = readPicaReg(0x01D0u);
GPUREG_LIGHTING_LUTINPUT_SELECT = readPicaReg(0x01D1u);

Expand All @@ -116,7 +116,7 @@ index 9f369e39..b4bb19d3 100644

// Bump mode is ignored for now because it breaks some games ie. Toad Treasure Tracker
switch (bump_mode) {
@@ -326,15 +333,15 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
@@ -328,15 +335,15 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);
vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);

Expand All @@ -135,7 +135,7 @@ index 9f369e39..b4bb19d3 100644

uint GPUREG_LIGHTi_SPECULAR0 = readPicaReg(0x0140u + (light_id << 4u));
uint GPUREG_LIGHTi_SPECULAR1 = readPicaReg(0x0141u + (light_id << 4u));
@@ -346,12 +353,12 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
@@ -348,12 +355,12 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {

float light_distance;
vec3 light_position = vec3(
Expand All @@ -151,7 +151,7 @@ index 9f369e39..b4bb19d3 100644
light_vector = light_position + v_view;
}

@@ -367,23 +374,23 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
@@ -369,23 +376,23 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
float NdotL = dot(normal, light_vector); // N dot Li

// Two sided diffuse
Expand Down Expand Up @@ -181,7 +181,7 @@ index 9f369e39..b4bb19d3 100644

float distance_attenuation_bias = decodeFP(GPUREG_LIGHTi_ATTENUATION_BIAS, 7u, 12u);
float distance_attenuation_scale = decodeFP(GPUREG_LIGHTi_ATTENUATION_SCALE, 7u, 12u);
@@ -428,8 +435,8 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
@@ -430,8 +437,8 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
specular_sum.rgb += light_factor * clamp_factor * (specular0 + specular1);
}

Expand Down
2 changes: 1 addition & 1 deletion docs/3ds/lighting.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ lut_id is one of these values
6 RR

lut_index on the other hand represents the actual index of the LUT in the texture
u_tex_lighting_lut has 24 LUTs and they are used like so:
u_tex_luts has 24 LUTs for lighting and they are used like so:
0 D0
1 D1
2 is missing because SP uses LUTs 8-15
Expand Down
3 changes: 3 additions & 0 deletions include/PICA/gpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ class GPU {
// Set to false by the renderer when the lighting_lut is uploaded ot the GPU
bool lightingLUTDirty = false;

bool fogLUTDirty = false;
std::array<uint32_t, 128> fogLUT;

GPU(Memory& mem, EmulatorConfig& config);
void display() { renderer->display(); }
void screenshot(const std::string& name) { renderer->screenshot(name); }
Expand Down
24 changes: 23 additions & 1 deletion include/PICA/pica_frag_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ namespace PICA {
std::array<u32, 4 * 6> tevConfigs;
};

struct FogConfig {
union {
u32 raw{};

BitField<0, 3, FogMode> mode;
BitField<3, 1, u32> flipDepth;
BitField<8, 8, u32> fogColorR;
BitField<16, 8, u32> fogColorG;
BitField<24, 8, u32> fogColorB;
};
};

struct Light {
union {
u16 raw;
Expand Down Expand Up @@ -189,6 +201,7 @@ namespace PICA {
struct FragmentConfig {
OutputConfig outConfig;
TextureConfig texConfig;
FogConfig fogConfig;
LightingConfig lighting;

bool operator==(const FragmentConfig& config) const {
Expand Down Expand Up @@ -220,12 +233,21 @@ namespace PICA {
setupTevStage(4);
setupTevStage(5);
#undef setupTevStage

fogConfig.mode = (FogMode)Helpers::getBits<0, 3>(regs[InternalRegs::TexEnvUpdateBuffer]);

if (fogConfig.mode == FogMode::Fog) {
fogConfig.flipDepth = Helpers::getBit<16>(regs[InternalRegs::TexEnvUpdateBuffer]);
fogConfig.fogColorR = Helpers::getBits<0, 8>(regs[InternalRegs::FogColor]);
fogConfig.fogColorG = Helpers::getBits<8, 8>(regs[InternalRegs::FogColor]);
fogConfig.fogColorB = Helpers::getBits<16, 8>(regs[InternalRegs::FogColor]);
}
}
};

static_assert(
std::has_unique_object_representations<OutputConfig>() && std::has_unique_object_representations<TextureConfig>() &&
std::has_unique_object_representations<Light>()
std::has_unique_object_representations<FogConfig>() && std::has_unique_object_representations<Light>()
);
} // namespace PICA

Expand Down
18 changes: 18 additions & 0 deletions include/PICA/regs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ namespace PICA {
#undef defineTexEnv
// clang-format on

// Fog registers
FogColor = 0xE1,
FogLUTIndex = 0xE6,
FogLUTData0 = 0xE8,
FogLUTData1 = 0xE9,
FogLUTData2 = 0xEA,
FogLUTData3 = 0xEB,
FogLUTData4 = 0xEC,
FogLUTData5 = 0xED,
FogLUTData6 = 0xEE,
FogLUTData7 = 0xEF,

// Framebuffer registers
ColourOperation = 0x100,
BlendFunc = 0x101,
Expand Down Expand Up @@ -384,6 +396,12 @@ namespace PICA {
GreaterOrEqual = 7,
};

enum class FogMode : u32 {
Disabled = 0,
Fog = 5,
Gas = 7,
};

struct TexEnvConfig {
enum class Source : u8 {
PrimaryColor = 0x0,
Expand Down
2 changes: 2 additions & 0 deletions include/PICA/shader_gen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ namespace PICA::ShaderGen {
void compileLUTLookup(std::string& shader, const PICA::FragmentConfig& config, u32 lightIndex, u32 lutID);
bool isSamplerEnabled(u32 environmentID, u32 lutID);

void compileFog(std::string& shader, const PICA::FragmentConfig& config);

public:
FragmentGenerator(API api, Language language) : api(api), language(language) {}
std::string generate(const PICA::FragmentConfig& config);
Expand Down
3 changes: 2 additions & 1 deletion include/renderer_gl/renderer_gl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class RendererGL final : public Renderer {
OpenGL::VertexBuffer dummyVBO;

OpenGL::Texture screenTexture;
OpenGL::Texture lightLUTTexture;
OpenGL::Texture LUTTexture;
OpenGL::Framebuffer screenFramebuffer;
OpenGL::Texture blankTexture;
// The "default" vertex shader to use when using specialized shaders but not PICA vertex shader -> GLSL recompilation
Expand All @@ -90,6 +90,7 @@ class RendererGL final : public Renderer {
void setupUbershaderTexEnv();
void bindTexturesToSlots();
void updateLightingLUT();
void updateFogLUT();
void initGraphicsContextInternal();

public:
Expand Down
3 changes: 3 additions & 0 deletions src/core/PICA/gpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ void GPU::reset() {
lightingLUT.fill(0);
lightingLUTDirty = true;

fogLUT.fill(0);
fogLUTDirty = true;

totalAttribCount = 0;
fixedAttribMask = 0;
fixedAttribIndex = 0;
Expand Down
15 changes: 15 additions & 0 deletions src/core/PICA/regs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,21 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
break;
}

case FogLUTData0:
case FogLUTData1:
case FogLUTData2:
case FogLUTData3:
case FogLUTData4:
case FogLUTData5:
case FogLUTData6:
case FogLUTData7: {
const uint32_t index = regs[FogLUTIndex] & 0x7F;
fogLUT[index] = value;
fogLUTDirty = true;
regs[FogLUTIndex] = (index + 1) & 0x7F;
break;
}

case LightingLUTData0:
case LightingLUTData1:
case LightingLUTData2:
Expand Down
29 changes: 27 additions & 2 deletions src/core/PICA/shader_gen_glsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
uniform sampler2D u_tex0;
uniform sampler2D u_tex1;
uniform sampler2D u_tex2;
uniform sampler2D u_tex_lighting_lut;
uniform sampler2D u_tex_luts;
)";

ret += uniformDefinition;
Expand All @@ -144,7 +144,7 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
}
float lutLookup(uint lut, int index) {
return texelFetch(u_tex_lighting_lut, ivec2(index, int(lut)), 0).r;
return texelFetch(u_tex_luts, ivec2(index, int(lut)), 0).r;
}
vec3 regToColor(uint reg) {
Expand Down Expand Up @@ -194,6 +194,8 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
compileTEV(ret, i, config);
}

compileFog(ret, config);

applyAlphaTest(ret, config);

ret += "fragColor = combinerOutput;\n}"; // End of main function
Expand Down Expand Up @@ -652,4 +654,27 @@ void FragmentGenerator::compileLUTLookup(std::string& shader, const PICA::Fragme
shader += "lut_lookup_result *= " + std::to_string(scales[scale]) + ";\n";
}
}
}

void FragmentGenerator::compileFog(std::string& shader, const PICA::FragmentConfig& config) {
if (config.fogConfig.mode != FogMode::Fog) {
return;
}

float r = config.fogConfig.fogColorR / 255.0f;
float g = config.fogConfig.fogColorG / 255.0f;
float b = config.fogConfig.fogColorB / 255.0f;

if (config.fogConfig.flipDepth) {
shader += "float fog_index = (1.0 - depth) * 128.0;\n";
} else {
shader += "float fog_index = depth * 128.0;\n";
}

shader += "float clamped_index = clamp(floor(fog_index), 0.0, 127.0);";
shader += "float delta = fog_index - clamped_index;";
shader += "vec3 fog_color = vec3(" + std::to_string(r) + ", " + std::to_string(g) + ", " + std::to_string(b) + ");";
shader += "vec2 value = texelFetch(u_tex_luts, ivec2(int(clamped_index), 24), 0).rg;"; // fog LUT is past the light LUTs
shader += "float fog_factor = clamp(value.r + value.g * delta, 0.0, 1.0);";
shader += "combinerOutput.rgb = mix(fog_color, combinerOutput.rgb, fog_factor);";
}
Loading

0 comments on commit cb2448a

Please sign in to comment.