diff --git a/aurora/include/aurora/gfx.hpp b/aurora/include/aurora/gfx.hpp index 4f9b0dd05..0af12a153 100644 --- a/aurora/include/aurora/gfx.hpp +++ b/aurora/include/aurora/gfx.hpp @@ -70,7 +70,7 @@ struct ClipRect { struct Light { zeus::CVector3f pos{0.f, 0.f, 0.f}; zeus::CVector3f dir{0.f, 0.f, -1.f}; - zeus::CColor color{0.f, 0.f, 0.f, 0.f}; + zeus::CColor color{0.f, 1.f}; zeus::CVector3f linAtt{1.f, 0.f, 0.f}; zeus::CVector3f angAtt{1.f, 0.f, 0.f}; }; @@ -89,10 +89,6 @@ struct ScopedDebugGroup { void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept; void unbind_texture(GX::TexMapID id) noexcept; -// TODO migrate to GX -void load_light(GX::LightID id, const Light& light) noexcept; -void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept; - void set_viewport(float left, float top, float width, float height, float znear, float zfar) noexcept; void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept; diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index 6adf5b992..9a4275fde 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -92,19 +92,13 @@ void GXSetChanCtrl(GX::ChannelID id, bool lightingEnabled, GX::ColorSrc ambSrc, Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id); unreachable(); } - if (diffFn != GX::DF_NONE && diffFn != GX::DF_CLAMP) { - Log.report(logvisor::Fatal, FMT_STRING("unhandled diffuse fn {}"), diffFn); - unreachable(); - } - if (attnFn != GX::AF_NONE && attnFn != GX::AF_SPOT) { - Log.report(logvisor::Fatal, FMT_STRING("unhandled attn fn {}"), attnFn); - unreachable(); - } u32 idx = id - GX::COLOR0A0; auto& chan = g_gxState.colorChannelConfig[idx]; chan.lightingEnabled = lightingEnabled; chan.ambSrc = ambSrc; chan.matSrc = matSrc; + chan.diffFn = diffFn; + chan.attnFn = attnFn; g_gxState.colorChannelState[idx].lightState = lightState; } void GXSetAlphaCompare(GX::Compare comp0, u8 ref0, GX::AlphaOp op, GX::Compare comp1, u8 ref1) noexcept { @@ -361,37 +355,7 @@ void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, floa void GXInitLightColor(GX::LightObj* light, GX::Color col) { light->color = col; } void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) { - u32 idx = 0; - switch (id) { - case GX::LIGHT0: - idx = 0; - break; - case GX::LIGHT1: - idx = 1; - break; - case GX::LIGHT2: - idx = 2; - break; - case GX::LIGHT3: - idx = 3; - break; - case GX::LIGHT4: - idx = 4; - break; - case GX::LIGHT5: - idx = 5; - break; - case GX::LIGHT6: - idx = 6; - break; - case GX::LIGHT7: - idx = 7; - break; - default: - idx = 0; - break; - } - + u32 idx = std::log2(id); aurora::gfx::Light realLight; realLight.pos.assign(light->px, light->py, light->pz); realLight.dir.assign(light->nx, light->ny, light->nz); @@ -442,11 +406,6 @@ void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHan } void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast(id)].reset(); } -void load_light(GX::LightID id, const Light& light) noexcept { gx::g_gxState.lights[std::log2(id)] = light; } -void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept { - gx::g_gxState.lights[std::log2(id)] = ambient; -} - namespace gx { using gpu::g_device; using gpu::g_graphicsConfig; @@ -829,27 +788,21 @@ Range build_uniform(const ShaderInfo& info) noexcept { buf.append(&g_gxState.colorChannelState[i].matColor, 16); if (g_gxState.colorChannelConfig[i].lightingEnabled) { - zeus::CColor ambient = zeus::skClear; int addedLights = 0; const auto& lightState = g_gxState.colorChannelState[i].lightState; for (int li = 0; li < lightState.size(); ++li) { if (!lightState.test(li)) { continue; } - const auto& variant = g_gxState.lights[li]; - if (std::holds_alternative(variant)) { - ambient += std::get(variant); - } else if (std::holds_alternative(variant)) { - static_assert(sizeof(Light) == 80); - buf.append(&std::get(variant), sizeof(Light)); - ++addedLights; - } + const auto& light = g_gxState.lights[li]; + static_assert(sizeof(Light) == 80); + buf.append(&light, sizeof(Light)); + ++addedLights; } constexpr Light emptyLight{}; for (int li = addedLights; li < GX::MaxLights; ++li) { buf.append(&emptyLight, sizeof(Light)); } - buf.append(&ambient, 16); } } for (int i = 0; i < info.sampledKColors.size(); ++i) { diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index af7d31285..face98395 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -75,6 +75,8 @@ struct TextureBind { struct ColorChannelConfig { GX::ColorSrc matSrc = GX::SRC_REG; GX::ColorSrc ambSrc = GX::SRC_REG; + GX::DiffuseFn diffFn = GX::DF_NONE; + GX::AttnFn attnFn = GX::AF_NONE; bool lightingEnabled = false; u8 _p1 = 0; u8 _p2 = 0; @@ -149,7 +151,7 @@ struct GXState { std::array kcolors; std::array colorChannelConfig; std::array colorChannelState; - std::array lights; + std::array lights; std::array tevStages; std::array textures; std::array texMtxs; diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index 2591dcd42..6ae97e106 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -548,7 +548,7 @@ ShaderInfo build_shader_info(const ShaderConfig& config) noexcept { if (info.sampledColorChannels.test(i)) { info.uniformSize += 32; if (config.colorChannels[i].lightingEnabled) { - info.uniformSize += (80 * GX::MaxLights) + 16; + info.uniformSize += (80 * GX::MaxLights); } } } @@ -758,7 +758,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in "\n out.pos = ubuf.proj * vec4(mv_pos, 1.0);"), vtx_attr(config, GX::VA_POS), vtx_attr(config, GX::VA_NRM)); if constexpr (EnableNormalVisualization) { - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3;"), vtxOutIdx++); + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3,"), vtxOutIdx++); vtxXfrAttrsPre += "\n out.nrm = mv_nrm;"; } @@ -825,7 +825,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in } for (int i = 0; i < info.usesTevReg.size(); ++i) { if (info.usesTevReg.test(i)) { - uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4;"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4,"), i); fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i); } } @@ -835,51 +835,77 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in continue; } - uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_amb: vec4;"), i); - uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4;"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_amb: vec4,"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4,"), i); - if (config.colorChannels[i].lightingEnabled) { + const auto& cc = config.colorChannels[i]; + if (cc.lightingEnabled) { if (!addedLightStruct) { uniformPre += "\n" "struct Light {\n" - " pos: vec3;\n" - " dir: vec3;\n" - " color: vec4;\n" - " lin_att: vec3;\n" - " ang_att: vec3;\n" + " pos: vec3,\n" + " dir: vec3,\n" + " color: vec4,\n" + " lin_att: vec3,\n" + " ang_att: vec3,\n" "};"; addedLightStruct = true; } - uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array;"), i, GX::MaxLights); - uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4;"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array,"), i, GX::MaxLights); + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4,"), vtxOutIdx++, i); - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), vtxOutIdx++, i); + std::string ambSrc, matSrc, lightAttnFn, lightDiffFn; + if (cc.ambSrc == GX::SRC_VTX) { + ambSrc = vtx_attr(config, static_cast(GX::VA_CLR0 + i)); + } else if (cc.ambSrc == GX::SRC_REG) { + ambSrc = fmt::format(FMT_STRING("ubuf.cc{0}_amb"), i); + } + if (cc.matSrc == GX::SRC_VTX) { + matSrc = vtx_attr(config, static_cast(GX::VA_CLR0 + i)); + } else if (cc.matSrc == GX::SRC_REG) { + matSrc = fmt::format(FMT_STRING("ubuf.cc{0}_mat"), i); + } + GX::DiffuseFn diffFn = cc.diffFn; + if (cc.attnFn == GX::AF_NONE) { + lightAttnFn = "attn = 1.0;"; + } else if (cc.attnFn == GX::AF_SPOT) { + lightAttnFn = fmt::format(FMT_STRING(R"""( + var cosine = max(0.0, dot(ldir, light.dir)); + var cos_attn = dot(light.ang_att, vec3(1.0, cosine, cosine * cosine)); + var dist_attn = dot(light.lin_att, vec3(1.0, dist, dist2)); + attn = max(0.0, cos_attn / dist_attn);)""")); + } else if (cc.attnFn == GX::AF_SPEC) { + diffFn = GX::DF_NONE; + Log.report(logvisor::Fatal, FMT_STRING("AF_SPEC unimplemented")); + } + if (diffFn == GX::DF_NONE) { + lightDiffFn = "1.0"; + } else if (diffFn == GX::DF_SIGN) { + lightDiffFn = "dot(ldir, mv_nrm)"; + } else if (diffFn == GX::DF_CLAMP) { + lightDiffFn = "max(0.0, dot(ldir, mv_nrm))"; + } vtxXfrAttrs += fmt::format(FMT_STRING(R"""( {{ - var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb; + var lighting = {5}; for (var i = 0; i < {1}; i = i + 1) {{ var light = ubuf.lights{0}[i]; - var delta = mv_pos.xyz - light.pos; - var dist = length(delta); - var delta_norm = delta / dist; - var ang_dot = max(dot(delta_norm, light.dir), 0.0); - var att = 1.0 / (light.lin_att.z * dist * dist + - light.lin_att.y * dist + - light.lin_att.x); - var ang_att = light.ang_att.z * ang_dot * ang_dot + - light.ang_att.y * ang_dot + - light.ang_att.x; - var this_color = light.color.xyz * ang_att * att * max(dot(-delta_norm, mv_nrm), 0.0); - lighting = lighting + vec4(this_color, 0.0); + var ldir = light.pos - mv_pos; + var dist2 = dot(ldir, ldir); + var dist = sqrt(dist2); + ldir = ldir / dist; + var attn: f32;{2} + var diff = {3}; + lighting = lighting + (attn * diff * light.color); }} - out.cc{0} = clamp(lighting, vec4(0.0), vec4(1.0)); + out.cc{0} = {4} * clamp(lighting, vec4(0.0), vec4(1.0)); }})"""), - i, GX::MaxLights); + i, GX::MaxLights, lightAttnFn, lightDiffFn, matSrc, ambSrc); fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); - } else if (config.colorChannels[i].matSrc == GX::SRC_VTX) { - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), vtxOutIdx++, i); + } else if (cc.matSrc == GX::SRC_VTX) { + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4,"), vtxOutIdx++, i); vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = {};"), i, vtx_attr(config, GX::Attr(GX::VA_CLR0 + i))); fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); } else { @@ -888,7 +914,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in } for (int i = 0; i < info.sampledKColors.size(); ++i) { if (info.sampledKColors.test(i)) { - uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4;"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4,"), i); } } size_t texBindIdx = 0; @@ -897,7 +923,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in continue; } const auto& tcg = config.tcgs[i]; - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2;"), vtxOutIdx++, i); + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2,"), vtxOutIdx++, i); if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) { vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4({}, 0.0, 1.0);"), i, vtx_attr(config, GX::Attr(GX::VA_TEX0 + (tcg.src - GX::TG_TEX0)))); @@ -941,10 +967,10 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in if (info.usesTexMtx.test(i)) { switch (info.texMtxTypes[i]) { case GX::TG_MTX2x4: - uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x2;"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x2,"), i); break; case GX::TG_MTX3x4: - uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x3;"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x3,"), i); break; default: Log.report(logvisor::Fatal, FMT_STRING("unhandled tex mtx type {}"), info.texMtxTypes[i]); @@ -954,20 +980,20 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in } for (int i = 0; i < info.usesPTTexMtx.size(); ++i) { if (info.usesPTTexMtx.test(i)) { - uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mat4x3;"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mat4x3,"), i); } } if (info.usesFog) { uniformPre += "\n" "struct Fog {\n" - " color: vec4;\n" - " a: f32;\n" - " b: f32;\n" - " c: f32;\n" - " pad: f32;\n" + " color: vec4,\n" + " a: f32,\n" + " b: f32,\n" + " c: f32,\n" + " pad: f32,\n" "}"; - uniBufAttrs += "\n fog: Fog;"; + uniBufAttrs += "\n fog: Fog,"; fragmentFn += "\n var fogF = clamp((ubuf.fog.a / (ubuf.fog.b - in.pos.z)) - ubuf.fog.c, 0.0, 1.0);"; switch (config.fogType) { @@ -1003,7 +1029,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in if (!info.sampledTextures.test(i)) { continue; } - uniBufAttrs += fmt::format(FMT_STRING("\n tex{}_lod: f32;"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n tex{}_lod: f32,"), i); sampBindings += fmt::format(FMT_STRING("\n@group(1) @binding({})\n" "var tex{}_samp: sampler;"), @@ -1046,15 +1072,15 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in const auto shaderSource = fmt::format(FMT_STRING(R"""({uniformPre} struct Uniform {{ - pos_mtx: mat4x3; - nrm_mtx: mat4x3; - proj: mat4x4;{uniBufAttrs} + pos_mtx: mat4x3, + nrm_mtx: mat4x3, + proj: mat4x4,{uniBufAttrs} }}; @group(0) @binding(0) var ubuf: Uniform;{uniformBindings}{sampBindings}{texBindings} struct VertexOutput {{ - @builtin(position) pos: vec4;{vtxOutAttrs} + @builtin(position) pos: vec4,{vtxOutAttrs} }}; @stage(vertex)