From 25e105aa5dfe2563661001e5a5d6a1b63154bbce Mon Sep 17 00:00:00 2001 From: Hat Kid <6624576+Hat-Kid@users.noreply.github.com> Date: Sun, 7 Jun 2026 07:27:43 +0200 Subject: [PATCH] jak2/3: implement ocean envmap (#4303) Implements the envmap for the ocean generated by `ocean-method-89`/`ocean-method-88`. While the resulting envmap looks accurate compared to PCSX2 in Renderdoc, the end result does not seem 100% identical, but it is a big improvement over the default placeholder texture. Closes #3417 --- game/CMakeLists.txt | 1 + game/graphics/opengl_renderer/Shader.cpp | 2 + game/graphics/opengl_renderer/Shader.h | 2 + .../opengl_renderer/ocean/OceanEnvmap.cpp | 307 ++++++++++++++++++ .../opengl_renderer/ocean/OceanEnvmap.h | 40 +++ .../opengl_renderer/ocean/OceanMidAndFar.cpp | 23 +- .../opengl_renderer/ocean/OceanMidAndFar.h | 8 +- .../opengl_renderer/ocean/OceanTexture_PC.cpp | 8 +- .../opengl_renderer/shaders/ocean_envmap.frag | 13 + .../opengl_renderer/shaders/ocean_envmap.vert | 7 + .../shaders/ocean_envmap_haze.frag | 8 + .../shaders/ocean_envmap_haze.vert | 11 + goal_src/jak2/engine/gfx/ocean/ocean.gc | 8 +- goal_src/jak3/engine/gfx/ocean/ocean.gc | 7 +- 14 files changed, 417 insertions(+), 28 deletions(-) create mode 100644 game/graphics/opengl_renderer/ocean/OceanEnvmap.cpp create mode 100644 game/graphics/opengl_renderer/ocean/OceanEnvmap.h create mode 100644 game/graphics/opengl_renderer/shaders/ocean_envmap.frag create mode 100644 game/graphics/opengl_renderer/shaders/ocean_envmap.vert create mode 100644 game/graphics/opengl_renderer/shaders/ocean_envmap_haze.frag create mode 100644 game/graphics/opengl_renderer/shaders/ocean_envmap_haze.vert diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 1677eca0e5..17e82017a4 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -59,6 +59,7 @@ set(RUNTIME_SOURCE graphics/opengl_renderer/loader/Loader.cpp graphics/opengl_renderer/loader/LoaderStages.cpp graphics/opengl_renderer/ocean/CommonOceanRenderer.cpp + graphics/opengl_renderer/ocean/OceanEnvmap.cpp graphics/opengl_renderer/ocean/OceanMid_PS2.cpp graphics/opengl_renderer/ocean/OceanMid.cpp graphics/opengl_renderer/ocean/OceanMidAndFar.cpp diff --git a/game/graphics/opengl_renderer/Shader.cpp b/game/graphics/opengl_renderer/Shader.cpp index c7ba095df6..bfe48e43df 100644 --- a/game/graphics/opengl_renderer/Shader.cpp +++ b/game/graphics/opengl_renderer/Shader.cpp @@ -134,6 +134,8 @@ ShaderLibrary::ShaderLibrary(GameVersion version) { at(ShaderId::TIE_WIND) = {"tie_wind", version}; at(ShaderId::SIMPLE_TEXTURE) = {"simple_texture", version}; at(ShaderId::SLOW_TIME) = {"slow_time", version}; + at(ShaderId::OCEAN_ENVMAP) = {"ocean_envmap", version}; + at(ShaderId::OCEAN_ENVMAP_HAZE) = {"ocean_envmap_haze", version}; for (auto& shader : m_shaders) { ASSERT_MSG(shader.okay(), "error compiling shader"); diff --git a/game/graphics/opengl_renderer/Shader.h b/game/graphics/opengl_renderer/Shader.h index f0bf05246e..bed259e6c5 100644 --- a/game/graphics/opengl_renderer/Shader.h +++ b/game/graphics/opengl_renderer/Shader.h @@ -67,6 +67,8 @@ enum class ShaderId { TIE_WIND = 40, SIMPLE_TEXTURE = 41, SLOW_TIME = 42, + OCEAN_ENVMAP = 43, + OCEAN_ENVMAP_HAZE = 44, MAX_SHADERS }; diff --git a/game/graphics/opengl_renderer/ocean/OceanEnvmap.cpp b/game/graphics/opengl_renderer/ocean/OceanEnvmap.cpp new file mode 100644 index 0000000000..65fd097ced --- /dev/null +++ b/game/graphics/opengl_renderer/ocean/OceanEnvmap.cpp @@ -0,0 +1,307 @@ +#include "OceanEnvmap.h" + +#include + +#include "common/dma/gs.h" + +#include "game/graphics/texture/TexturePool.h" + +#include "fmt/format.h" +#include "third-party/imgui/imgui.h" + +namespace { + +/*! + * check if a gif packet from a dma-buffer-add-gs-set contains a given register address + */ +bool scan_gs_set(const u8* data, const u32 size, GsRegisterAddress reg, u64* out) { + if (size < 16) { + return false; + } + GifTag tag(data); + if (tag.flg() != GifTag::Format::PACKED) { + return false; + } + u32 nreg = tag.nreg(); + u32 offset = 16; + for (u32 loop = 0; loop < tag.nloop(); loop++) { + for (u32 r = 0; r < nreg; r++) { + if (offset + 16 > size) { + return false; + } + if (tag.reg(r) == GifTag::RegisterDescriptor::AD) { + u64 value; + u8 addr; + memcpy(&value, data + offset, sizeof(value)); + memcpy(&addr, data + offset + 8, sizeof(addr)); + if (addr == (u8)reg) { + *out = value; + return true; + } + } + offset += 16; + } + } + return false; +} + +bool is_untextured_draw(const u8* data, u32 size) { + if (size < 16) { + return false; + } + GifTag tag(data); + if (!tag.pre()) { + return false; + } + return !GsPrim(tag.prim()).tme(); +} + +bool find_sky_color(DmaFollower dma, u32 next_bucket, u8 out[4]) { + for (int i = 0; i < 256 && dma.current_tag_offset() != next_bucket; i++) { + auto d = dma.read_and_advance(); + if (d.size_bytes >= 32 && is_untextured_draw(d.data, d.size_bytes)) { + out[0] = d.data[16 + 0]; + out[1] = d.data[16 + 4]; + out[2] = d.data[16 + 8]; + out[3] = d.data[16 + 12]; + return true; + } + } + return false; +} +} // namespace + +OceanEnvmap::OceanEnvmap(const std::string& name, int my_id, int batch_size) + : DirectRenderer(name, my_id, batch_size), + m_first_pass_fb(ENVMAP_WIDTH, ENVMAP_HEIGHT, GL_UNSIGNED_INT_8_8_8_8_REV), + m_envmap_fb(ENVMAP_WIDTH, ENVMAP_HEIGHT, GL_UNSIGNED_INT_8_8_8_8_REV) {} + +static void make_single_level_linear(const GLuint tex) { + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glBindTexture(GL_TEXTURE_2D, 0); +} + +void OceanEnvmap::init_textures(TexturePool& pool, GameVersion version) { + TextureInput in; + in.w = ENVMAP_WIDTH; + in.h = ENVMAP_HEIGHT; + in.debug_page_name = "PC-OCEAN-ENVMAP"; + + in.gpu_texture = m_envmap_fb.texture(); + in.debug_name = "ocean-envmap"; + in.id = pool.allocate_pc_port_texture(version); + m_envmap_gpu_tex = pool.give_texture_and_load_to_vram(in, ENVMAP_VRAM_ADDR); + + make_single_level_linear(m_first_pass_fb.texture()); + make_single_level_linear(m_envmap_fb.texture()); + + glGenVertexArrays(1, &m_radial_vao); + glBindVertexArray(m_radial_vao); + glGenBuffers(1, &m_radial_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_radial_vbo); + const float verts[8] = {-1.f, -1.f, -1.f, 1.f, 1.f, -1.f, 1.f, 1.f}; + glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenVertexArrays(1, &m_haze_vao); + glBindVertexArray(m_haze_vao); + glGenBuffers(1, &m_haze_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_haze_vbo); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)nullptr); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(2 * sizeof(float))); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void OceanEnvmap::render_haze(const u8* gif_data, u32 size, SharedRenderState* render_state) { + if (size < 16) { + return; + } + const float x_off = m_prim_buffer.x_off; + const float y_off = m_prim_buffer.y_off; + + GifTag tag(gif_data); + if (tag.flg() != GifTag::Format::PACKED) { + return; + } + const u32 nreg = tag.nreg(); + + std::vector verts; + verts.reserve(tag.nloop() * 2 * 6); + float cur[4] = {1.f, 1.f, 1.f, 1.f}; + u32 offset = 16; + for (u32 loop = 0; loop < tag.nloop(); loop++) { + for (u32 r = 0; r < nreg; r++) { + if (offset + 16 > size) { + break; + } + const u8* d = gif_data + offset; + switch (tag.reg(r)) { + case GifTag::RegisterDescriptor::RGBAQ: + cur[0] = d[0] / 255.f; + cur[1] = d[4] / 255.f; + cur[2] = d[8] / 255.f; + cur[3] = d[12] / 255.f; + break; + case GifTag::RegisterDescriptor::XYZF2: { + u16 rawx, rawy; + memcpy(&rawx, d + 0, 2); + memcpy(&rawy, d + 4, 2); + float px = rawx / 65536.f + x_off; + float py = rawy / 65536.f + y_off; + float ndc_x = (px - 0.453125f) * 64.f; + float ndc_y = (py - 0.5f + (2.25f / 64.f)) * 64.f; + verts.insert(verts.end(), {ndc_x, ndc_y, cur[0], cur[1], cur[2], cur[3] * 2.f}); + } break; + default: + break; + } + offset += 16; + } + } + if (verts.size() < 6 * 3) { + return; + } + + GLboolean depth = glIsEnabled(GL_DEPTH_TEST); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + render_state->shaders[ShaderId::OCEAN_ENVMAP_HAZE].activate(); + glBindVertexArray(m_haze_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_haze_vbo); + glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), verts.data(), GL_STREAM_DRAW); + glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)(verts.size() / 6)); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if (depth) { + glEnable(GL_DEPTH_TEST); + } +} + +void OceanEnvmap::render_envmap(SharedRenderState* render_state) { + GLboolean blend = glIsEnabled(GL_BLEND); + GLboolean depth_test = glIsEnabled(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + + FramebufferTexturePairContext ctxt(m_envmap_fb); + glViewport(0, 0, ENVMAP_WIDTH, ENVMAP_HEIGHT); + auto shader = &render_state->shaders[ShaderId::OCEAN_ENVMAP]; + shader->activate(); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_first_pass_fb.texture()); + glBindVertexArray(m_radial_vao); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + + if (blend) { + glEnable(GL_BLEND); + } + if (depth_test) { + glEnable(GL_DEPTH_TEST); + } +} + +void OceanEnvmap::handle_ocean_envmap_jak2(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof) { + u8 sky[4] = {0, 0, 0, 255}; + find_sky_color(dma, render_state->next_bucket, sky); + + auto scissor_backup = m_scissor; + + bool active = false; + bool registered = false; + int setup64_count = 0; + + for (int guard = 0; guard < 4096; guard++) { + DmaFollower peek = dma; + if (peek.current_tag_offset() == render_state->next_bucket) { + break; + } + auto next = peek.read_and_advance(); + u64 scissor = 0; + u64 frame = 0; + bool has_scissor = + scan_gs_set(next.data, next.size_bytes, GsRegisterAddress::SCISSOR_1, &scissor); + bool has_frame = scan_gs_set(next.data, next.size_bytes, GsRegisterAddress::FRAME_1, &frame); + if (has_scissor && GsScissor(scissor).x1() == 127) { + break; + } + bool is_reset = has_scissor && GsScissor(scissor).x1() != ENVMAP_WIDTH - 1; + + auto data = dma.read_and_advance(); + + if (has_scissor && GsScissor(scissor).x1() == ENVMAP_WIDTH - 1) { + setup64_count++; + u32 page_tbp = has_frame ? GsFrame(frame).fbp() << 5 : 0; + if (active) { + flush_pending(render_state, prof); + } + m_fb_ctxt.reset(); + reset_state(); + if (setup64_count == 1) { + m_offscreen_mode = true; + m_fb_ctxt.emplace(m_first_pass_fb); + glViewport(0, 0, ENVMAP_WIDTH * 2, ENVMAP_HEIGHT * 2); + glClearColor(sky[0] / 255.f, sky[1] / 255.f, sky[2] / 255.f, sky[3] / 255.f); + glClear(GL_COLOR_BUFFER_BIT); + active = true; + } else if (setup64_count == 2) { + m_offscreen_mode = false; + if (page_tbp) { + render_state->texture_pool->move_existing_to_vram(m_envmap_gpu_tex, page_tbp); + registered = true; + } + } + } + + if (active && setup64_count == 1 && !is_reset && data.size_bytes >= 16 && + data.vifcode1().kind == VifCode::Kind::DIRECT && + !is_untextured_draw(data.data, data.size_bytes)) { + render_gif(data.data, data.size_bytes, render_state, prof); + } + + // "haze" effect + if (active && setup64_count == 1 && !is_reset && data.size_bytes >= 16 && + is_untextured_draw(data.data, data.size_bytes) && + GsPrim(GifTag(data.data).prim()).kind() == GsPrim::Kind::TRI_STRIP) { + flush_pending(render_state, prof); + render_haze(data.data, data.size_bytes, render_state); + reinitialize_gl_state(); + } + } + + if (active) { + flush_pending(render_state, prof); + m_fb_ctxt.reset(); + m_offscreen_mode = false; + render_envmap(render_state); + m_scissor = scissor_backup; + if (!registered) { + render_state->texture_pool->move_existing_to_vram(m_envmap_gpu_tex, ENVMAP_VRAM_ADDR); + } + } +} + +void OceanEnvmap::draw_debug_window() { + ImGui::Text("first pass envmap"); + ImGui::Image((ImTextureID)(intptr_t)m_first_pass_fb.texture(), + ImVec2(ENVMAP_WIDTH * 2, ENVMAP_HEIGHT * 2)); + ImGui::SameLine(); + ImGui::Image((ImTextureID)(intptr_t)m_envmap_fb.texture(), + ImVec2(ENVMAP_WIDTH * 2, ENVMAP_HEIGHT * 2)); +} diff --git a/game/graphics/opengl_renderer/ocean/OceanEnvmap.h b/game/graphics/opengl_renderer/ocean/OceanEnvmap.h new file mode 100644 index 0000000000..d9f2541f05 --- /dev/null +++ b/game/graphics/opengl_renderer/ocean/OceanEnvmap.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "game/graphics/opengl_renderer/DirectRenderer.h" +#include "game/graphics/opengl_renderer/opengl_utils.h" + +/*! + * This class generates the ocean envmap texture using the sky + time of day (ocean-method-89). + */ +class OceanEnvmap : public DirectRenderer { + public: + // (-> *ocean-envmap-texture-base* vram-block) + static constexpr int ENVMAP_VRAM_ADDR = 0xf80; + static constexpr int ENVMAP_WIDTH = 64; + static constexpr int ENVMAP_HEIGHT = 64; + + OceanEnvmap(const std::string& name, int my_id, int batch_size); + void init_textures(TexturePool& pool, GameVersion version) override; + void handle_ocean_envmap_jak2(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& prof); + void draw_debug_window() override; + + private: + FramebufferTexturePair m_first_pass_fb; + FramebufferTexturePair m_envmap_fb; + std::optional m_fb_ctxt; + GpuTexture* m_envmap_gpu_tex = nullptr; + + // ocean-method-85 + GLuint m_haze_vao = 0; + GLuint m_haze_vbo = 0; + void render_haze(const u8* gif_data, u32 size, SharedRenderState* render_state); + + // ocean-method-83 + GLuint m_radial_vao = 0; + GLuint m_radial_vbo = 0; + void render_envmap(SharedRenderState* render_state); +}; diff --git a/game/graphics/opengl_renderer/ocean/OceanMidAndFar.cpp b/game/graphics/opengl_renderer/ocean/OceanMidAndFar.cpp index 75e68eb97e..de71b68fb6 100644 --- a/game/graphics/opengl_renderer/ocean/OceanMidAndFar.cpp +++ b/game/graphics/opengl_renderer/ocean/OceanMidAndFar.cpp @@ -3,15 +3,23 @@ #include "third-party/imgui/imgui.h" OceanMidAndFar::OceanMidAndFar(const std::string& name, int my_id) - : BucketRenderer(name, my_id), m_direct(name, my_id, 4096), m_texture_renderer(true) {} + : BucketRenderer(name, my_id), + m_direct(name, my_id, 4096), + m_envmap_renderer(name + "-envmap", my_id, 4096), + m_texture_renderer(true) {} void OceanMidAndFar::draw_debug_window() { + if (ImGui::TreeNode("envmap")) { + m_envmap_renderer.draw_debug_window(); + ImGui::TreePop(); + } m_texture_renderer.draw_debug_window(); m_direct.draw_debug_window(); } void OceanMidAndFar::init_textures(TexturePool& pool, GameVersion version) { m_texture_renderer.init_textures(pool, version); + m_envmap_renderer.init_textures(pool, version); } void OceanMidAndFar::render(DmaFollower& dma, @@ -96,15 +104,16 @@ void OceanMidAndFar::render_jak2(DmaFollower& dma, } m_direct.reset_state(); - // TODO handle ocean::89 and ocean::79 - // handle_ocean_89_jak2(dma, render_state, prof); + { + auto p = prof.make_scoped_child("envmap"); + m_envmap_renderer.handle_ocean_envmap_jak2(dma, render_state, p); + } { auto p = prof.make_scoped_child("texture"); m_texture_renderer.handle_ocean_texture_jak2(dma, render_state, p); } - // handle_ocean_79_jak2(dma, render_state, prof); handle_ocean_far(dma, render_state, prof); m_direct.flush_pending(render_state, prof); @@ -188,8 +197,4 @@ void OceanMidAndFar::handle_ocean_mid(DmaFollower& dma, while (!is_end_tag(dma.current_tag(), dma.current_tag_vifcode0(), dma.current_tag_vifcode1())) { dma.read_and_advance(); } -} - -void handle_ocean_89_jak2(DmaFollower&, SharedRenderState*, ScopedProfilerNode&) {} - -void handle_ocean_79_jak2(DmaFollower&, SharedRenderState*, ScopedProfilerNode&) {} \ No newline at end of file +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/ocean/OceanMidAndFar.h b/game/graphics/opengl_renderer/ocean/OceanMidAndFar.h index 52046e97ac..9bb21b71a6 100644 --- a/game/graphics/opengl_renderer/ocean/OceanMidAndFar.h +++ b/game/graphics/opengl_renderer/ocean/OceanMidAndFar.h @@ -2,6 +2,7 @@ #include "game/graphics/opengl_renderer/BucketRenderer.h" #include "game/graphics/opengl_renderer/DirectRenderer.h" +#include "game/graphics/opengl_renderer/ocean/OceanEnvmap.h" #include "game/graphics/opengl_renderer/ocean/OceanMid.h" #include "game/graphics/opengl_renderer/ocean/OceanTexture.h" #include "game/graphics/opengl_renderer/opengl_utils.h" @@ -29,14 +30,9 @@ class OceanMidAndFar : public BucketRenderer { void handle_ocean_mid(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof); - void handle_ocean_89_jak2(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - void handle_ocean_79_jak2(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof); DirectRenderer m_direct; + OceanEnvmap m_envmap_renderer; OceanTexture m_texture_renderer; OceanMid m_mid_renderer; }; diff --git a/game/graphics/opengl_renderer/ocean/OceanTexture_PC.cpp b/game/graphics/opengl_renderer/ocean/OceanTexture_PC.cpp index 7e00b94a3d..429845d84f 100644 --- a/game/graphics/opengl_renderer/ocean/OceanTexture_PC.cpp +++ b/game/graphics/opengl_renderer/ocean/OceanTexture_PC.cpp @@ -584,13 +584,13 @@ void OceanTexture::run_L3_PC_jak2() { // iaddi vi01, vi01, -0x1 | ftoi0.xyzw vf19, vf19 78 vtx3.ftoi0(Mask::xyzw, vtx3); loop_idx = loop_idx + -1; // sq.xyzw vf16, 1(vi06) | add.xyzw vf28, vf28, vf07 79 - cout0.add(Mask::xyzw, cout0, m_texture_constants.cam_nrm); sq_buffer(Mask::xyzw, vtx0, vu.dbuf_write + 1); + cout0.add(Mask::xyzw, cout0, m_texture_constants.constants); sq_buffer(Mask::xyzw, vtx0, vu.dbuf_write + 1); // sq.xyzw vf17, 4(vi06) | add.xyzw vf29, vf29, vf07 80 - cout1.add(Mask::xyzw, cout1, m_texture_constants.cam_nrm); sq_buffer(Mask::xyzw, vtx1, vu.dbuf_write + 4); + cout1.add(Mask::xyzw, cout1, m_texture_constants.constants); sq_buffer(Mask::xyzw, vtx1, vu.dbuf_write + 4); // sq.xyzw vf18, 7(vi06) | add.xyzw vf30, vf30, vf07 81 - cout2.add(Mask::xyzw, cout2, m_texture_constants.cam_nrm); sq_buffer(Mask::xyzw, vtx2, vu.dbuf_write + 7); + cout2.add(Mask::xyzw, cout2, m_texture_constants.constants); sq_buffer(Mask::xyzw, vtx2, vu.dbuf_write + 7); // sq.xyzw vf19, 10(vi06) | add.xyzw vf31, vf31, vf07 82 - cout3.add(Mask::xyzw, cout3, m_texture_constants.cam_nrm); sq_buffer(Mask::xyzw, vtx3, vu.dbuf_write + 10); + cout3.add(Mask::xyzw, cout3, m_texture_constants.constants); sq_buffer(Mask::xyzw, vtx3, vu.dbuf_write + 10); // lq.xyzw vf24, 1(vi05) | sub.zw vf28, vf01, vf00 83 cout0.sub(Mask::zw, ones, vf00); lq_buffer(Mask::xyzw, nrm0, vu.in_ptr + 1); // lq.xyzw vf26, 5(vi05) | sub.zw vf29, vf01, vf00 84 diff --git a/game/graphics/opengl_renderer/shaders/ocean_envmap.frag b/game/graphics/opengl_renderer/shaders/ocean_envmap.frag new file mode 100644 index 0000000000..eb2320ff0c --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/ocean_envmap.frag @@ -0,0 +1,13 @@ +#version 410 core +uniform sampler2D tex_T1; +in vec2 tex_coord; +out vec4 color; +void main() { + const float PI = 3.14159265358979; + float u = tex_coord.x; + float v = tex_coord.y; + float theta = (0.5 - u) * 2.0 * PI; + float t = 1.0 - abs(2.0 * v - 1.0); + vec2 st = vec2(0.5) + t * 0.5 * vec2(sin(theta), cos(theta)); + color = texture(tex_T1, st); +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/shaders/ocean_envmap.vert b/game/graphics/opengl_renderer/shaders/ocean_envmap.vert new file mode 100644 index 0000000000..fb289e2747 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/ocean_envmap.vert @@ -0,0 +1,7 @@ +#version 410 core +layout (location = 0) in vec2 position_in; +out vec2 tex_coord; +void main() { + gl_Position = vec4(position_in, 0.0, 1.0); + tex_coord = (position_in + 1.0) * 0.5; +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/shaders/ocean_envmap_haze.frag b/game/graphics/opengl_renderer/shaders/ocean_envmap_haze.frag new file mode 100644 index 0000000000..4ec2c6bb41 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/ocean_envmap_haze.frag @@ -0,0 +1,8 @@ +#version 410 core + +in vec4 color; +out vec4 out_color; + +void main() { + out_color = color; +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/shaders/ocean_envmap_haze.vert b/game/graphics/opengl_renderer/shaders/ocean_envmap_haze.vert new file mode 100644 index 0000000000..89736bb907 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/ocean_envmap_haze.vert @@ -0,0 +1,11 @@ +#version 410 core + +layout (location = 0) in vec2 ndc_in; +layout (location = 1) in vec4 color_in; + +out vec4 color; + +void main() { + gl_Position = vec4(ndc_in, 0.0, 1.0); + color = color_in; +} \ No newline at end of file diff --git a/goal_src/jak2/engine/gfx/ocean/ocean.gc b/goal_src/jak2/engine/gfx/ocean/ocean.gc index dcdbfcf4a0..fe4b7c72d2 100644 --- a/goal_src/jak2/engine/gfx/ocean/ocean.gc +++ b/goal_src/jak2/engine/gfx/ocean/ocean.gc @@ -1167,11 +1167,9 @@ (let* ((s4-0 (-> *display* frames (-> *display* on-screen) global-buf)) (s5-2 (-> s4-0 base)) ) - ;; TODO handle ocean::79 and ocean::89 - ;; diasble tod ocean stuff - ;; (if (-> *time-of-day-context* sky) - ;; (ocean-method-89 this s4-0) - ;; ) + (if (-> *time-of-day-context* sky) + (ocean-method-89 this s4-0) + ) (draw-ocean-texture this s4-0 (the-as int (-> this verts))) ;; disable whatever this is ;; (ocean-method-79 this s4-0) diff --git a/goal_src/jak3/engine/gfx/ocean/ocean.gc b/goal_src/jak3/engine/gfx/ocean/ocean.gc index 1606d764e9..b9eac10649 100644 --- a/goal_src/jak3/engine/gfx/ocean/ocean.gc +++ b/goal_src/jak3/engine/gfx/ocean/ocean.gc @@ -1191,10 +1191,9 @@ (let* ((s4-1 (-> *display* frames (-> *display* on-screen) global-buf)) (s5-2 (-> s4-1 base)) ) - ;; og:preserve-this not-yet-implemented - ; (if (-> *time-of-day-context* sky) - ; (ocean-method-88 this s4-1) - ; ) + (if (-> *time-of-day-context* sky) + (ocean-method-88 this s4-1) + ) (draw-ocean-texture this s4-1 (the-as int (-> this verts))) ; (ocean-method-89 this s4-1) (init-buffer! this s4-1)