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
This commit is contained in:
Ethan Lafrenais 2022-07-08 21:56:38 -04:00 committed by GitHub
parent 5e23057ed1
commit 8ba010ca97
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 667 additions and 147 deletions

View file

@ -125,6 +125,7 @@ std::string register_address_name(u32 reg);
struct GsZbuf { struct GsZbuf {
GsZbuf(u64 val) : data(val) {} GsZbuf(u64 val) : data(val) {}
GsZbuf() = default;
u32 zbp() const { return data & 0b1'1111'1111; } u32 zbp() const { return data & 0b1'1111'1111; }

View file

@ -248,7 +248,7 @@ class Vector {
} }
Vector<T, 3> xyz() const { return head<3>(); } Vector<T, 3> xyz() const { return head<3>(); }
Vector<T, 3> xy() const { return head<2>(); } Vector<T, 2> xy() const { return head<2>(); }
void fill(const T& val) { void fill(const T& val) {
for (auto& x : m_data) { for (auto& x : m_data) {

View file

@ -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

View file

@ -56,6 +56,11 @@ struct SharedRenderState {
EyeRenderer* eye_renderer = nullptr; EyeRenderer* eye_renderer = nullptr;
std::string load_status_debug; std::string load_status_debug;
int window_width_px;
int window_height_px;
int window_offset_x_px;
int window_offset_y_px;
}; };
/*! /*!

View file

@ -414,6 +414,11 @@ void OpenGLRenderer::setup_frame(int window_width_px,
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDisable(GL_BLEND); 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;
} }
/*! /*!

View file

@ -87,6 +87,7 @@ ShaderLibrary::ShaderLibrary() {
at(ShaderId::SHADOW) = {"shadow"}; at(ShaderId::SHADOW) = {"shadow"};
at(ShaderId::COLLISION) = {"collision"}; at(ShaderId::COLLISION) = {"collision"};
at(ShaderId::MERC2) = {"merc2"}; at(ShaderId::MERC2) = {"merc2"};
at(ShaderId::SPRITE_DISTORT) = {"sprite_distort"};
for (auto& shader : m_shaders) { for (auto& shader : m_shaders) {
ASSERT_MSG(shader.okay(), "Shader compiled"); ASSERT_MSG(shader.okay(), "Shader compiled");

View file

@ -42,6 +42,7 @@ enum class ShaderId {
SHRUB = 17, SHRUB = 17,
COLLISION = 18, COLLISION = 18,
MERC2 = 19, MERC2 = 19,
SPRITE_DISTORT = 20,
MAX_SHADERS MAX_SHADERS
}; };

View file

@ -33,9 +33,20 @@ u32 process_sprite_chunk_header(DmaFollower& dma) {
ASSERT(header[0] <= Sprite3::SPRITES_PER_CHUNK); ASSERT(header[0] <= Sprite3::SPRITES_PER_CHUNK);
return header[0]; 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 } // namespace
constexpr int SPRITE_RENDERER_MAX_SPRITES = 8000; 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) Sprite3::Sprite3(const std::string& name, BucketId my_id)
: BucketRenderer(name, my_id), m_direct(name, my_id, 1024) { : 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); glEnableVertexAttribArray(1);
glVertexAttribPointer( glVertexAttribPointer(
1, // location 0 in the shader 1, // location 1 in the shader
4, // 4 color components 4, // 4 color components
GL_FLOAT, // floats GL_FLOAT, // floats
GL_TRUE, // normalized, ignored, GL_TRUE, // normalized, ignored,
@ -68,7 +79,7 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id)
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glVertexAttribPointer( glVertexAttribPointer(
2, // location 0 in the shader 2, // location 2 in the shader
4, // 4 color components 4, // 4 color components
GL_FLOAT, // floats GL_FLOAT, // floats
GL_TRUE, // normalized, ignored, GL_TRUE, // normalized, ignored,
@ -78,7 +89,7 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id)
glEnableVertexAttribArray(3); glEnableVertexAttribArray(3);
glVertexAttribIPointer( glVertexAttribIPointer(
3, // location 0 in the shader 3, // location 3 in the shader
2, // 4 color components 2, // 4 color components
GL_UNSIGNED_SHORT, // floats GL_UNSIGNED_SHORT, // floats
sizeof(SpriteVertex3D), // sizeof(SpriteVertex3D), //
@ -87,7 +98,7 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id)
glEnableVertexAttribArray(4); glEnableVertexAttribArray(4);
glVertexAttribIPointer( glVertexAttribIPointer(
4, // location 0 in the shader 4, // location 4 in the shader
4, // 3 floats per vert 4, // 3 floats per vert
GL_UNSIGNED_SHORT, // floats GL_UNSIGNED_SHORT, // floats
sizeof(SpriteVertex3D), // sizeof(SpriteVertex3D), //
@ -116,16 +127,81 @@ Sprite3::Sprite3(const std::string& name, BucketId my_id)
m_default_mode.set_ab(true); m_default_mode.set_ab(true);
m_current_mode = m_default_mode; 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 * Run the sprite distorter.
* the table upload stuff that runs every frame, even if there are no sprites.
*/ */
void Sprite3::render_distorter(DmaFollower& dma, void Sprite3::render_distorter(DmaFollower& dma,
SharedRenderState* render_state, SharedRenderState* render_state,
ScopedProfilerNode& prof) { ScopedProfilerNode& prof) {
// Next thing should be the sprite-distorter setup // Skip to distorter DMA
m_direct.reset_state(); m_direct.reset_state();
while (dma.current_tag().qwc != 7) { while (dma.current_tag().qwc != 7) {
auto direct_data = dma.read_and_advance(); auto direct_data = dma.read_and_advance();
@ -133,26 +209,293 @@ void Sprite3::render_distorter(DmaFollower& dma,
direct_data.size_bytes, render_state, prof); direct_data.size_bytes, render_state, prof);
} }
m_direct.flush_pending(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(); auto sprite_distorter_direct_setup = dma.read_and_advance();
ASSERT(sprite_distorter_direct_setup.vifcode0().kind == VifCode::Kind::NOP); 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().kind == VifCode::Kind::DIRECT);
ASSERT(sprite_distorter_direct_setup.vifcode1().immediate == 7); 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(); auto sprite_distorter_tables = dma.read_and_advance();
ASSERT(sprite_distorter_tables.size_bytes == 0x8b * 16); unpack_to_stcycl(&m_sprite_distorter_sine_tables, sprite_distorter_tables,
ASSERT(sprite_distorter_tables.vifcode0().kind == VifCode::Kind::STCYCL); VifCode::Kind::UNPACK_V4_32, 4, 4, 0x8b * 16, 0x160, false, false);
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)
// 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<u32, 4> 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() { void Sprite3::draw_debug_window() {
ImGui::Separator(); 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, ImGui::Text("2D Group 0 (World) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp0,
m_debug_stats.count_2d_grp0); m_debug_stats.count_2d_grp0);
ImGui::Text("2D Group 1 (HUD) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp1, 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::Checkbox("2d", &m_2d_enable);
ImGui::SameLine(); ImGui::SameLine();
ImGui::Checkbox("3d", &m_3d_enable); 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); 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); GsAlpha reg(val);
if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && reg.b_mode() == GsAlpha::BlendMode::DEST && 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) { reg.c_mode() == GsAlpha::BlendMode::SOURCE && reg.d_mode() == GsAlpha::BlendMode::DEST) {

View file

@ -22,6 +22,9 @@ class Sprite3 : public BucketRenderer {
void render_distorter(DmaFollower& dma, void render_distorter(DmaFollower& dma,
SharedRenderState* render_state, SharedRenderState* render_state,
ScopedProfilerNode& prof); 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 handle_sprite_frame_setup(DmaFollower& dma);
void render_3d(DmaFollower& dma); void render_3d(DmaFollower& dma);
void render_2d_group0(DmaFollower& dma, void render_2d_group0(DmaFollower& dma,
@ -37,6 +40,7 @@ class Sprite3 : public BucketRenderer {
SharedRenderState* render_state, SharedRenderState* render_state,
ScopedProfilerNode& prof); ScopedProfilerNode& prof);
void update_mode_from_alpha1(u64 val, DrawMode& mode);
void handle_tex0(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); void handle_tex0(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_tex1(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); // 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); 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<u32, 4> ientry[9];
GifTag gs_gif_tag;
math::Vector<u32, 4> 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<SpriteDistortVertex> m_sprite_distorter_vertices;
std::vector<u32> m_sprite_distorter_indices;
SpriteDistorterSetup m_sprite_distorter_setup; // direct data
SpriteDistorterSineTables m_sprite_distorter_sine_tables;
std::vector<SpriteDistortFrameData> m_sprite_distorter_frame_data;
u8 m_sprite_direct_setup[3 * 16]; u8 m_sprite_direct_setup[3 * 16];
SpriteFrameData m_frame_data; // qwa: 980 SpriteFrameData m_frame_data; // qwa: 980
Sprite3DMatrixData m_3d_matrix_data; Sprite3DMatrixData m_3d_matrix_data;
@ -67,6 +131,7 @@ class Sprite3 : public BucketRenderer {
bool m_2d_enable = true; bool m_2d_enable = true;
bool m_3d_enable = true; bool m_3d_enable = true;
bool m_distort_enable = true;
struct SpriteVertex3D { struct SpriteVertex3D {
math::Vector4f xyz_sx; // position + x scale math::Vector4f xyz_sx; // position + x scale
@ -104,4 +169,4 @@ class Sprite3 : public BucketRenderer {
u64 m_sprite_idx = 0; u64 m_sprite_idx = 0;
std::vector<u32> m_index_buffer_data; std::vector<u32> m_index_buffer_data;
}; };

View file

@ -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);
}

View file

@ -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;
}

View file

@ -26,59 +26,64 @@
(defun sprite-distorter-generate-tables () (defun sprite-distorter-generate-tables ()
"Regenerate sprite-distorter tables. This should be done whenever the aspect ratio changes" "Regenerate sprite-distorter tables. This should be done whenever the aspect ratio changes"
(let ((gp-0 *sprite-distorter-sine-tables*)) (let ((tables *sprite-distorter-sine-tables*))
(let ((s3-0 0) (let ((entry-index 0)
(s5-0 0) (ientry-index 0)
(s4-0 3) (iterations 3)
(f28-0 (- (-> *math-camera* perspective vector 0 x))) ;; get camera aspect
(f30-0 (- (-> *math-camera* perspective vector 1 y))) (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))) ;; regenerate if aspect ratio changed
(set! (-> gp-0 aspx) f28-0) (when (or (!= cam-aspx (-> tables aspx)) (!= cam-aspy (-> tables aspy)))
(set! (-> gp-0 aspy) f30-0) (set! (-> tables aspx) cam-aspx)
(while (< s4-0 12) (set! (-> tables aspy) cam-aspy)
(set! (-> gp-0 ientry s5-0 vector4w x) (+ s3-0 352)) (while (< iterations 12)
(+! s5-0 1) ;; set ientry
(dotimes (s2-0 s4-0) (set! (-> tables ientry ientry-index vector4w x) (+ entry-index 352)) ;; 352 = tables.entry in VU
(let ((f26-0 (* 65536.0 (/ (the float s2-0) (the float s4-0))))) (+! ientry-index 1)
;; set entries
(dotimes (i iterations)
(let ((f26-0 (* 65536.0 (/ (the float i) (the float iterations)))))
(set-vector! (set-vector!
(-> gp-0 entry s3-0) (-> tables entry entry-index)
(* (sin f26-0) f28-0) (* (sin f26-0) cam-aspx)
(* (cos f26-0) f30-0) (* (cos f26-0) cam-aspy)
0.0 0.0
0.0 0.0
) )
(let ((s3-1 (+ s3-0 1))) (set-vector!
(set-vector! (-> tables entry (+ entry-index 1))
(-> gp-0 entry s3-1) (* (* 0.001953125 cam-aspx) (sin f26-0))
(* (* 0.001953125 f28-0) (sin f26-0)) (* (* 0.00390625 cam-aspy) (cos f26-0))
(* (* 0.00390625 f30-0) (cos f26-0)) 0.0
0.0 0.0
0.0
)
(set! s3-0 (+ s3-1 1))
) )
(+! entry-index 2)
) )
) )
(+! s4-0 1) (+! iterations 1)
) )
(set-vector! (-> gp-0 entry s3-0) 0.0 f30-0 0.0 0.0) ;; final entry pair
(let ((v1-17 (+ s3-0 1))) (set-vector! (-> tables entry entry-index) 0.0 cam-aspy 0.0 0.0)
(set-vector! (-> gp-0 entry v1-17) 0.0 (* 0.00390625 f30-0) 0.0 0.0) (let ((v1-17 (+ entry-index 1)))
(+ v1-17 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 (new 'static 'gif-tag64
:nloop #x1 :nloop 1
:eop #x1 :eop 1
:pre #x1 :pre 1
:prim (new 'static 'gs-prim :prim (gs-prim-type tri-strip) :tme #x1) :prim (new 'static 'gs-prim :prim (gs-prim-type tri-strip) :tme 1)
:nreg #xf :nreg 15
) )
) )
(set! (-> gp-0 giftag regs) ;; set up registers
(set! (-> tables giftag regs)
(new 'static 'gif-tag-regs (new 'static 'gif-tag-regs
:regs0 (gif-reg-id st) :regs0 (gif-reg-id st)
:regs1 (gif-reg-id rgbaq) :regs1 (gif-reg-id rgbaq)
@ -97,10 +102,11 @@
:regs14 (gif-reg-id xyzf2) :regs14 (gif-reg-id xyzf2)
) )
) )
(set! (-> gp-0 color vector4w x) 128) ;; set color
(set! (-> gp-0 color vector4w y) 128) (set! (-> tables color vector4w x) 128)
(set! (-> gp-0 color vector4w z) 128) (set! (-> tables color vector4w y) 128)
(set! (-> gp-0 color vector4w w) 128) (set! (-> tables color vector4w z) 128)
(set! (-> tables color vector4w w) 128)
) )
0 0
(none) (none)
@ -111,92 +117,40 @@
(define sprite-distort-vu1-block (new 'static 'vu-function)) (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" "Set up DMA for setting up the sprite-distorter renderer"
;;(format #t "distorter: ~d~%" (-> *sprite-aux-list* entry)) ;;(format #t "distorter: ~d~%" (-> *sprite-aux-list* entry))
(let* ((v1-0 arg0)
(a2-0 (the-as object (-> v1-0 base))) ;; set up GS registers
) (dma-buffer-add-gs-set dma-buff
(set! (-> (the-as dma-packet a2-0) dma) (new 'static 'dma-tag :qwc #x7 :id (dma-tag-id cnt))) ;; dont update zbuffer
(set! (-> (the-as dma-packet a2-0) vif0) (new 'static 'vif-tag)) (zbuf-1 (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24) :zmsk 1))
(set! (-> (the-as dma-packet a2-0) vif1) (new 'static 'vif-tag :imm #x7 :cmd (vif-cmd direct) :msk #x1)) ;; use framebuffer as texture
(set! (-> v1-0 base) (&+ (the-as pointer a2-0) 16)) (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) ;; send distorter sine tables
(a2-2 (the-as object (-> v1-1 base))) (dma-buffer-add-ref-vif2 dma-buff #x8b
) (-> *sprite-distorter-sine-tables* entry)
(set! (-> (the-as gs-gif-tag a2-2) tag) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
(new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x6) (new 'static 'vif-tag :imm #x160 :num #x8b :cmd (vif-cmd unpack-v4-32))
)
(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))
) )
(let* ((v1-2 arg0) ;; load VU1 code
(a2-4 (-> v1-2 base)) (dma-buffer-add-vu-function dma-buff sprite-distort-vu1-block 1)
)
(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)
0 0
(none) (none)
) )

View file

@ -87,6 +87,9 @@
(defmethod new sprite-aux-list ((allocation symbol) (type-to-make type) (size int)) (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" "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 (let ((v0-0 (object-new allocation type-to-make
(the-as int (+ (-> type-to-make size) (the-as uint (* (+ size -1) 4)))) (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)) (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*)) (let ((v1-0 *sprite-aux-list*))
(when (< (-> v1-0 entry) (-> v1-0 num-entries)) (when (< (-> v1-0 entry) (-> v1-0 num-entries))
(set! (-> v1-0 data (-> v1-0 entry)) (-> arg1 sprite)) (set! (-> v1-0 data (-> v1-0 entry)) (-> arg1 sprite))