Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement fog #549

Merged
merged 4 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;

std::array<uint32_t, 128> fogLUT;
bool fogLUTDirty = false;
OFFTKP marked this conversation as resolved.
Show resolved Hide resolved

GPU(Memory& mem, EmulatorConfig& config);
void display() { renderer->display(); }
void screenshot(const std::string& name) { renderer->screenshot(name); }
Expand Down
21 changes: 20 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;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For texenv constant colours it's normally ideal to pass them as uniforms as they change constantly, though we'll see if this is necessary here, since I don't expect games to constantly change fog colour

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,18 @@ namespace PICA {
setupTevStage(4);
setupTevStage(5);
#undef setupTevStage

fogConfig.mode = (FogMode)Helpers::getBits<0, 3>(regs[InternalRegs::TexEnvUpdateBuffer]);
OFFTKP marked this conversation as resolved.
Show resolved Hide resolved
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] & 127;
fogLUT[index] = value;
fogLUTDirty = true;
regs[FogLUTIndex] = (index + 1) & 127;
OFFTKP marked this conversation as resolved.
Show resolved Hide resolved
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) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦊

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦊

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
Loading