From 8ba010ca97b04f7c84e2dc1c4d137ea5d8a87079 Mon Sep 17 00:00:00 2001 From: Ethan Lafrenais <6609531+Francessco121@users.noreply.github.com> Date: Fri, 8 Jul 2022 21:56:38 -0400 Subject: [PATCH] Sprite Distort (#1626) * [WIP] initial sprite distort implementation * Clean up * More clean up + document sprite distort VU program * Format code * Address CI issues * Adjust hacks in distort fragment shader * oops * Optimize sprite distort rendering down to one draw call ~2x speed up * Format file * Clean up distort rendering and add separate profile scopes * Fix glVertexAttribPointer * Fix sprite distort getting messed up when the viewable area doesn't fit the window perfectly * Add debug option to disable sprite distort * One evil space to fail CI... * oops * Increase sprite-aux-list size when PC_BIG_MEMORY is true * Address lints --- common/dma/gs.h | 1 + common/math/Vector.h | 2 +- docs/scratch/sprite_distort_vu1.txt | 94 +++++ .../graphics/opengl_renderer/BucketRenderer.h | 5 + .../opengl_renderer/OpenGLRenderer.cpp | 5 + game/graphics/opengl_renderer/Shader.cpp | 1 + game/graphics/opengl_renderer/Shader.h | 1 + game/graphics/opengl_renderer/Sprite3.cpp | 383 +++++++++++++++++- game/graphics/opengl_renderer/Sprite3.h | 69 +++- .../shaders/sprite_distort.frag | 21 + .../shaders/sprite_distort.vert | 26 ++ .../jak1/engine/gfx/sprite/sprite-distort.gc | 202 ++++----- goal_src/jak1/engine/gfx/sprite/sprite.gc | 4 +- 13 files changed, 667 insertions(+), 147 deletions(-) create mode 100644 docs/scratch/sprite_distort_vu1.txt create mode 100644 game/graphics/opengl_renderer/shaders/sprite_distort.frag create mode 100644 game/graphics/opengl_renderer/shaders/sprite_distort.vert diff --git a/common/dma/gs.h b/common/dma/gs.h index cd7fb0ebd..4ecfb3d92 100644 --- a/common/dma/gs.h +++ b/common/dma/gs.h @@ -125,6 +125,7 @@ std::string register_address_name(u32 reg); struct GsZbuf { GsZbuf(u64 val) : data(val) {} + GsZbuf() = default; u32 zbp() const { return data & 0b1'1111'1111; } diff --git a/common/math/Vector.h b/common/math/Vector.h index 9351b123e..e79c1149e 100644 --- a/common/math/Vector.h +++ b/common/math/Vector.h @@ -248,7 +248,7 @@ class Vector { } Vector xyz() const { return head<3>(); } - Vector xy() const { return head<2>(); } + Vector xy() const { return head<2>(); } void fill(const T& val) { for (auto& x : m_data) { diff --git a/docs/scratch/sprite_distort_vu1.txt b/docs/scratch/sprite_distort_vu1.txt new file mode 100644 index 000000000..378bccc44 --- /dev/null +++ b/docs/scratch/sprite_distort_vu1.txt @@ -0,0 +1,94 @@ +;; VU memory: +;; 0: GS vertex data (buffer 1) +;; 176: GS vertex data (buffer 2) +;; 352: sinetables.entry[128] +;; 480: sinetables.ientry[9] +;; 489: sinetables.giftag +;; 490: sinetables.color +;; 511: num sprites +;; 512: sprite data + +;; Init + lq.xyzw vf01, 489(vi00) | nop ;; Load giftag + lq.xyzw vf05, 490(vi00) | nop ;; Load color + ilw.x vi01, 511(vi00) | nop ;; Load number of sprites + iaddiu vi04, vi00, 0x200 | nop ;; Address of sprite data (512) + iaddi vi02, vi00, 0x0 | nop + +;; Loop for each sprite +L1: + ilw.w vi07, 1(vi04) | nop ;; Get sprite.flag + ;; The flag represents the 'resolution' of the sprite, + ;; which is a circle. The vertices are constructed below + ;; by creating "pie-slices" of a circle where the number + ;; of slices is the value of flag. In practice, flag + ;; can range from 3-11. + ior vi05, vi02, vi00 | nop + ilw.x vi06, 477(vi07) | nop ;; Get ptr to sinetables.entry + ;; addr = sinetables.ientry[flag - 3] + ;; The smallest value of flag is 3 and 3 + 477 = 480, + ;; which is sinetables.ientry. + ;; The values in ientry are an index of entry + 352, + ;; which gives the address of an entry element. + sqi.xyzw vf01, vi05 | nop ;; Write giftag to GS data + iaddiu vi08, vi07, 0x4000 | nop + iaddiu vi08, vi08, 0x4000 | nop + isw.x vi08, -1(vi05) | nop ;; Set giftag.nloop to flag (number of slices) + lqi.xyzw vf02, vi04 | nop ;; Get sprite.xyz + lqi.xyzw vf03, vi04 | nop ;; Get sprite.st + lqi.xyzw vf04, vi04 | nop ;; Get sprite.rgba + nop | ftoi4.xyzw vf14, vf02 + +;; Loop the number of times denoted by sprite.flag +;; Here, we build the GS data for a single distort sprite +L2: + lqi.xyzw vf06, vi06 | nop ;; Load 4 sine table vectors + lqi.xyzw vf07, vi06 | nop + lq.xyzw vf08, 0(vi06) | nop + lq.xyzw vf09, 1(vi06) | nop + iaddi vi07, vi07, -0x1 | muly.xyzw vf10, vf06, vf04 ;; Decrement loop count + nop | mulz.xyzw vf11, vf07, vf04 ;; Calculate vertex positions, texture coords, and color + nop | muly.xyzw vf12, vf08, vf04 + nop | mulz.xyzw vf13, vf09, vf04 + nop | mulx.xyzw vf06, vf06, vf04 + nop | mulx.xyzw vf07, vf07, vf04 + nop | mulx.xyzw vf08, vf08, vf04 + nop | mulx.xyzw vf09, vf09, vf04 + nop | add.xyzw vf10, vf10, vf02 + nop | add.xyzw vf11, vf11, vf03 + nop | add.xyzw vf12, vf12, vf02 + nop | add.xyzw vf13, vf13, vf03 + nop | add.xyzw vf06, vf06, vf02 + nop | add.xyzw vf07, vf07, vf03 + nop | add.xyzw vf08, vf08, vf02 + nop | add.xyzw vf09, vf09, vf03 + nop | ftoi4.xyzw vf10, vf10 + nop | ftoi4.xyzw vf12, vf12 + nop | ftoi4.xyzw vf06, vf06 + nop | ftoi4.xyzw vf08, vf08 + sqi.xyzw vf07, vi05 | nop ;; Write the 5 vertexes for this "pie-slice" to GS data + sqi.xyzw vf05, vi05 | nop + sqi.xyzw vf06, vi05 | nop + sqi.xyzw vf09, vi05 | nop + sqi.xyzw vf05, vi05 | nop + sqi.xyzw vf08, vi05 | nop + sqi.xyzw vf11, vi05 | nop + sqi.xyzw vf05, vi05 | nop + sqi.xyzw vf10, vi05 | nop + sqi.xyzw vf13, vi05 | nop + sqi.xyzw vf05, vi05 | nop + sqi.xyzw vf12, vi05 | nop + sqi.xyzw vf03, vi05 | nop + sqi.xyzw vf05, vi05 | nop + ibne vi00, vi07, L2 | nop ;; Repeat for remaining slices + sqi.xyzw vf14, vi05 | nop + +;; Finally, tell the GS to draw the current sprite and switch +;; to the other buffer for the next sprite + xgkick vi02 | nop ;; Draw sprite + iaddi vi01, vi01, -0x1 | nop + iaddiu vi03, vi00, 0xb0 | nop ;; Switch buffer + ibne vi00, vi01, L1 | nop ;; Loop for remaining sprites + isub vi02, vi03, vi02 | nop + nop | nop :e + nop | nop diff --git a/game/graphics/opengl_renderer/BucketRenderer.h b/game/graphics/opengl_renderer/BucketRenderer.h index 8b4383507..5300a4b36 100644 --- a/game/graphics/opengl_renderer/BucketRenderer.h +++ b/game/graphics/opengl_renderer/BucketRenderer.h @@ -56,6 +56,11 @@ struct SharedRenderState { EyeRenderer* eye_renderer = nullptr; std::string load_status_debug; + + int window_width_px; + int window_height_px; + int window_offset_x_px; + int window_offset_y_px; }; /*! diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 431c51614..4f7935f16 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -414,6 +414,11 @@ void OpenGLRenderer::setup_frame(int window_width_px, glDepthMask(GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDisable(GL_BLEND); + + m_render_state.window_width_px = window_width_px; + m_render_state.window_height_px = window_height_px; + m_render_state.window_offset_x_px = offset_x; + m_render_state.window_offset_y_px = offset_y; } /*! diff --git a/game/graphics/opengl_renderer/Shader.cpp b/game/graphics/opengl_renderer/Shader.cpp index 05b072e59..ef54afad4 100644 --- a/game/graphics/opengl_renderer/Shader.cpp +++ b/game/graphics/opengl_renderer/Shader.cpp @@ -87,6 +87,7 @@ ShaderLibrary::ShaderLibrary() { at(ShaderId::SHADOW) = {"shadow"}; at(ShaderId::COLLISION) = {"collision"}; at(ShaderId::MERC2) = {"merc2"}; + at(ShaderId::SPRITE_DISTORT) = {"sprite_distort"}; for (auto& shader : m_shaders) { ASSERT_MSG(shader.okay(), "Shader compiled"); diff --git a/game/graphics/opengl_renderer/Shader.h b/game/graphics/opengl_renderer/Shader.h index ec50baf37..b8f3f3021 100644 --- a/game/graphics/opengl_renderer/Shader.h +++ b/game/graphics/opengl_renderer/Shader.h @@ -42,6 +42,7 @@ enum class ShaderId { SHRUB = 17, COLLISION = 18, MERC2 = 19, + SPRITE_DISTORT = 20, MAX_SHADERS }; diff --git a/game/graphics/opengl_renderer/Sprite3.cpp b/game/graphics/opengl_renderer/Sprite3.cpp index f59a125d0..996a330dc 100644 --- a/game/graphics/opengl_renderer/Sprite3.cpp +++ b/game/graphics/opengl_renderer/Sprite3.cpp @@ -33,9 +33,20 @@ u32 process_sprite_chunk_header(DmaFollower& dma) { ASSERT(header[0] <= Sprite3::SPRITES_PER_CHUNK); return header[0]; } + +/*! + * Does the next DMA transfer look like the frame data for sprite distort? + */ +bool looks_like_distort_frame_data(const DmaFollower& dma) { + return dma.current_tag().kind == DmaTag::Kind::CNT && + dma.current_tag_vifcode0().kind == VifCode::Kind::NOP && + dma.current_tag_vifcode1().kind == VifCode::Kind::UNPACK_V4_32; +} } // namespace constexpr int SPRITE_RENDERER_MAX_SPRITES = 8000; +constexpr int SPRITE_RENDERER_MAX_DISTORT_SPRITES = + 256 * 8; // size of sprite-aux-list in GOAL code * SPRITE_MAX_AMOUNT_MULT Sprite3::Sprite3(const std::string& name, BucketId my_id) : BucketRenderer(name, my_id), m_direct(name, my_id, 1024) { @@ -58,7 +69,7 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id) glEnableVertexAttribArray(1); glVertexAttribPointer( - 1, // location 0 in the shader + 1, // location 1 in the shader 4, // 4 color components GL_FLOAT, // floats GL_TRUE, // normalized, ignored, @@ -68,7 +79,7 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id) glEnableVertexAttribArray(2); glVertexAttribPointer( - 2, // location 0 in the shader + 2, // location 2 in the shader 4, // 4 color components GL_FLOAT, // floats GL_TRUE, // normalized, ignored, @@ -78,7 +89,7 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id) glEnableVertexAttribArray(3); glVertexAttribIPointer( - 3, // location 0 in the shader + 3, // location 3 in the shader 2, // 4 color components GL_UNSIGNED_SHORT, // floats sizeof(SpriteVertex3D), // @@ -87,7 +98,7 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id) glEnableVertexAttribArray(4); glVertexAttribIPointer( - 4, // location 0 in the shader + 4, // location 4 in the shader 4, // 3 floats per vert GL_UNSIGNED_SHORT, // floats sizeof(SpriteVertex3D), // @@ -116,16 +127,81 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id) m_default_mode.set_ab(true); m_current_mode = m_default_mode; + + // distort + glGenFramebuffers(1, &m_distort_ogl.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, m_distort_ogl.fbo); + + glGenTextures(1, &m_distort_ogl.fbo_texture); + glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_distort_ogl.fbo_width, m_distort_ogl.fbo_height, 0, + GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + m_distort_ogl.fbo_texture, 0); + + ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glGenBuffers(1, &m_distort_ogl.vertex_buffer); + glGenVertexArrays(1, &m_distort_ogl.vao); + glBindVertexArray(m_distort_ogl.vao); + glBindBuffer(GL_ARRAY_BUFFER, m_distort_ogl.vertex_buffer); + // note: each sprite shares a single vertex per slice, account for that here + int distort_vert_buffer_len = + SPRITE_RENDERER_MAX_DISTORT_SPRITES * + ((5 - 1) * 11 + 1); // max * ((verts_per_slice - 1) * max_slices + 1) + glBufferData(GL_ARRAY_BUFFER, distort_vert_buffer_len * sizeof(SpriteDistortVertex), nullptr, + GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, // location 0 in the shader + 3, // 3 floats per vert + GL_FLOAT, // floats + GL_TRUE, // normalized, ignored, + sizeof(SpriteDistortVertex), // + (void*)offsetof(SpriteDistortVertex, xyz) // offset in array + ); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, // location 1 in the shader + 2, // 2 floats per vert + GL_FLOAT, // floats + GL_TRUE, // normalized, ignored, + sizeof(SpriteDistortVertex), // + (void*)offsetof(SpriteDistortVertex, st) // offset in array + ); + + // note: add one extra element per sprite that marks the end of a triangle strip + int distort_idx_buffer_len = SPRITE_RENDERER_MAX_DISTORT_SPRITES * + ((5 * 11) + 1); // max * ((verts_per_slice * max_slices) + 1) + glGenBuffers(1, &m_distort_ogl.index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_distort_ogl.index_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, distort_idx_buffer_len * sizeof(u32), nullptr, + GL_DYNAMIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + m_sprite_distorter_vertices.resize(distort_vert_buffer_len); + m_sprite_distorter_indices.resize(distort_idx_buffer_len); + m_sprite_distorter_frame_data.resize(SPRITE_RENDERER_MAX_DISTORT_SPRITES); } /*! - * Run the sprite distorter. Currently nothing uses sprite-distorter so this just skips through - * the table upload stuff that runs every frame, even if there are no sprites. + * Run the sprite distorter. */ void Sprite3::render_distorter(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) { - // Next thing should be the sprite-distorter setup + // Skip to distorter DMA m_direct.reset_state(); while (dma.current_tag().qwc != 7) { auto direct_data = dma.read_and_advance(); @@ -133,26 +209,293 @@ void Sprite3::render_distorter(DmaFollower& dma, direct_data.size_bytes, render_state, prof); } m_direct.flush_pending(render_state, prof); + + // Read DMA + { + auto prof_node = prof.make_scoped_child("dma"); + distort_dma(dma, prof_node); + } + + if (!m_enabled || !m_distort_enable) { + // Distort disabled, we can stop here since all the DMA has been read + return; + } + + // Setup vertex data + { + auto prof_node = prof.make_scoped_child("setup"); + distort_setup(prof_node); + } + + // Draw + { + auto prof_node = prof.make_scoped_child("drawing"); + distort_draw(render_state, prof_node); + } +} + +/*! + * Reads all sprite distort related DMA packets. + */ +void Sprite3::distort_dma(DmaFollower& dma, ScopedProfilerNode& /*prof*/) { + // First should be the GS setup auto sprite_distorter_direct_setup = dma.read_and_advance(); ASSERT(sprite_distorter_direct_setup.vifcode0().kind == VifCode::Kind::NOP); ASSERT(sprite_distorter_direct_setup.vifcode1().kind == VifCode::Kind::DIRECT); ASSERT(sprite_distorter_direct_setup.vifcode1().immediate == 7); - memcpy(m_sprite_distorter_setup, sprite_distorter_direct_setup.data, 7 * 16); + memcpy(&m_sprite_distorter_setup, sprite_distorter_direct_setup.data, 7 * 16); - // Next thing should be the sprite-distorter tables + auto gif_tag = m_sprite_distorter_setup.gif_tag; + ASSERT(gif_tag.nloop() == 1); + ASSERT(gif_tag.eop() == 1); + ASSERT(gif_tag.nreg() == 6); + ASSERT(gif_tag.reg(0) == GifTag::RegisterDescriptor::AD); + + auto zbuf1 = m_sprite_distorter_setup.zbuf; + ASSERT(zbuf1.zbp() == 0x1c0); + ASSERT(zbuf1.zmsk() == true); + ASSERT(zbuf1.psm() == TextureFormat::PSMZ24); + + auto tex0 = m_sprite_distorter_setup.tex0; + ASSERT(tex0.tbw() == 8); + ASSERT(tex0.tw() == 9); + ASSERT(tex0.th() == 8); + + auto tex1 = m_sprite_distorter_setup.tex1; + ASSERT(tex1.mmag() == true); + ASSERT(tex1.mmin() == 1); + + auto alpha = m_sprite_distorter_setup.alpha; + ASSERT(alpha.a_mode() == GsAlpha::BlendMode::SOURCE); + ASSERT(alpha.b_mode() == GsAlpha::BlendMode::DEST); + ASSERT(alpha.c_mode() == GsAlpha::BlendMode::SOURCE); + ASSERT(alpha.d_mode() == GsAlpha::BlendMode::DEST); + + // Next thing should be the sine tables auto sprite_distorter_tables = dma.read_and_advance(); - ASSERT(sprite_distorter_tables.size_bytes == 0x8b * 16); - ASSERT(sprite_distorter_tables.vifcode0().kind == VifCode::Kind::STCYCL); - VifCodeStcycl distorter_table_transfer(sprite_distorter_tables.vifcode0()); - ASSERT(distorter_table_transfer.cl == 4); - ASSERT(distorter_table_transfer.wl == 4); - // TODO: check unpack cmd (vif1) + unpack_to_stcycl(&m_sprite_distorter_sine_tables, sprite_distorter_tables, + VifCode::Kind::UNPACK_V4_32, 4, 4, 0x8b * 16, 0x160, false, false); - // TODO: do something with the table + ASSERT(GsPrim(m_sprite_distorter_sine_tables.gs_gif_tag.prim()).kind() == + GsPrim::Kind::TRI_STRIP); - // next would be the program, but we don't have it. + // Finally, should be frame data packets (containing sprites) + // Up to 170 sprites will be DMA'd at a time followed by a mscalf, + // and this process can happen twice up to a maximum of 256 sprites DMA'd + // (256 is the size of sprite-aux-list which drives this). + int sprite_idx = 0; + m_distort_stats.total_sprites = 0; - // TODO: next is the sprite-distorter (currently not used) + while (looks_like_distort_frame_data(dma)) { + math::Vector num_sprites_vec; + + // Read sprite packets + do { + int qwc = dma.current_tag().qwc; + int dest = dma.current_tag_vifcode1().immediate; + auto distort_data = dma.read_and_advance(); + + if (dest == 511) { + // VU address 511 specifies the number of sprites + unpack_to_no_stcycl(&num_sprites_vec, distort_data, VifCode::Kind::UNPACK_V4_32, 16, dest, + false, false); + } else { + // VU address >= 512 is the actual vertex data + ASSERT(dest >= 512); + ASSERT(sprite_idx + (qwc / 3) <= m_sprite_distorter_frame_data.capacity()); + + unpack_to_no_stcycl(&m_sprite_distorter_frame_data.at(sprite_idx), distort_data, + VifCode::Kind::UNPACK_V4_32, qwc * 16, dest, false, false); + + sprite_idx += qwc / 3; + } + } while (looks_like_distort_frame_data(dma)); + + // Sprite packets should always end with a mscalf flush + ASSERT(dma.current_tag().kind == DmaTag::Kind::CNT); + ASSERT(dma.current_tag_vifcode0().kind == VifCode::Kind::MSCALF); + ASSERT(dma.current_tag_vifcode1().kind == VifCode::Kind::FLUSH); + dma.read_and_advance(); + + m_distort_stats.total_sprites += num_sprites_vec.x(); + } + + // Done + ASSERT(m_distort_stats.total_sprites <= SPRITE_RENDERER_MAX_DISTORT_SPRITES); +} + +/*! + * Sets up OpenGL data for each distort sprite. + */ +void Sprite3::distort_setup(ScopedProfilerNode& /*prof*/) { + m_distort_stats.total_tris = 0; + + m_sprite_distorter_vertices.clear(); + m_sprite_distorter_indices.clear(); + + int sprite_idx = 0; + int sprites_left = m_distort_stats.total_sprites; + + // This part is mostly ripped from the VU program + while (sprites_left != 0) { + // flag seems to represent the 'resolution' of the circle sprite used to create the distortion + // effect For example, a flag value of 3 will create a circle using 3 "pie-slice" shapes + u32 flag = m_sprite_distorter_frame_data.at(sprite_idx).flag; + u32 slices_left = flag; + + // flag has a minimum value of 3 which represents the first ientry + // Additionally, the ientry index has 352 added to it (which is the start of the entry array + // in VU memory), so we need to subtract that as well + int entry_index = m_sprite_distorter_sine_tables.ientry[flag - 3].x() - 352; + + // Here would be adding the giftag, but we don't need that + + // Get the frame data for the next distort sprite + SpriteDistortFrameData frame_data = m_sprite_distorter_frame_data.at(sprite_idx); + sprite_idx++; + + // Build the OpenGL data for the sprite + math::Vector2f vf03 = frame_data.st; + math::Vector3f vf14 = frame_data.xyz; + + // Each slice shares a center vertex, we can use this fact and cut out duplicate vertexes + u32 center_vert_idx = m_sprite_distorter_vertices.size(); + m_sprite_distorter_vertices.push_back({vf14, vf03}); + + do { + math::Vector3f vf06 = m_sprite_distorter_sine_tables.entry[entry_index++].xyz(); + math::Vector2f vf07 = m_sprite_distorter_sine_tables.entry[entry_index++].xy(); + math::Vector3f vf08 = m_sprite_distorter_sine_tables.entry[entry_index + 0].xyz(); + math::Vector2f vf09 = m_sprite_distorter_sine_tables.entry[entry_index + 1].xy(); + + slices_left--; + + math::Vector2f vf11 = (vf07 * frame_data.rgba.z()) + frame_data.st; + math::Vector2f vf13 = (vf09 * frame_data.rgba.z()) + frame_data.st; + math::Vector3f vf06_2 = (vf06 * frame_data.rgba.x()) + frame_data.xyz; + math::Vector2f vf07_2 = (vf07 * frame_data.rgba.x()) + frame_data.st; + math::Vector3f vf08_2 = (vf08 * frame_data.rgba.x()) + frame_data.xyz; + math::Vector2f vf09_2 = (vf09 * frame_data.rgba.x()) + frame_data.st; + math::Vector3f vf10 = (vf06 * frame_data.rgba.y()) + frame_data.xyz; + math::Vector3f vf12 = (vf08 * frame_data.rgba.y()) + frame_data.xyz; + math::Vector3f vf06_3 = vf06_2; + math::Vector3f vf08_3 = vf08_2; + + m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size()); + m_sprite_distorter_vertices.push_back({vf06_3, vf07_2}); + + m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size()); + m_sprite_distorter_vertices.push_back({vf08_3, vf09_2}); + + m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size()); + m_sprite_distorter_vertices.push_back({vf10, vf11}); + + m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size()); + m_sprite_distorter_vertices.push_back({vf12, vf13}); + + // Originally, would add the shared center vertex, but in our case we can just add the index + m_sprite_distorter_indices.push_back(center_vert_idx); + // m_sprite_distorter_vertices.push_back({vf14, vf03}); + + m_distort_stats.total_tris += 2; + } while (slices_left != 0); + + // Mark the end of the triangle strip + m_sprite_distorter_indices.push_back(UINT32_MAX); + + sprites_left--; + } +} + +/*! + * Draws each distort sprite. + */ +void Sprite3::distort_draw(SharedRenderState* render_state, ScopedProfilerNode& prof) { + // First, make sure the distort framebuffer is the correct size + if (m_distort_ogl.fbo_width != render_state->window_width_px || + m_distort_ogl.fbo_height != render_state->window_height_px) { + m_distort_ogl.fbo_width = render_state->window_width_px; + m_distort_ogl.fbo_height = render_state->window_height_px; + + glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_distort_ogl.fbo_width, m_distort_ogl.fbo_height, 0, + GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_2D, 0); + } + + if (m_distort_stats.total_tris == 0) { + // No distort sprites to draw, we can end early + return; + } + + // The distort effect needs to read the current framebuffer, so copy what's been rendered so far + // to a texture that we can then pass to the shader + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_distort_ogl.fbo); + + glBlitFramebuffer(render_state->window_offset_x_px, // srcX0 + render_state->window_offset_y_px, // srcY0 + render_state->window_width_px + render_state->window_offset_x_px, // srcX1 + render_state->window_height_px + render_state->window_offset_y_px, // srcY1 + 0, // dstX0 + 0, // dstY0 + m_distort_ogl.fbo_width, // dstX1 + m_distort_ogl.fbo_height, // dstY1 + GL_COLOR_BUFFER_BIT, // mask + GL_NEAREST // filter + ); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Set up OpenGL state + m_current_mode.set_depth_write_enable(!m_sprite_distorter_setup.zbuf.zmsk()); // zbuf + glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture); // tex0 + m_current_mode.set_filt_enable(m_sprite_distorter_setup.tex1.mmag()); // tex1 + update_mode_from_alpha1(m_sprite_distorter_setup.alpha.data, m_current_mode); // alpha1 + // note: clamp and miptbp are skipped since that is set up ahead of time with the distort + // framebuffer texture + + setup_opengl_from_draw_mode(m_current_mode, GL_TEXTURE0, false); + + // Setup shader + auto shader = &render_state->shaders[ShaderId::SPRITE_DISTORT]; + shader->activate(); + + Vector4f colorf = Vector4f(m_sprite_distorter_sine_tables.color.x() / 255.0f, + m_sprite_distorter_sine_tables.color.y() / 255.0f, + m_sprite_distorter_sine_tables.color.z() / 255.0f, + m_sprite_distorter_sine_tables.color.w() / 255.0f); + glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data()); + + // Bind vertex array + glBindVertexArray(m_distort_ogl.vao); + + // Enable prim restart, we need this to break up the triangle strips + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex(UINT32_MAX); + + // Upload vertex data + glBindBuffer(GL_ARRAY_BUFFER, m_distort_ogl.vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, m_sprite_distorter_vertices.size() * sizeof(SpriteDistortVertex), + m_sprite_distorter_vertices.data(), GL_DYNAMIC_DRAW); + + // Upload element data + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_distort_ogl.index_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_sprite_distorter_indices.size() * sizeof(u32), + m_sprite_distorter_indices.data(), GL_DYNAMIC_DRAW); + + // Draw + prof.add_draw_call(); + prof.add_tri(m_distort_stats.total_tris); + + glDrawElements(GL_TRIANGLE_STRIP, m_sprite_distorter_indices.size(), GL_UNSIGNED_INT, (void*)0); + + // Done + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(0); } /*! @@ -417,6 +760,7 @@ void Sprite3::render(DmaFollower& dma, SharedRenderState* render_state, ScopedPr void Sprite3::draw_debug_window() { ImGui::Separator(); + ImGui::Text("Distort sprites: %d", m_distort_stats.total_sprites); ImGui::Text("2D Group 0 (World) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp0, m_debug_stats.count_2d_grp0); ImGui::Text("2D Group 1 (HUD) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp1, @@ -425,6 +769,7 @@ void Sprite3::draw_debug_window() { ImGui::Checkbox("2d", &m_2d_enable); ImGui::SameLine(); ImGui::Checkbox("3d", &m_3d_enable); + ImGui::Checkbox("Distort", &m_distort_enable); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -571,7 +916,7 @@ void Sprite3::handle_clamp(u64 val, m_current_mode.set_clamp_t_enable(val & 0b100); } -void update_mode_from_alpha1(u64 val, DrawMode& mode) { +void Sprite3::update_mode_from_alpha1(u64 val, DrawMode& mode) { GsAlpha reg(val); if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && reg.b_mode() == GsAlpha::BlendMode::DEST && reg.c_mode() == GsAlpha::BlendMode::SOURCE && reg.d_mode() == GsAlpha::BlendMode::DEST) { diff --git a/game/graphics/opengl_renderer/Sprite3.h b/game/graphics/opengl_renderer/Sprite3.h index 4b20be892..af668cea3 100644 --- a/game/graphics/opengl_renderer/Sprite3.h +++ b/game/graphics/opengl_renderer/Sprite3.h @@ -22,6 +22,9 @@ class Sprite3 : public BucketRenderer { void render_distorter(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof); + void distort_dma(DmaFollower& dma, ScopedProfilerNode& prof); + void distort_setup(ScopedProfilerNode& prof); + void distort_draw(SharedRenderState* render_state, ScopedProfilerNode& prof); void handle_sprite_frame_setup(DmaFollower& dma); void render_3d(DmaFollower& dma); void render_2d_group0(DmaFollower& dma, @@ -37,6 +40,7 @@ class Sprite3 : public BucketRenderer { SharedRenderState* render_state, ScopedProfilerNode& prof); + void update_mode_from_alpha1(u64 val, DrawMode& mode); void handle_tex0(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); void handle_tex1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); // void handle_mip(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); @@ -46,7 +50,67 @@ class Sprite3 : public BucketRenderer { void flush_sprites(SharedRenderState* render_state, ScopedProfilerNode& prof, bool double_draw); - u8 m_sprite_distorter_setup[7 * 16]; // direct data + struct SpriteDistorterSetup { + GifTag gif_tag; + GsZbuf zbuf; + u64 zbuf_addr; + GsTex0 tex0; + u64 tex0_addr; + GsTex1 tex1; + u64 tex1_addr; + u64 miptbp; + u64 miptbp_addr; + u64 clamp; + u64 clamp_addr; + GsAlpha alpha; + u64 alpha_addr; + }; + static_assert(sizeof(SpriteDistorterSetup) == (7 * 16)); + + struct SpriteDistorterSineTables { + Vector4f entry[128]; + math::Vector ientry[9]; + GifTag gs_gif_tag; + math::Vector color; + }; + static_assert(sizeof(SpriteDistorterSineTables) == (0x8b * 16)); + + struct SpriteDistortFrameData { + math::Vector3f xyz; // position + float num_255; // always 255.0 + math::Vector2f st; // texture coords + float num_1; // always 1.0 + u32 flag; // 'resolution' of the sprite + Vector4f rgba; // ? (doesn't seem to be color) + }; + static_assert(sizeof(SpriteDistortFrameData) == 16 * 3); + + struct SpriteDistortVertex { + math::Vector3f xyz; + math::Vector2f st; + }; + + struct { + GLuint vao; + GLuint vertex_buffer; + GLuint index_buffer; + GLuint fbo; + GLuint fbo_texture; + int fbo_width = 640; + int fbo_height = 480; + } m_distort_ogl; + + struct { + int total_sprites; + int total_tris; + } m_distort_stats; + + std::vector m_sprite_distorter_vertices; + std::vector m_sprite_distorter_indices; + SpriteDistorterSetup m_sprite_distorter_setup; // direct data + SpriteDistorterSineTables m_sprite_distorter_sine_tables; + std::vector m_sprite_distorter_frame_data; + u8 m_sprite_direct_setup[3 * 16]; SpriteFrameData m_frame_data; // qwa: 980 Sprite3DMatrixData m_3d_matrix_data; @@ -67,6 +131,7 @@ class Sprite3 : public BucketRenderer { bool m_2d_enable = true; bool m_3d_enable = true; + bool m_distort_enable = true; struct SpriteVertex3D { math::Vector4f xyz_sx; // position + x scale @@ -104,4 +169,4 @@ class Sprite3 : public BucketRenderer { u64 m_sprite_idx = 0; std::vector m_index_buffer_data; -}; \ No newline at end of file +}; diff --git a/game/graphics/opengl_renderer/shaders/sprite_distort.frag b/game/graphics/opengl_renderer/shaders/sprite_distort.frag new file mode 100644 index 000000000..3170235a0 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/sprite_distort.frag @@ -0,0 +1,21 @@ +#version 430 core + +out vec4 out_color; + +uniform sampler2D framebuffer_tex; + +in flat vec4 fragment_color; +in vec2 tex_coord; + +void main() { + vec4 color = fragment_color; + + // correct color + color *= 2; + + // correct texture coordinates + vec2 texture_coords = vec2(tex_coord.x, (1.0f - tex_coord.y) - (1 - (448.0/512.0)) / 2); + + // sample framebuffer texture + out_color = color * texture(framebuffer_tex, texture_coords); +} diff --git a/game/graphics/opengl_renderer/shaders/sprite_distort.vert b/game/graphics/opengl_renderer/shaders/sprite_distort.vert new file mode 100644 index 000000000..31726c59e --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/sprite_distort.vert @@ -0,0 +1,26 @@ +#version 430 core + +layout (location = 0) in vec3 xyz; +layout (location = 1) in vec2 st; + +uniform vec4 u_color; + +out flat vec4 fragment_color; +out vec2 tex_coord; + +void main() { + fragment_color = u_color; + tex_coord = st; + vec4 transformed = vec4(xyz, 1.0); + + // correct xy offset + transformed.xy -= (2048.); + // correct z scale + transformed.z /= (8388608); + transformed.z -= 1; + // correct xy scale + transformed.x /= (256); + transformed.y /= -(128); + + gl_Position = transformed; +} diff --git a/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc b/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc index 6bb1823b2..8706e1aff 100644 --- a/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc +++ b/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc @@ -26,59 +26,64 @@ (defun sprite-distorter-generate-tables () "Regenerate sprite-distorter tables. This should be done whenever the aspect ratio changes" - (let ((gp-0 *sprite-distorter-sine-tables*)) - (let ((s3-0 0) - (s5-0 0) - (s4-0 3) - (f28-0 (- (-> *math-camera* perspective vector 0 x))) - (f30-0 (- (-> *math-camera* perspective vector 1 y))) + (let ((tables *sprite-distorter-sine-tables*)) + (let ((entry-index 0) + (ientry-index 0) + (iterations 3) + ;; get camera aspect + (cam-aspx (- (-> *math-camera* perspective vector 0 x))) + (cam-aspy (- (-> *math-camera* perspective vector 1 y))) ) - (when (or (!= f28-0 (-> gp-0 aspx)) (!= f30-0 (-> gp-0 aspy))) - (set! (-> gp-0 aspx) f28-0) - (set! (-> gp-0 aspy) f30-0) - (while (< s4-0 12) - (set! (-> gp-0 ientry s5-0 vector4w x) (+ s3-0 352)) - (+! s5-0 1) - (dotimes (s2-0 s4-0) - (let ((f26-0 (* 65536.0 (/ (the float s2-0) (the float s4-0))))) + ;; regenerate if aspect ratio changed + (when (or (!= cam-aspx (-> tables aspx)) (!= cam-aspy (-> tables aspy))) + (set! (-> tables aspx) cam-aspx) + (set! (-> tables aspy) cam-aspy) + (while (< iterations 12) + ;; set ientry + (set! (-> tables ientry ientry-index vector4w x) (+ entry-index 352)) ;; 352 = tables.entry in VU + (+! ientry-index 1) + ;; set entries + (dotimes (i iterations) + (let ((f26-0 (* 65536.0 (/ (the float i) (the float iterations))))) (set-vector! - (-> gp-0 entry s3-0) - (* (sin f26-0) f28-0) - (* (cos f26-0) f30-0) + (-> tables entry entry-index) + (* (sin f26-0) cam-aspx) + (* (cos f26-0) cam-aspy) 0.0 0.0 ) - (let ((s3-1 (+ s3-0 1))) - (set-vector! - (-> gp-0 entry s3-1) - (* (* 0.001953125 f28-0) (sin f26-0)) - (* (* 0.00390625 f30-0) (cos f26-0)) - 0.0 - 0.0 - ) - (set! s3-0 (+ s3-1 1)) + (set-vector! + (-> tables entry (+ entry-index 1)) + (* (* 0.001953125 cam-aspx) (sin f26-0)) + (* (* 0.00390625 cam-aspy) (cos f26-0)) + 0.0 + 0.0 ) + (+! entry-index 2) ) ) - (+! s4-0 1) + (+! iterations 1) ) - (set-vector! (-> gp-0 entry s3-0) 0.0 f30-0 0.0 0.0) - (let ((v1-17 (+ s3-0 1))) - (set-vector! (-> gp-0 entry v1-17) 0.0 (* 0.00390625 f30-0) 0.0 0.0) - (+ v1-17 1) + ;; final entry pair + (set-vector! (-> tables entry entry-index) 0.0 cam-aspy 0.0 0.0) + (let ((v1-17 (+ entry-index 1))) + (set-vector! (-> tables entry v1-17) 0.0 (* 0.00390625 cam-aspy) 0.0 0.0) + (+ v1-17 1) ;; ? ) ) ) - (set! (-> gp-0 giftag tag) + ;; set up giftag + (set! (-> tables giftag tag) (new 'static 'gif-tag64 - :nloop #x1 - :eop #x1 - :pre #x1 - :prim (new 'static 'gs-prim :prim (gs-prim-type tri-strip) :tme #x1) - :nreg #xf + :nloop 1 + :eop 1 + :pre 1 + :prim (new 'static 'gs-prim :prim (gs-prim-type tri-strip) :tme 1) + :nreg 15 ) ) - (set! (-> gp-0 giftag regs) + ;; set up registers + (set! (-> tables giftag regs) (new 'static 'gif-tag-regs :regs0 (gif-reg-id st) :regs1 (gif-reg-id rgbaq) @@ -97,10 +102,11 @@ :regs14 (gif-reg-id xyzf2) ) ) - (set! (-> gp-0 color vector4w x) 128) - (set! (-> gp-0 color vector4w y) 128) - (set! (-> gp-0 color vector4w z) 128) - (set! (-> gp-0 color vector4w w) 128) + ;; set color + (set! (-> tables color vector4w x) 128) + (set! (-> tables color vector4w y) 128) + (set! (-> tables color vector4w z) 128) + (set! (-> tables color vector4w w) 128) ) 0 (none) @@ -111,92 +117,40 @@ (define sprite-distort-vu1-block (new 'static 'vu-function)) -(defun sprite-init-distorter ((arg0 dma-buffer) (arg1 uint)) +(defun sprite-init-distorter ((dma-buff dma-buffer) (frame-base-pointer uint)) "Set up DMA for setting up the sprite-distorter renderer" ;;(format #t "distorter: ~d~%" (-> *sprite-aux-list* entry)) - (let* ((v1-0 arg0) - (a2-0 (the-as object (-> v1-0 base))) - ) - (set! (-> (the-as dma-packet a2-0) dma) (new 'static 'dma-tag :qwc #x7 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet a2-0) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet a2-0) vif1) (new 'static 'vif-tag :imm #x7 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> v1-0 base) (&+ (the-as pointer a2-0) 16)) + + ;; set up GS registers + (dma-buffer-add-gs-set dma-buff + ;; dont update zbuffer + (zbuf-1 (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24) :zmsk 1)) + ;; use framebuffer as texture + (tex0-1 (new 'static 'gs-tex0 :tbw #x8 :tw #x9 :th #x8 :tbp0 (* frame-base-pointer 32))) + ;; bilinear filtering + (tex1-1 (new 'static 'gs-tex1 :mmag 1 :mmin 1)) + ;; mipmapping + (miptbp1-1 (new 'static 'gs-miptbp)) + ;; set texture wrap mode to clamp + (clamp-1 + (new 'static 'gs-clamp + :wms (gs-tex-wrap-mode region-clamp) + :wmt (gs-tex-wrap-mode region-clamp) + :maxu #x1ff + :maxv (-> *video-parms* screen-masky) + ) + ) + ;; blend source and framebuffer RGB + (alpha-1 (new 'static 'gs-alpha :b 1 :d 1)) ) - (let* ((v1-1 arg0) - (a2-2 (the-as object (-> v1-1 base))) - ) - (set! (-> (the-as gs-gif-tag a2-2) tag) - (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x6) - ) - (set! (-> (the-as gs-gif-tag a2-2) regs) - (new 'static 'gif-tag-regs - :regs0 (gif-reg-id a+d) - :regs1 (gif-reg-id a+d) - :regs2 (gif-reg-id a+d) - :regs3 (gif-reg-id a+d) - :regs4 (gif-reg-id a+d) - :regs5 (gif-reg-id a+d) - :regs6 (gif-reg-id a+d) - :regs7 (gif-reg-id a+d) - :regs8 (gif-reg-id a+d) - :regs9 (gif-reg-id a+d) - :regs10 (gif-reg-id a+d) - :regs11 (gif-reg-id a+d) - :regs12 (gif-reg-id a+d) - :regs13 (gif-reg-id a+d) - :regs14 (gif-reg-id a+d) - :regs15 (gif-reg-id a+d) - ) - ) - (set! (-> v1-1 base) (&+ (the-as pointer a2-2) 16)) + ;; send distorter sine tables + (dma-buffer-add-ref-vif2 dma-buff #x8b + (-> *sprite-distorter-sine-tables* entry) + (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl)) + (new 'static 'vif-tag :imm #x160 :num #x8b :cmd (vif-cmd unpack-v4-32)) ) - (let* ((v1-2 arg0) - (a2-4 (-> v1-2 base)) - ) - (set! (-> (the-as (pointer gs-zbuf) a2-4) 0) - (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24) :zmsk #x1) - ) - (set! (-> (the-as (pointer gs-reg64) a2-4) 1) (gs-reg64 zbuf-1)) - (set! (-> (the-as (pointer gs-tex0) a2-4) 2) - (new 'static 'gs-tex0 :tbw #x8 :tw #x9 :th #x8 :tbp0 (* arg1 32)) - ) - (set! (-> (the-as (pointer gs-reg64) a2-4) 3) (gs-reg64 tex0-1)) - (set! (-> (the-as (pointer gs-tex1) a2-4) 4) - (new 'static 'gs-tex1 :mmag #x1 :mmin #x1) - ) - (set! (-> (the-as (pointer gs-reg64) a2-4) 5) (gs-reg64 tex1-1)) - (set! (-> (the-as (pointer gs-miptbp) a2-4) 6) (new 'static 'gs-miptbp)) - (set! (-> (the-as (pointer gs-reg64) a2-4) 7) (gs-reg64 miptbp1-1)) - (set! (-> (the-as (pointer gs-clamp) a2-4) 8) - (new 'static 'gs-clamp - :wms (gs-tex-wrap-mode region-clamp) - :wmt (gs-tex-wrap-mode region-clamp) - :maxu #x1ff - :maxv (-> *video-parms* screen-masky) - ) - ) - (set! (-> (the-as (pointer gs-reg64) a2-4) 9) (gs-reg64 clamp-1)) - (set! (-> (the-as (pointer gs-alpha) a2-4) 10) - (new 'static 'gs-alpha :b #x1 :d #x1) - ) - (set! (-> (the-as (pointer gs-reg64) a2-4) 11) (gs-reg64 alpha-1)) - (set! (-> v1-2 base) (&+ a2-4 96)) - ) - (let* ((v1-3 arg0) - (a1-15 (the-as object (-> v1-3 base))) - ) - (set! (-> (the-as dma-packet a1-15) dma) - (new 'static 'dma-tag - :qwc #x8b - :id (dma-tag-id ref) - :addr (the-as uint (-> *sprite-distorter-sine-tables* entry)) - ) - ) - (set! (-> (the-as dma-packet a1-15) vif0) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))) - (set! (-> (the-as dma-packet a1-15) vif1) (new 'static 'vif-tag :imm #x160 :num #x8b :cmd (vif-cmd unpack-v4-32))) - (set! (-> v1-3 base) (&+ (the-as pointer a1-15) 16)) - ) - (dma-buffer-add-vu-function arg0 sprite-distort-vu1-block 1) + ;; load VU1 code + (dma-buffer-add-vu-function dma-buff sprite-distort-vu1-block 1) 0 (none) ) diff --git a/goal_src/jak1/engine/gfx/sprite/sprite.gc b/goal_src/jak1/engine/gfx/sprite/sprite.gc index c34a7afbb..4c12e2400 100644 --- a/goal_src/jak1/engine/gfx/sprite/sprite.gc +++ b/goal_src/jak1/engine/gfx/sprite/sprite.gc @@ -87,6 +87,9 @@ (defmethod new sprite-aux-list ((allocation symbol) (type-to-make type) (size int)) "Allocate a sprite-aux-list with room for size 4-byte entries" + (#when PC_BIG_MEMORY + (*! size SPRITE_MAX_AMOUNT_MULT) + ) (let ((v0-0 (object-new allocation type-to-make (the-as int (+ (-> type-to-make size) (the-as uint (* (+ size -1) 4)))) ) @@ -117,7 +120,6 @@ ) (defun add-to-sprite-aux-list ((arg0 sparticle-system) (arg1 sparticle-cpuinfo) (arg2 sprite-vec-data-3d)) - (return 0) ;; hack (let ((v1-0 *sprite-aux-list*)) (when (< (-> v1-0 entry) (-> v1-0 num-entries)) (set! (-> v1-0 data (-> v1-0 entry)) (-> arg1 sprite))