diff --git a/game/graphics/opengl_renderer/Profiler.cpp b/game/graphics/opengl_renderer/Profiler.cpp index 69feba4e0e..7479495fca 100644 --- a/game/graphics/opengl_renderer/Profiler.cpp +++ b/game/graphics/opengl_renderer/Profiler.cpp @@ -108,7 +108,7 @@ void Profiler::draw_node(ProfilerNode& node, bool expand, int depth, float start bool color_orange = false; ImGui::PushStyleColor(ImGuiCol_Text, color); auto str = - fmt::format("{:20s} {:.2f}ms {:6d} tri {:4d} draw", node.m_name, node.m_stats.duration * 1000, + fmt::format("{:20s} {:.3f}ms {:6d} tri {:4d} draw", node.m_name, node.m_stats.duration * 1000, node.m_stats.triangles, node.m_stats.draw_calls); if (node.m_children.empty()) { ImGui::Text(" %s", str.c_str()); @@ -154,7 +154,7 @@ std::string Profiler::to_string() { void ProfilerNode::to_string_helper(std::string& str, int depth) const { str += - fmt::format("{}{:.2f} ms {:30s}\n", std::string(depth, ' '), m_stats.duration * 1000, m_name); + fmt::format("{}{:.3f} ms {:30s}\n", std::string(depth, ' '), m_stats.duration * 1000, m_name); for (const auto& child : m_children) { child.to_string_helper(str, depth + 1); } diff --git a/game/graphics/opengl_renderer/ShadowRenderer.cpp b/game/graphics/opengl_renderer/ShadowRenderer.cpp index ed00574ef2..00ec163ad4 100644 --- a/game/graphics/opengl_renderer/ShadowRenderer.cpp +++ b/game/graphics/opengl_renderer/ShadowRenderer.cpp @@ -326,7 +326,7 @@ void ShadowRenderer::render(DmaFollower& dma, m_color.y() = g / 255.0f; m_color.z() = b / 255.0f; m_color.w() = a / 128.0f; - // fmt::print("rgba: {} {} {} {}\n", r, g, b, a); + // fmt::print("rgba: {}\n", m_color.to_string_aligned()); } else { ASSERT_MSG(false, fmt::format("{} {}", next.vifcode0().print(), next.vifcode1().print())); } diff --git a/game/graphics/opengl_renderer/foreground/Shadow3.cpp b/game/graphics/opengl_renderer/foreground/Shadow3.cpp index eddbe01ba5..af6558f21d 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3.cpp +++ b/game/graphics/opengl_renderer/foreground/Shadow3.cpp @@ -35,6 +35,7 @@ Shadow3::Shadow3(ShaderLibrary& shaders) { m_uniforms.origin = glGetUniformLocation(id, "origin"); m_uniforms.top_plane = glGetUniformLocation(id, "top_plane"); m_uniforms.bottom_plane = glGetUniformLocation(id, "bottom_plane"); + m_uniforms.scissor_top = glGetUniformLocation(id, "scissor_top"); } std::vector temp(MAX_SHADER_BONE_VECTORS * sizeof(math::Vector4f)); @@ -52,7 +53,7 @@ Shadow3::~Shadow3() { void Shadow3::setup_for_level(SharedRenderState* render_state, const LevelData* level_data) { glBindVertexArray(m_opengl.vao); - glBindBuffer(GL_ARRAY_BUFFER, level_data->shadow_vertices); + glBindBuffer(GL_ARRAY_BUFFER, m_hacks ? m_opengl.debug_verts : level_data->shadow_vertices); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); @@ -92,10 +93,10 @@ void Shadow3::setup_for_level(SharedRenderState* render_state, const LevelData* } namespace { -void set_uniform(GLuint uniform, const math::Vector3f& val) { +void set_uniform(GLint uniform, const math::Vector3f& val) { glUniform3f(uniform, val.x(), val.y(), val.z()); } -void set_uniform(GLuint uniform, const math::Vector4f& val) { +void set_uniform(GLint uniform, const math::Vector4f& val) { glUniform4f(uniform, val.x(), val.y(), val.z(), val.w()); } @@ -112,21 +113,21 @@ void Shadow3::draw_model(SharedRenderState* render_state, .bones = request->bones, .model = request->model.model, .vertices = &request->model.level->level->shadow_data.vertices, - .flags = request->flags, + .scissor_top = request->scissor_top, .debug_highlight_tri = m_debug_tri, }; calc_shadow_indices(input, &m_cpu_workspace, &m_cpu_output); glBindBuffer(GL_UNIFORM_BUFFER, m_opengl.bones_buffer); glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_opengl.bones_buffer, sizeof(math::Vector4f) * request->bone_idx, 128 * 16 * 4); - const auto* geo = request->model.model; + // const auto* geo = request->model.model; // printf("draw %s\n", geo->name.c_str()); set_uniform(m_uniforms.origin, request->origin); set_uniform(m_uniforms.top_plane, request->top_plane); set_uniform(m_uniforms.bottom_plane, request->bottom_plane); + glUniform1i(m_uniforms.scissor_top, request->scissor_top); - // glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); if (m_hacks) { auto* model = request->model.model; int num_verts = model->num_one_bone_vertices + model->num_two_bone_vertices; @@ -230,14 +231,16 @@ void Shadow3::draw_model(SharedRenderState* render_state, void Shadow3::finish(SharedRenderState* render_state, ScopedProfilerNode& prof) { // finally, draw shadow. if (!m_hacks) { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + // glStencilFunc(GL_GREATER, 0, 0); glStencilFunc(GL_NOTEQUAL, 0, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glDepthFunc(GL_ALWAYS); + glEnable(GL_BLEND); - glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ZERO); - glColorMask(true, true, true, false); - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - m_full_screen_draw.draw(math::Vector4f(0.5, 0.4, 0.3, 0.5), render_state, prof); + glBlendEquation(GL_FUNC_ADD); + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ONE, GL_ZERO); + m_full_screen_draw.draw(m_color, render_state, prof); } // restore @@ -270,7 +273,6 @@ void Shadow3::flush_requests(SharedRenderState* render_state, ScopedProfilerNode for (auto& c : m_level_chains) { if (!c.head) continue; - // printf("in level %s\n", c.level->level->level_name.c_str()); setup_for_level(render_state, c.level); ShadowRequest* iter = c.head; while (iter) { @@ -309,9 +311,7 @@ void Shadow3::render_jak1(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) { m_did_first_time_setup = false; - while (dma.current_tag_offset() != render_state->next_bucket) { - // auto dmatag = dma.current_tag(); auto data = dma.read_and_advance(); if (data.vifcode0().kind == VifCode::Kind::PC_PORT) { u32 next = data.data_offset; @@ -330,23 +330,15 @@ void Shadow3::render_jak1(DmaFollower& dma, printf(" SKIP: no model data\n"); continue; } - /* - * (shdf00) ;; unused - (disable-fade) - (shdf02) ;; only set, never used. - (shdf03) - (shdf04) ;; unused - (disable-draw) - */ + constexpr u32 kCullWhenUnderPlane = 1; - constexpr u32 kDisableFade = 2; + // constexpr u32 kDisableFade = 2; constexpr u32 kAbsolutePlanes = 4; - constexpr u32 kFlag3 = 8; - constexpr u32 kFlag4 = 16; + constexpr u32 kUpperClip = 8; + // constexpr u32 kFlag4 = 16; constexpr u32 kDisableDraw = 32; if (game_request.settings.flags & kDisableDraw) { - printf(" SKIP: disable flag set\n"); continue; } @@ -380,7 +372,9 @@ void Shadow3::render_jak1(DmaFollower& dma, request.origin = game_request.settings.center + game_request.settings.shadow_dir * game_request.settings.dist_to_locus; request.bones = g_ee_main_mem + game_request.mtx; - request.flags = game_request.settings.flags; + request.scissor_top = game_request.settings.flags & kUpperClip; + request.color = game_request.color; + m_color = request.color; // copy bones to buffer constexpr int in_stride = 8 * 4 * sizeof(float); @@ -397,8 +391,6 @@ void Shadow3::render_jak1(DmaFollower& dma, request.top_plane = game_request.settings.top_plane; request.bottom_plane = game_request.settings.bot_plane; if (!(kAbsolutePlanes & game_request.settings.flags)) { - // printf("relative plane mode, base is %f, move by %f\n", - // -request.bottom_plane.w() / 4096.0, game_request.settings.center.y() / 4096.0); // in relative planes mode, the height of the plane is adjusted to be relative to the // height of the center, so the planes move and down with the model request.top_plane.w() -= game_request.settings.center.y(); @@ -413,7 +405,6 @@ void Shadow3::render_jak1(DmaFollower& dma, if (render_state->camera_pos.xyz().dot(request.bottom_plane.xyz()) + request.bottom_plane.w() < 0) { - // printf(" SKIP: camera below lower clipping plane.\n"); m_next_request--; continue; } @@ -425,21 +416,10 @@ void Shadow3::render_jak1(DmaFollower& dma, // detect if the origin is below the clipping plane and if so, move it up. const float dot = request.bottom_plane.xyz().dot(request.origin); if (dot + request.bottom_plane.w() > 0) { - // printf(" the origin is below the clipping plane, moving it up.\n"); - // printf(" center was %s\n", - // game_request.settings.center.to_string_aligned().c_str()); printf(" dir was %s\n", - // game_request.settings.shadow_dir.to_string_aligned().c_str()); printf(" locus %f\n", - // game_request.settings.dist_to_locus); printf(" bottom plane was %s\n", - // game_request.settings.bot_plane.to_string_aligned().c_str()); - // printf(" adjusted bottom plane was %s\n", - // request.bottom_plane.to_string_aligned().c_str()); - // printf(" abs flag %d\n", game_request.settings.flags & kAbsolutePlanes); - request.bottom_plane.w() = -dot; } const auto& cam_rot = render_state->camera_rot; - const auto& cam_pos = render_state->camera_pos; request.light_dir = game_request.settings.shadow_dir; @@ -457,26 +437,10 @@ void Shadow3::render_jak1(DmaFollower& dma, return math::Vector4f(xyz.x(), xyz.y(), xyz.z(), in.w() - xyz.dot(cam_rot[3].xyz())); }; - // printf("plane offset before: %f\n", - // game_request.settings.center.dot(request.bottom_plane.xyz()) + - // request.bottom_plane.w()); - request.light_dir = rotate(request.light_dir); request.top_plane = rotate_plane(request.top_plane); request.bottom_plane = rotate_plane(request.bottom_plane); request.origin = transform(request.origin); - - math::Vector3f up_rt_w = math::Vector3f(0, 1, 0); - math::Vector3f up_rt_cam = rotate(up_rt_w); - // printf("ups: %f\n", up_rt_cam.dot(request.bottom_plane.xyz())); - - // printf("plane offset after: %f\n", - // transform(game_request.settings.center).dot(request.bottom_plane.xyz()) + - // request.bottom_plane.w()); - // printf("rot3: %s\n", cam_rot[3].to_string_aligned().c_str()); - // printf(" 2: %s\n", cam_pos.to_string_aligned().c_str()); - - // printf(" origin: %s\n", (request.origin / 4096.f).to_string_aligned().c_str()); } } } diff --git a/game/graphics/opengl_renderer/foreground/Shadow3.h b/game/graphics/opengl_renderer/foreground/Shadow3.h index e0e5382b96..b7be9bff49 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3.h +++ b/game/graphics/opengl_renderer/foreground/Shadow3.h @@ -20,6 +20,7 @@ static_assert(sizeof(Jak1ShadowSettings) == 5 * 16); struct Jak1ShadowRequest { u8 dma[16]; Jak1ShadowSettings settings; + math::Vector4f color; u32 geo_name; u32 mtx; u32 num_joints; @@ -39,10 +40,11 @@ class Shadow3 { math::Vector origin; math::Vector4f top_plane, bottom_plane; math::Vector3f light_dir; + math::Vector4f color; ShadowRequest* next = nullptr; const u8* bones = nullptr; u32 bone_idx = 0; - u32 flags = 0; + bool scissor_top = false; }; struct LevelChain { @@ -73,14 +75,15 @@ class Shadow3 { } m_opengl; struct { - GLuint hvdf_offset = 0; - GLuint fog_constants = 0; - GLuint perspective_matrix = 0; - GLuint camera_rot = 0; - GLuint debug_color = 0; - GLuint bottom_plane = 0; - GLuint top_plane = 0; - GLuint origin = 0; + GLint hvdf_offset = 0; + GLint fog_constants = 0; + GLint perspective_matrix = 0; + GLint camera_rot = 0; + GLint debug_color = 0; + GLint bottom_plane = 0; + GLint top_plane = 0; + GLint origin = 0; + GLint scissor_top = 0; } m_uniforms; bool m_did_first_time_setup = false; @@ -92,4 +95,5 @@ class Shadow3 { ShadowCPUWorkspace m_cpu_workspace; ShadowCPUOutput m_cpu_output; FullScreenDraw m_full_screen_draw; + math::Vector4f m_color; }; \ No newline at end of file diff --git a/game/graphics/opengl_renderer/foreground/Shadow3CPU.cpp b/game/graphics/opengl_renderer/foreground/Shadow3CPU.cpp index f26638f79a..223626eb83 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3CPU.cpp +++ b/game/graphics/opengl_renderer/foreground/Shadow3CPU.cpp @@ -62,7 +62,7 @@ void transform_vertices(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { * of casting shadows on the "wrong side of the ground", and reduces fill. */ void calc_dual_verts(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { - int num_verts = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; + const int num_verts = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; for (int i = 0; i < num_verts; i++) { math::Vector4f origin(input.origin.x(), input.origin.y(), input.origin.z(), 1.f); math::Vector4f p = work->vertices[i]; @@ -77,12 +77,23 @@ void calc_dual_verts(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { * reduces fill. */ void scissor_top(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { - // TODO + const int num_verts = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; + for (int i = 0; i < num_verts; i++) { + auto& original_vertex = work->vertices[i]; + const auto& dual_vertex = work->dual_vertices[i]; + const float above = original_vertex.dot(input.top_plane); + if (above > 0) { + const math::Vector4f offset = dual_vertex - original_vertex; + float scale = above / offset.xyz().dot(input.top_plane.xyz()); + original_vertex -= offset * scale; + } + } } /** * Clip against the near plane. I'm not sure why this is needed, but it may be another fill-reducing - * trick, or maybe just allows them to avoid scissoring against the near plane in the VU program. + * trick, or maybe just allows them to avoid scissoring against the near plane in the VU program? + * Either way, it seems like this isn't really needed. */ void scissor_edges(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { // TODO @@ -265,7 +276,9 @@ void calc_shadow_indices(const ShadowCPUInput& input, transform_vertices(input, work); calc_dual_verts(input, work); - scissor_top(input, work); + if (input.scissor_top) { + scissor_top(input, work); + } scissor_edges(input, work); find_facing_single_tris(input, work, output, input.model->single_tris); find_single_edges(input, work, output); diff --git a/game/graphics/opengl_renderer/foreground/Shadow3CPU.h b/game/graphics/opengl_renderer/foreground/Shadow3CPU.h index 3861ce4046..b2dd970ca3 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3CPU.h +++ b/game/graphics/opengl_renderer/foreground/Shadow3CPU.h @@ -9,7 +9,7 @@ struct ShadowCPUInput { const u8* bones = nullptr; const tfrag3::ShadowModel* model = nullptr; std::vector* vertices = nullptr; - u32 flags = 0; + bool scissor_top = false; int debug_highlight_tri = 0; }; diff --git a/game/graphics/opengl_renderer/shaders/shadow3.vert b/game/graphics/opengl_renderer/shaders/shadow3.vert index c5396aedb9..483eb42397 100644 --- a/game/graphics/opengl_renderer/shaders/shadow3.vert +++ b/game/graphics/opengl_renderer/shaders/shadow3.vert @@ -15,6 +15,7 @@ uniform vec3 debug_color; uniform vec4 bottom_plane; uniform vec4 top_plane; uniform vec3 origin; +uniform bool scissor_top; // output out vec4 vtx_color; @@ -48,7 +49,6 @@ vec4 dual(vec4 p, vec4 plane) { } vec4 scissor(vec4 p, vec4 plane) { - return p; float plane_offset = dot(p, plane); if (plane_offset > 0) { vec4 offset = vec4(origin, 1) - p; @@ -77,7 +77,9 @@ void main() { if ((flags & uint(1)) != 0) { vtx_pos = dual(vtx_pos, bottom_plane); } else { - vtx_pos = scissor(vtx_pos, top_plane); + if (scissor_top) { + vtx_pos = scissor(vtx_pos, top_plane); + } } } diff --git a/goal_src/jak1/engine/gfx/foreground/bones.gc b/goal_src/jak1/engine/gfx/foreground/bones.gc index 0b1b3f9f04..ae92c94137 100644 --- a/goal_src/jak1/engine/gfx/foreground/bones.gc +++ b/goal_src/jak1/engine/gfx/foreground/bones.gc @@ -42,7 +42,7 @@ (define *ripple-force-generic* #f) ;; when set, use the rewritten PC shadow render (faster) -(define *use-pc-shadow* #f) +(define *use-pc-shadow* #t) ;; use rewritten bones math (GOAL asm instead of mips2c) (define *use-new-bones* #t) @@ -724,6 +724,7 @@ (set! (-> pse geo-name) (-> sgeo name)) (set! (-> pse mtx) mtx) (set! (-> pse num-joints) (-> sgeo header num-joints)) + (vector-copy! (-> pse color) (-> *time-of-day-context* current-shadow-color)) ;; set up linked list. (let* ((run (-> *pc-shadow-queue* run (-> *pc-shadow-queue* cur-run))) diff --git a/goal_src/jak1/engine/gfx/shadow/shadow-cpu-h.gc b/goal_src/jak1/engine/gfx/shadow/shadow-cpu-h.gc index fd3f6e39ec..6f0204378a 100644 --- a/goal_src/jak1/engine/gfx/shadow/shadow-cpu-h.gc +++ b/goal_src/jak1/engine/gfx/shadow/shadow-cpu-h.gc @@ -110,6 +110,7 @@ ( (dma-next dma-packet :inline) (settings shadow-settings :inline) + (color vector :inline) (geo-name string) ;; name to send to PC renderer (mtx pointer) ;; pointer to DMA memory that will contain bones (num-joints uint32) ;; number of joints needed for shadow