diff --git a/game/graphics/opengl_renderer/BucketRenderer.h b/game/graphics/opengl_renderer/BucketRenderer.h index e34605377f..f3d800b95e 100644 --- a/game/graphics/opengl_renderer/BucketRenderer.h +++ b/game/graphics/opengl_renderer/BucketRenderer.h @@ -92,6 +92,8 @@ struct SharedRenderState { bool render_debug = false; bool enable_merc_xgkick = true; bool enable_generic_xgkick = true; + math::Vector fog_color; + float fog_intensity = 1.f; void reset(); bool has_camera_planes = false; diff --git a/game/graphics/opengl_renderer/DirectRenderer.cpp b/game/graphics/opengl_renderer/DirectRenderer.cpp index f6bfa127c3..09e87dc62f 100644 --- a/game/graphics/opengl_renderer/DirectRenderer.cpp +++ b/game/graphics/opengl_renderer/DirectRenderer.cpp @@ -6,8 +6,8 @@ #include "third-party/imgui/imgui.h" #include "common/util/Assert.h" -DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batch_size, Mode mode) - : BucketRenderer(name, my_id), m_prim_buffer(batch_size), m_mode(mode) { +DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batch_size) + : BucketRenderer(name, my_id), m_prim_buffer(batch_size) { glGenBuffers(1, &m_ogl.vertex_buffer); glGenVertexArrays(1, &m_ogl.vao); glBindVertexArray(m_ogl.vao); @@ -17,12 +17,12 @@ DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batc glBufferData(GL_ARRAY_BUFFER, m_ogl.vertex_buffer_bytes, nullptr, GL_STREAM_DRAW); // todo stream? glEnableVertexAttribArray(0); - glVertexAttribPointer(0, // location 0 in the shader - 4, // 4 floats per vert (w unused) - GL_FLOAT, // floats - GL_TRUE, // normalized, ignored, - sizeof(Vertex), // - (void*)offsetof(Vertex, xyz) // offset in array (why is this a pointer...) + glVertexAttribPointer(0, // location 0 in the shader + 4, // 4 floats per vert (w unused) + GL_FLOAT, // floats + GL_TRUE, // normalized, ignored, + sizeof(Vertex), // + (void*)offsetof(Vertex, xyzf) // offset in array (why is this a pointer...) ); glEnableVertexAttribArray(1); @@ -123,10 +123,6 @@ void DirectRenderer::draw_debug_window() { ImGui::SameLine(); ImGui::Checkbox("no mip", &m_debug_state.disable_mipmap); - if (m_mode == Mode::SPRITE_CPU) { - ImGui::Checkbox("draw1", &m_sprite_mode.do_first_draw); - } - ImGui::Text("Triangles: %d", m_stats.triangles); ImGui::SameLine(); ImGui::Text("Draws: %d", m_stats.draw_calls); @@ -193,6 +189,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfil if (m_debug_state.disable_texture) { // a bit of a hack, this forces the non-textured shader always. render_state->shaders[ShaderId::DIRECT_BASIC].activate(); + m_blend_state_needs_gl_update = true; + m_prim_gl_state_needs_gl_update = true; } if (m_debug_state.red) { @@ -216,23 +214,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfil m_prim_buffer.vertices.data(), GL_STREAM_DRAW); int draw_count = 0; - if (m_mode == Mode::SPRITE_CPU) { - if (!m_prim_gl_state.texture_enable) { - render_state->shaders[ShaderId::DIRECT_BASIC].activate(); - } else { - // ASSERT(m_global_texture_state.tcc); - ASSERT(m_prim_gl_state.texture_enable); - render_state->shaders[ShaderId::SPRITE_CPU].activate(); - } - - if (m_sprite_mode.do_first_draw) { - glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count); - draw_count++; - } - } else { - glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count); - draw_count++; - } + glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count); + draw_count++; if (m_debug_state.wireframe) { render_state->shaders[ShaderId::DEBUG_RED].activate(); @@ -240,6 +223,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfil glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + m_blend_state_needs_gl_update = true; + m_prim_gl_state_needs_gl_update = true; draw_count++; } @@ -272,25 +257,21 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) { ASSERT(false); } } - if (m_mode == Mode::SPRITE_CPU) { - render_state->shaders[ShaderId::SPRITE_CPU].activate(); - } else if (m_mode == Mode::SKY) { - ASSERT(false); - } else { - render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].activate(); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].id(), - "alpha_reject"), - alpha_reject); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].id(), - "color_mult"), - m_ogl.color_mult); - } + + render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].activate(); + glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].id(), + "alpha_reject"), + alpha_reject); + glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].id(), + "color_mult"), + m_ogl.color_mult); + glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].id(), + "fog_color"), + render_state->fog_color[0], render_state->fog_color[1], render_state->fog_color[2], + render_state->fog_intensity); + } else { - if (m_mode == Mode::SKY) { - render_state->shaders[ShaderId::SKY].activate(); - } else { - render_state->shaders[ShaderId::DIRECT_BASIC].activate(); - } + render_state->shaders[ShaderId::DIRECT_BASIC].activate(); } if (state.fogging_enable) { // ASSERT(false); @@ -932,7 +913,8 @@ void DirectRenderer::handle_xyzf2_common(u32 x, bool advance) { ASSERT(z < (1 << 24)); (void)f; // TODO: do something with this. - if (m_my_id == BucketId::GENERIC_PRIS) { + + if (m_my_id == BucketId::MERC_TFRAG_TEX_LEVEL0) { // fmt::print("0x{:x}, 0x{:x}, 0x{:x}\n", x, y, z); } if (m_prim_buffer.is_full()) { @@ -945,13 +927,14 @@ void DirectRenderer::handle_xyzf2_common(u32 x, m_prim_building.st_reg.x(), m_prim_building.st_reg.y(), m_prim_building.Q); m_prim_building.building_rgba.at(m_prim_building.building_idx) = m_prim_building.rgba_reg; m_prim_building.building_vert.at(m_prim_building.building_idx) = - math::Vector{x << 16, y << 16, z << 8}; + math::Vector{x << 16, y << 16, z << 8, f}; m_prim_building.building_idx++; int tex_unit = get_texture_unit_for_current_reg(render_state, prof); bool tcc = m_buffered_tex_state[tex_unit].tcc; bool decal = m_buffered_tex_state[tex_unit].decal; + bool fge = m_prim_gl_state.fogging_enable; switch (m_prim_building.kind) { case GsPrim::Kind::SPRITE: { @@ -962,8 +945,8 @@ void DirectRenderer::handle_xyzf2_common(u32 x, auto& corner2_vert = m_prim_building.building_vert[1]; auto& corner2_rgba = m_prim_building.building_rgba[1]; // should use most recent vertex z. - math::Vector corner3_vert{corner1_vert[0], corner2_vert[1], corner2_vert[2]}; - math::Vector corner4_vert{corner2_vert[0], corner1_vert[1], corner2_vert[2]}; + math::Vector corner3_vert{corner1_vert[0], corner2_vert[1], corner2_vert[2]}; + math::Vector corner4_vert{corner2_vert[0], corner1_vert[1], corner2_vert[2]}; if (m_prim_gl_state.gouraud_enable) { // I'm not really sure what the GS does here. @@ -972,12 +955,12 @@ void DirectRenderer::handle_xyzf2_common(u32 x, auto& corner3_rgba = corner2_rgba; auto& corner4_rgba = corner2_rgba; - m_prim_buffer.push(corner1_rgba, corner1_vert, {}, 0, tcc, decal); - m_prim_buffer.push(corner3_rgba, corner3_vert, {}, 0, tcc, decal); - m_prim_buffer.push(corner2_rgba, corner2_vert, {}, 0, tcc, decal); - m_prim_buffer.push(corner2_rgba, corner2_vert, {}, 0, tcc, decal); - m_prim_buffer.push(corner4_rgba, corner4_vert, {}, 0, tcc, decal); - m_prim_buffer.push(corner1_rgba, corner1_vert, {}, 0, tcc, decal); + m_prim_buffer.push(corner1_rgba, corner1_vert, {}, 0, tcc, decal, fge); + m_prim_buffer.push(corner3_rgba, corner3_vert, {}, 0, tcc, decal, fge); + m_prim_buffer.push(corner2_rgba, corner2_vert, {}, 0, tcc, decal, fge); + m_prim_buffer.push(corner2_rgba, corner2_vert, {}, 0, tcc, decal, fge); + m_prim_buffer.push(corner4_rgba, corner4_vert, {}, 0, tcc, decal, fge); + m_prim_buffer.push(corner1_rgba, corner1_vert, {}, 0, tcc, decal, fge); m_prim_building.building_idx = 0; } } break; @@ -993,7 +976,7 @@ void DirectRenderer::handle_xyzf2_common(u32 x, if (advance) { for (int i = 0; i < 3; i++) { m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i], - m_prim_building.building_stq[i], tex_unit, tcc, decal); + m_prim_building.building_stq[i], tex_unit, tcc, decal, fge); } } } @@ -1005,7 +988,7 @@ void DirectRenderer::handle_xyzf2_common(u32 x, m_prim_building.building_idx = 0; for (int i = 0; i < 3; i++) { m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i], - m_prim_building.building_stq[i], tex_unit, tcc, decal); + m_prim_building.building_stq[i], tex_unit, tcc, decal, fge); } } break; @@ -1021,15 +1004,15 @@ void DirectRenderer::handle_xyzf2_common(u32 x, } for (int i = 0; i < 3; i++) { m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i], - m_prim_building.building_stq[i], tex_unit, tcc, decal); + m_prim_building.building_stq[i], tex_unit, tcc, decal, fge); } } } break; case GsPrim::Kind::LINE: { if (m_prim_building.building_idx == 2) { - math::Vector pt0 = m_prim_building.building_vert[0].cast(); - math::Vector pt1 = m_prim_building.building_vert[1].cast(); + math::Vector pt0 = m_prim_building.building_vert[0].xyz().cast(); + math::Vector pt1 = m_prim_building.building_vert[1].xyz().cast(); auto normal = (pt1 - pt0).normalized().cross(math::Vector{0, 0, 1}); double line_width = (1 << 19); @@ -1040,15 +1023,19 @@ void DirectRenderer::handle_xyzf2_common(u32 x, math::Vector b = pt1 + normal * line_width; math::Vector c = pt0 - normal * line_width; math::Vector d = pt1 - normal * line_width; + math::Vector ai{a.x(), a.y(), a.z(), 0}; + math::Vector bi{b.x(), b.y(), b.z(), 0}; + math::Vector ci{c.x(), c.y(), c.z(), 0}; + math::Vector di{d.x(), d.y(), d.z(), 0}; // ACB: - m_prim_buffer.push(m_prim_building.building_rgba[0], a.cast(), {}, 0, false, false); - m_prim_buffer.push(m_prim_building.building_rgba[0], c.cast(), {}, 0, false, false); - m_prim_buffer.push(m_prim_building.building_rgba[1], b.cast(), {}, 0, false, false); + m_prim_buffer.push(m_prim_building.building_rgba[0], ai, {}, 0, false, false, false); + m_prim_buffer.push(m_prim_building.building_rgba[0], ci, {}, 0, false, false, false); + m_prim_buffer.push(m_prim_building.building_rgba[1], bi, {}, 0, false, false, false); // b c d - m_prim_buffer.push(m_prim_building.building_rgba[1], b.cast(), {}, 0, false, false); - m_prim_buffer.push(m_prim_building.building_rgba[0], c.cast(), {}, 0, false, false); - m_prim_buffer.push(m_prim_building.building_rgba[1], d.cast(), {}, 0, false, false); + m_prim_buffer.push(m_prim_building.building_rgba[1], bi, {}, 0, false, false, false); + m_prim_buffer.push(m_prim_building.building_rgba[0], ci, {}, 0, false, false, false); + m_prim_buffer.push(m_prim_building.building_rgba[1], di, {}, 0, false, false, false); // m_prim_building.building_idx = 0; @@ -1115,19 +1102,22 @@ DirectRenderer::PrimitiveBuffer::PrimitiveBuffer(int max_triangles) { } void DirectRenderer::PrimitiveBuffer::push(const math::Vector& rgba, - const math::Vector& vert, + const math::Vector& vert, const math::Vector& st, int unit, bool tcc, - bool decal) { + bool decal, + bool fog_enable) { auto& v = vertices[vert_count]; v.rgba = rgba; - v.xyz[0] = (float)vert[0] / (float)UINT32_MAX; - v.xyz[1] = (float)vert[1] / (float)UINT32_MAX; - v.xyz[2] = (float)vert[2] / (float)UINT32_MAX; + v.xyzf[0] = (float)vert[0] / (float)UINT32_MAX; + v.xyzf[1] = (float)vert[1] / (float)UINT32_MAX; + v.xyzf[2] = (float)vert[2] / (float)UINT32_MAX; + v.xyzf[3] = (float)vert[3]; v.stq = st; v.tex_unit = unit; v.tcc = tcc; v.decal = decal; + v.fog_enable = fog_enable; vert_count++; } diff --git a/game/graphics/opengl_renderer/DirectRenderer.h b/game/graphics/opengl_renderer/DirectRenderer.h index a51e4a9edd..7c617e2bb9 100644 --- a/game/graphics/opengl_renderer/DirectRenderer.h +++ b/game/graphics/opengl_renderer/DirectRenderer.h @@ -19,13 +19,7 @@ */ class DirectRenderer : public BucketRenderer { public: - // specializations of direct renderer to handle certain outputs. - enum class Mode { - NORMAL, // use for general debug drawing, font. - SPRITE_CPU, // use for sprites (does the appropriate alpha test tricks) - SKY // disables texture perspective correction - }; - DirectRenderer(const std::string& name, BucketId my_id, int batch_size, Mode mode); + DirectRenderer(const std::string& name, BucketId my_id, int batch_size); ~DirectRenderer(); void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; @@ -199,7 +193,7 @@ class DirectRenderer : public BucketRenderer { math::Vector st_reg; std::array, 3> building_rgba; - std::array, 3> building_vert; + std::array, 3> building_vert; std::array, 3> building_stq; int building_idx = 0; int tri_strip_startup = 0; @@ -209,13 +203,14 @@ class DirectRenderer : public BucketRenderer { } m_prim_building; struct Vertex { - math::Vector xyz; + math::Vector xyzf; math::Vector stq; math::Vector rgba; u8 tex_unit; u8 tcc; u8 decal; - math::Vector pad; + u8 fog_enable; + math::Vector pad; }; static_assert(sizeof(Vertex) == 64); static_assert(offsetof(Vertex, tex_unit) == 32); @@ -229,11 +224,12 @@ class DirectRenderer : public BucketRenderer { // leave 6 free on the end so we always have room to flush one last primitive. bool is_full() { return max_verts < (vert_count + 18); } void push(const math::Vector& rgba, - const math::Vector& vert, + const math::Vector& vert, const math::Vector& stq, int unit, bool tcc, - bool decal); + bool decal, + bool fog_enable); } m_prim_buffer; struct { @@ -273,6 +269,4 @@ class DirectRenderer : public BucketRenderer { struct SpriteMode { bool do_first_draw = true; } m_sprite_mode; - - Mode m_mode; }; diff --git a/game/graphics/opengl_renderer/GenericRenderer.cpp b/game/graphics/opengl_renderer/GenericRenderer.cpp index 8a6a6972bf..795ac4a06a 100644 --- a/game/graphics/opengl_renderer/GenericRenderer.cpp +++ b/game/graphics/opengl_renderer/GenericRenderer.cpp @@ -2,7 +2,7 @@ #include "third-party/imgui/imgui.h" GenericRenderer::GenericRenderer(const std::string& name, BucketId my_id) - : BucketRenderer(name, my_id), m_direct(name, my_id, 0x4000, DirectRenderer::Mode::NORMAL) {} + : BucketRenderer(name, my_id), m_direct(name, my_id, 0x4000) {} void GenericRenderer::render(DmaFollower& dma, SharedRenderState* render_state, diff --git a/game/graphics/opengl_renderer/MercRenderer.cpp b/game/graphics/opengl_renderer/MercRenderer.cpp index 093c385e21..87f9419221 100644 --- a/game/graphics/opengl_renderer/MercRenderer.cpp +++ b/game/graphics/opengl_renderer/MercRenderer.cpp @@ -3,8 +3,7 @@ #include "third-party/imgui/imgui.h" MercRenderer::MercRenderer(const std::string& name, BucketId my_id) - : BucketRenderer(name, my_id), - m_direct(fmt::format("{}-dir", name), my_id, 0x30000, DirectRenderer::Mode::NORMAL) { + : BucketRenderer(name, my_id), m_direct(fmt::format("{}-dir", name), my_id, 0x30000) { memset(m_buffer.data, 0, sizeof(m_buffer.data)); } diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 3e023feb67..6abd8918e8 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -211,10 +211,8 @@ void OpenGLRenderer::init_bucket_renderers() { sprite_renderers.push_back(std::make_unique("sprite-renderer", BucketId::SPRITE)); init_bucket_renderer("sprite", BucketId::SPRITE, std::move(sprite_renderers)); // 66 - init_bucket_renderer("debug-draw-0", BucketId::DEBUG_DRAW_0, 0x20000, - DirectRenderer::Mode::NORMAL); - init_bucket_renderer("debug-draw-1", BucketId::DEBUG_DRAW_1, 0x8000, - DirectRenderer::Mode::NORMAL); + init_bucket_renderer("debug-draw-0", BucketId::DEBUG_DRAW_0, 0x20000); + init_bucket_renderer("debug-draw-1", BucketId::DEBUG_DRAW_1, 0x8000); // for now, for any unset renderers, just set them to an EmptyBucketRenderer. for (size_t i = 0; i < m_bucket_renderers.size(); i++) { @@ -266,6 +264,10 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) { m_profiler.draw(); } + if (settings.draw_small_profiler_window) { + m_profiler.draw_small_window(); + } + if (settings.save_screenshot) { finish_screenshot(settings.screenshot_path, settings.window_width_px, settings.window_height_px, settings.lbox_width_px, settings.lbox_height_px); @@ -287,6 +289,7 @@ void OpenGLRenderer::serialize(Serializer& ser) { void OpenGLRenderer::draw_renderer_selection_window() { ImGui::Begin("Renderer Debug"); + ImGui::SliderFloat("Fog Adjust", &m_render_state.fog_intensity, 0, 10); ImGui::Checkbox("Sky CPU", &m_render_state.use_sky_cpu); ImGui::Checkbox("Occlusion Cull", &m_render_state.use_occlusion_culling); ImGui::Checkbox("Render Debug (slower)", &m_render_state.render_debug); @@ -348,7 +351,9 @@ void OpenGLRenderer::dispatch_buckets(DmaFollower dma, ScopedProfilerNode& prof) ASSERT(default_regs_tag.kind == DmaTag::Kind::CNT); ASSERT(default_regs_tag.qwc == 10); // TODO verify data in here. - dma.read_and_advance(); + auto default_data = dma.read_and_advance(); + ASSERT(default_data.size_bytes > 148); + memcpy(m_render_state.fog_color.data(), default_data.data + 144, 4); auto default_ret_tag = dma.current_tag(); ASSERT(default_ret_tag.qwc == 0); ASSERT(default_ret_tag.kind == DmaTag::Kind::RET); diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.h b/game/graphics/opengl_renderer/OpenGLRenderer.h index 111ef0397f..c8e03ab57d 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.h +++ b/game/graphics/opengl_renderer/OpenGLRenderer.h @@ -15,6 +15,7 @@ struct RenderOptions { int lbox_width_px = 0; bool draw_render_debug_window = false; bool draw_profiler_window = false; + bool draw_small_profiler_window = false; bool playing_from_dump = false; bool save_screenshot = false; diff --git a/game/graphics/opengl_renderer/Profiler.cpp b/game/graphics/opengl_renderer/Profiler.cpp index 85655f471c..7222bbe26c 100644 --- a/game/graphics/opengl_renderer/Profiler.cpp +++ b/game/graphics/opengl_renderer/Profiler.cpp @@ -88,6 +88,31 @@ void Profiler::draw() { ImGui::End(); } +void Profiler::draw_small_window() { + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; + auto* p_open = &m_small_window_open; + const float PAD = 10.0f; + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any! + ImVec2 work_size = viewport->WorkSize; + ImVec2 window_pos, window_pos_pivot; + window_pos.x = (work_pos.x + PAD); + window_pos.y = (work_pos.y + work_size.y - PAD); + window_pos_pivot.x = 0.0f; + window_pos_pivot.y = 1.0f; + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); + + ImGui::SetNextWindowBgAlpha(0.85f); // Transparent background + if (ImGui::Begin("Profiler (short)", p_open, window_flags)) { + ImGui::Text(" tri: %7d\n", m_root.m_stats.triangles); + ImGui::Text(" DC: %4d\n", m_root.m_stats.draw_calls); + } + ImGui::End(); +} + u32 name_to_color(const std::string& name) { u64 val = std::hash{}(name); return colors::common_colors[val % colors::COLOR_COUNT] | 0xff000000; diff --git a/game/graphics/opengl_renderer/Profiler.h b/game/graphics/opengl_renderer/Profiler.h index 98c1b9d6e2..69e751d15e 100644 --- a/game/graphics/opengl_renderer/Profiler.h +++ b/game/graphics/opengl_renderer/Profiler.h @@ -67,6 +67,7 @@ class Profiler { Profiler(); void clear(); void draw(); + void draw_small_window(); void finish(); ProfilerNode* root() { return &m_root; } @@ -79,5 +80,6 @@ class Profiler { }; int m_mode_selector = 0; + bool m_small_window_open = true; ProfilerNode m_root; }; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/Shader.h b/game/graphics/opengl_renderer/Shader.h index d1ba4f2243..edca2d7c98 100644 --- a/game/graphics/opengl_renderer/Shader.h +++ b/game/graphics/opengl_renderer/Shader.h @@ -25,19 +25,13 @@ enum class ShaderId { TEST_SHADER = 0, DIRECT_BASIC = 1, DIRECT_BASIC_TEXTURED = 2, - // DIRECT_BASIC_TEXTURED_TCC0 = 3, - DEBUG_RED = 4, - SPRITE_CPU = 5, - // SPRITE_CPU_AFAIL = 6, - SKY = 7, - SKY_BLEND = 8, - // DEBUG_BUFFERED = 9, - // BUFFERED_TCC0 = 10, - // BUFFERED_TCC1 = 11, - TFRAG3 = 12, - TFRAG3_NO_TEX = 13, - SPRITE = 14, - SPRITE3 = 15, + DEBUG_RED = 3, + SKY = 4, + SKY_BLEND = 5, + TFRAG3 = 6, + TFRAG3_NO_TEX = 7, + SPRITE = 8, + SPRITE3 = 9, MAX_SHADERS }; diff --git a/game/graphics/opengl_renderer/SkyRenderer.cpp b/game/graphics/opengl_renderer/SkyRenderer.cpp index e7ff3d4d7b..b58f2521a0 100644 --- a/game/graphics/opengl_renderer/SkyRenderer.cpp +++ b/game/graphics/opengl_renderer/SkyRenderer.cpp @@ -120,8 +120,7 @@ void SkyBlendHandler::draw_debug_window() { } SkyRenderer::SkyRenderer(const std::string& name, BucketId my_id) - : BucketRenderer(name, my_id), - m_direct_renderer("sky-direct", my_id, 100, DirectRenderer::Mode::NORMAL) {} + : BucketRenderer(name, my_id), m_direct_renderer("sky-direct", my_id, 100) {} void SkyRenderer::render(DmaFollower& dma, SharedRenderState* render_state, diff --git a/game/graphics/opengl_renderer/debug_gui.cpp b/game/graphics/opengl_renderer/debug_gui.cpp index e24341db52..25e52d648a 100644 --- a/game/graphics/opengl_renderer/debug_gui.cpp +++ b/game/graphics/opengl_renderer/debug_gui.cpp @@ -92,6 +92,7 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) { ImGui::MenuItem("Frame Time Plot", nullptr, &m_draw_frame_time); ImGui::MenuItem("Render Debug", nullptr, &m_draw_debug); ImGui::MenuItem("Profiler", nullptr, &m_draw_profiler); + ImGui::MenuItem("Small Profiler", nullptr, &small_profiler); ImGui::EndMenu(); } diff --git a/game/graphics/opengl_renderer/debug_gui.h b/game/graphics/opengl_renderer/debug_gui.h index 6bb5402e30..458eca3c42 100644 --- a/game/graphics/opengl_renderer/debug_gui.h +++ b/game/graphics/opengl_renderer/debug_gui.h @@ -67,6 +67,7 @@ class OpenGlDebugGui { float target_fps = 60.f; bool experimental_accurate_lag = false; bool sleep_in_frame_limiter = true; + bool small_profiler = true; private: FrameTimeRecorder m_frame_timer; diff --git a/game/graphics/opengl_renderer/shaders/direct_basic_textured.frag b/game/graphics/opengl_renderer/shaders/direct_basic_textured.frag index ba540316d6..a75012c3fa 100644 --- a/game/graphics/opengl_renderer/shaders/direct_basic_textured.frag +++ b/game/graphics/opengl_renderer/shaders/direct_basic_textured.frag @@ -6,8 +6,10 @@ in vec4 fragment_color; in vec3 tex_coord; uniform float alpha_reject; uniform float color_mult; +uniform vec4 fog_color; in flat uvec4 tex_info; +in float fog; layout (binding = 20) uniform sampler2D tex_T0; layout (binding = 21) uniform sampler2D tex_T1; @@ -21,49 +23,52 @@ layout (binding = 28) uniform sampler2D tex_T8; layout (binding = 29) uniform sampler2D tex_T9; vec4 sample_tex(vec2 coord, uint unit) { - switch (unit) { - case 0: return texture(tex_T0, coord); - case 1: return texture(tex_T1, coord); - case 2: return texture(tex_T2, coord); - case 3: return texture(tex_T3, coord); - case 4: return texture(tex_T4, coord); - case 5: return texture(tex_T5, coord); - case 6: return texture(tex_T6, coord); - case 7: return texture(tex_T7, coord); - case 8: return texture(tex_T8, coord); - case 9: return texture(tex_T9, coord); - default: return vec4(1.0, 0, 1.0, 1.0); - } + switch (unit) { + case 0: return texture(tex_T0, coord); + case 1: return texture(tex_T1, coord); + case 2: return texture(tex_T2, coord); + case 3: return texture(tex_T3, coord); + case 4: return texture(tex_T4, coord); + case 5: return texture(tex_T5, coord); + case 6: return texture(tex_T6, coord); + case 7: return texture(tex_T7, coord); + case 8: return texture(tex_T8, coord); + case 9: return texture(tex_T9, coord); + default : return vec4(1.0, 0, 1.0, 1.0); + } } void main() { - vec4 T0 = sample_tex(tex_coord.xy / tex_coord.z, tex_info.x); - // y is tcc - // z is decal + vec4 T0 = sample_tex(tex_coord.xy / tex_coord.z, tex_info.x); + // y is tcc + // z is decal - if (tex_info.y == 0) { - if (tex_info.z == 0) { - // modulate + no tcc - color.xyz = fragment_color.xyz * T0.xyz; - color.w = fragment_color.w; + if (tex_info.y == 0) { + if (tex_info.z == 0) { + // modulate + no tcc + color.xyz = fragment_color.xyz * T0.xyz; + color.w = fragment_color.w; + } else { + // decal + no tcc + color.xyz = T0.xyz * 0.5; + color.w = fragment_color.w; + } } else { - // decal + no tcc - color.xyz = T0.xyz * 0.5; - color.w = fragment_color.w; + if (tex_info.z == 0) { + // modulate + tcc + color = fragment_color * T0; + } else { + // decal + tcc + color.xyz = T0.xyz * 0.5; + color.w = T0.w; + } } - } else { - if (tex_info.z == 0) { - // modulate + tcc - color = fragment_color * T0; - } else { - // decal + tcc - color.xyz = T0.xyz * 0.5; - color.w = T0.w; + color *= 2; + color.xyz *= color_mult; + if (color.a < alpha_reject) { + discard; + } + if (tex_info.w == 1) { + color.xyz = mix(color.xyz, fog_color.xyz / 255., clamp(fog_color.w * (1 - fog), 0, 1)); } - } - color *= 2; - color.xyz *= color_mult; - if (color.a < alpha_reject) { - discard; - } } diff --git a/game/graphics/opengl_renderer/shaders/direct_basic_textured.vert b/game/graphics/opengl_renderer/shaders/direct_basic_textured.vert index 508cb91c20..e60ccbf733 100644 --- a/game/graphics/opengl_renderer/shaders/direct_basic_textured.vert +++ b/game/graphics/opengl_renderer/shaders/direct_basic_textured.vert @@ -1,11 +1,12 @@ #version 430 core -layout (location = 0) in vec3 position_in; +layout (location = 0) in vec4 position_in; layout (location = 1) in vec4 rgba_in; layout (location = 2) in vec3 tex_coord_in; out vec4 fragment_color; out vec3 tex_coord; +out float fog; // putting all texture info stuff here so it's easier to copy-paste layout (location = 3) in uvec4 tex_info_in; @@ -18,4 +19,5 @@ void main() { fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.); tex_coord = tex_coord_in; tex_info = tex_info_in; + fog = position_in.w / 255.; } diff --git a/game/graphics/opengl_renderer/shaders/tfrag3.frag b/game/graphics/opengl_renderer/shaders/tfrag3.frag index 96759a0f2d..bb51ed66ed 100644 --- a/game/graphics/opengl_renderer/shaders/tfrag3.frag +++ b/game/graphics/opengl_renderer/shaders/tfrag3.frag @@ -4,10 +4,12 @@ out vec4 color; in vec4 fragment_color; in vec3 tex_coord; +in float fogginess; uniform sampler2D tex_T0; uniform float alpha_min; uniform float alpha_max; +uniform vec4 fog_color; void main() { //vec4 T0 = texture(tex_T0, tex_coord); @@ -21,4 +23,6 @@ void main() { if (color.a > alpha_max) { discard; } + + color.xyz = mix(color.xyz, fog_color.xyz / 255., clamp(fogginess/255 * fog_color.w, 0., 1.)); } diff --git a/game/graphics/opengl_renderer/shaders/tfrag3.vert b/game/graphics/opengl_renderer/shaders/tfrag3.vert index 05543b5b1d..c01989c814 100644 --- a/game/graphics/opengl_renderer/shaders/tfrag3.vert +++ b/game/graphics/opengl_renderer/shaders/tfrag3.vert @@ -7,10 +7,13 @@ layout (location = 2) in int time_of_day_index; uniform vec4 hvdf_offset; uniform mat4 camera; uniform float fog_constant; +uniform float fog_min; +uniform float fog_max; layout (binding = 10) uniform sampler1D tex_T1; // note, sampled in the vertex shader on purpose. out vec4 fragment_color; out vec3 tex_coord; +out float fogginess; void main() { @@ -38,6 +41,11 @@ void main() { // compute Q float Q = fog_constant / transformed[3]; + float fog1 = -transformed.w + hvdf_offset.w; + float fog2 = min(fog1, fog_max); + float fog3 = max(fog2, fog_min); + fogginess = 255 - fog3; + // perspective divide! transformed.xyz *= Q; diff --git a/game/graphics/opengl_renderer/shaders/tfrag3_decal.frag b/game/graphics/opengl_renderer/shaders/tfrag3_decal.frag deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/game/graphics/opengl_renderer/shaders/tfrag3_decal.vert b/game/graphics/opengl_renderer/shaders/tfrag3_decal.vert deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/game/graphics/opengl_renderer/tfrag/TFragment.cpp b/game/graphics/opengl_renderer/tfrag/TFragment.cpp index e6062999dd..5b8be8f205 100644 --- a/game/graphics/opengl_renderer/tfrag/TFragment.cpp +++ b/game/graphics/opengl_renderer/tfrag/TFragment.cpp @@ -119,7 +119,7 @@ void TFragment::render(DmaFollower& dma, m_tfrag3.setup_for_level(m_tree_kinds, level_name, render_state); TfragRenderSettings settings; settings.hvdf_offset = m_tfrag_data.hvdf_offset; - settings.fog_x = m_tfrag_data.fog.x(); + settings.fog = m_tfrag_data.fog; memcpy(settings.math_camera.data(), &m_buffered_data[0].pad[TFragDataMem::TFragMatrix0 * 16], 64); settings.tree_idx = 0; @@ -175,7 +175,7 @@ void TFragment::render(DmaFollower& dma, m_many_level_render.tie_level_renderers[i]->setup_for_level(level_names[i], render_state); TfragRenderSettings settings; settings.hvdf_offset = m_tfrag_data.hvdf_offset; - settings.fog_x = m_tfrag_data.fog.x(); + settings.fog = m_tfrag_data.fog; memcpy(settings.math_camera.data(), &m_buffered_data[0].pad[TFragDataMem::TFragMatrix0 * 16], 64); settings.tree_idx = 0; diff --git a/game/graphics/opengl_renderer/tfrag/Tfrag3.cpp b/game/graphics/opengl_renderer/tfrag/Tfrag3.cpp index fb65975554..b44ee59e2e 100644 --- a/game/graphics/opengl_renderer/tfrag/Tfrag3.cpp +++ b/game/graphics/opengl_renderer/tfrag/Tfrag3.cpp @@ -499,7 +499,7 @@ void Tfrag3::render_tree_cull_debug(const TfragRenderSettings& settings, settings.hvdf_offset[3]); glUniform1f( glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3_NO_TEX].id(), "fog_constant"), - settings.fog_x); + settings.fog.x()); // glDisable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_GEQUAL); diff --git a/game/graphics/opengl_renderer/tfrag/Tie3.cpp b/game/graphics/opengl_renderer/tfrag/Tie3.cpp index 1fa64ab404..83e365a821 100644 --- a/game/graphics/opengl_renderer/tfrag/Tie3.cpp +++ b/game/graphics/opengl_renderer/tfrag/Tie3.cpp @@ -411,7 +411,7 @@ void Tie3::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfi TfragRenderSettings settings; settings.hvdf_offset = m_pc_port_data.hvdf_off; - settings.fog_x = m_pc_port_data.fogx; + settings.fog = m_pc_port_data.fog; memcpy(settings.math_camera.data(), m_pc_port_data.camera[0].data(), 64); settings.tree_idx = 0; @@ -703,7 +703,7 @@ void Tie3::render_tree(int idx, settings.hvdf_offset[3]); glUniform1f( glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3_NO_TEX].id(), "fog_constant"), - settings.fog_x); + settings.fog.x()); glDisable(GL_BLEND); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDrawElements(GL_TRIANGLE_STRIP, draw_size, GL_UNSIGNED_INT, (void*)offset); diff --git a/game/graphics/opengl_renderer/tfrag/tfrag_common.cpp b/game/graphics/opengl_renderer/tfrag/tfrag_common.cpp index 4861d7ec03..4354da4c5c 100644 --- a/game/graphics/opengl_renderer/tfrag/tfrag_common.cpp +++ b/game/graphics/opengl_renderer/tfrag/tfrag_common.cpp @@ -150,7 +150,14 @@ void first_tfrag_draw_setup(const TfragRenderSettings& settings, SharedRenderSta settings.hvdf_offset[0], settings.hvdf_offset[1], settings.hvdf_offset[2], settings.hvdf_offset[3]); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "fog_constant"), - settings.fog_x); + settings.fog.x()); + glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "fog_min"), + settings.fog.y()); + glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "fog_max"), + settings.fog.z()); + glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "fog_color"), + render_state->fog_color[0], render_state->fog_color[1], render_state->fog_color[2], + render_state->fog_intensity); } void interp_time_of_day_slow(const float weights[8], diff --git a/game/graphics/opengl_renderer/tfrag/tfrag_common.h b/game/graphics/opengl_renderer/tfrag/tfrag_common.h index ab87ec00d9..bc3d442337 100644 --- a/game/graphics/opengl_renderer/tfrag/tfrag_common.h +++ b/game/graphics/opengl_renderer/tfrag/tfrag_common.h @@ -6,7 +6,7 @@ struct TfragRenderSettings { math::Matrix4f math_camera; math::Vector4f hvdf_offset; - float fog_x; + math::Vector4f fog; int tree_idx; float time_of_day_weights[8] = {0}; math::Vector4f planes[4]; @@ -53,8 +53,7 @@ struct TfragPcPortData { math::Vector itimes[4]; math::Vector4f camera[4]; math::Vector4f hvdf_off; - float fogx; - float unused[3]; + math::Vector4f fog; char level_name[12]; u32 tree_idx; }; diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index 73c3f1cb8f..ea4c7052be 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -264,6 +264,7 @@ void render_game_frame(int width, int height, int lbox_width, int lbox_height) { options.draw_profiler_window = g_gfx_data->debug_gui.should_draw_profiler(); options.playing_from_dump = false; options.save_screenshot = g_gfx_data->debug_gui.get_screenshot_flag(); + options.draw_small_profiler_window = g_gfx_data->debug_gui.small_profiler; if (options.save_screenshot) { options.screenshot_path = make_output_file_name(g_gfx_data->debug_gui.screenshot_name()); } diff --git a/goal_src/engine/gfx/tfrag/tfrag.gc b/goal_src/engine/gfx/tfrag/tfrag.gc index 615d32689f..901602761d 100644 --- a/goal_src/engine/gfx/tfrag/tfrag.gc +++ b/goal_src/engine/gfx/tfrag/tfrag.gc @@ -345,6 +345,8 @@ (set! (-> data-ptr 12) (-> *math-camera* hvdf-off quad)) (let ((vec (-> (the (inline-array vector) data-ptr) 13))) (set! (-> vec x) (-> *math-camera* pfog0)) + (set! (-> vec y) (-> *math-camera* fog-min)) + (set! (-> vec z) (-> *math-camera* fog-max)) ) (charp<-string (the (pointer uint8) (&-> data-ptr 14)) (symbol->string (-> lev nickname))) )