mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 00:57:44 -04:00
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:
parent
5e23057ed1
commit
8ba010ca97
|
@ -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; }
|
||||
|
||||
|
|
|
@ -248,7 +248,7 @@ class Vector {
|
|||
}
|
||||
|
||||
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) {
|
||||
for (auto& x : m_data) {
|
||||
|
|
94
docs/scratch/sprite_distort_vu1.txt
Normal file
94
docs/scratch/sprite_distort_vu1.txt
Normal 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
|
|
@ -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;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -42,6 +42,7 @@ enum class ShaderId {
|
|||
SHRUB = 17,
|
||||
COLLISION = 18,
|
||||
MERC2 = 19,
|
||||
SPRITE_DISTORT = 20,
|
||||
MAX_SHADERS
|
||||
};
|
||||
|
||||
|
|
|
@ -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<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() {
|
||||
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) {
|
||||
|
|
|
@ -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<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];
|
||||
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<u32> m_index_buffer_data;
|
||||
};
|
||||
};
|
||||
|
|
21
game/graphics/opengl_renderer/shaders/sprite_distort.frag
Normal file
21
game/graphics/opengl_renderer/shaders/sprite_distort.frag
Normal 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);
|
||||
}
|
26
game/graphics/opengl_renderer/shaders/sprite_distort.vert
Normal file
26
game/graphics/opengl_renderer/shaders/sprite_distort.vert
Normal 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;
|
||||
}
|
|
@ -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)
|
||||
)
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue