mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
Depth Cue (#1676)
* Initial depth-cue implementation * Oops * Finish merge + fix issues with letterboxing * Fix alpha blending * Add some debug options + profiler stats * More debug options + respect xyoffset GS register * Clean up GOAL code * Disable depth-cue by default * typo * very important typo * depth-cue disable, but better
This commit is contained in:
parent
6e77b1154d
commit
bb323c2ebe
|
@ -359,6 +359,14 @@ std::string GsPrim::print() const {
|
|||
return fmt::format("0x{:x}, kind {}\n", data, kind());
|
||||
}
|
||||
|
||||
std::string GsFrame::print() const {
|
||||
return fmt::format("fbp: {} fbw: {} psm: {} fbmsk: {:x}\n", fbp(), fbw(), psm(), fbmsk());
|
||||
}
|
||||
|
||||
std::string GsXYOffset::print() const {
|
||||
return fmt::format("ofx: {} ofy: {}\n", ofx(), ofy());
|
||||
}
|
||||
|
||||
std::string DrawMode::to_string() const {
|
||||
std::string result;
|
||||
result += fmt::format(" depth-write: {}\n", get_depth_write_enable());
|
||||
|
|
|
@ -341,6 +341,52 @@ struct GsTexa {
|
|||
u64 data = 0;
|
||||
};
|
||||
|
||||
struct GsFrame {
|
||||
enum class PSM {
|
||||
PSMCT32 = 0,
|
||||
PSMCT24 = 1,
|
||||
PSMCT16 = 2,
|
||||
PSMCT16S = 0b1010,
|
||||
PSMT8 = 0b10011,
|
||||
PSMT4 = 0b10100,
|
||||
PSMT8H = 0b011011,
|
||||
PSMT4HL = 0b100100,
|
||||
PSMT4HH = 0b101100,
|
||||
PSMZ32 = 0b110000,
|
||||
PSMZ24 = 0b110001,
|
||||
PSMZ16 = 0b110010,
|
||||
PSMZ16S = 0b111010
|
||||
};
|
||||
|
||||
GsFrame() = default;
|
||||
GsFrame(u64 val) : data(val) {}
|
||||
|
||||
// Frame buffer base pointer (word address / 2048)
|
||||
u32 fbp() const { return (data & 0b1'1111'1111); }
|
||||
// Frame buffer width (pixels / 64)
|
||||
u32 fbw() const { return ((data >> 16) & 0b11'1111); }
|
||||
// Frame buffer pixel storage format
|
||||
PSM psm() const { return (PSM)((data >> 24) & 0b11'1111); }
|
||||
// Frame buffer drawing mask
|
||||
u32 fbmsk() const { return ((data >> 32) & 0xFFFF'FFFF); }
|
||||
|
||||
std::string print() const;
|
||||
|
||||
u64 data = 0;
|
||||
};
|
||||
|
||||
struct GsXYOffset {
|
||||
GsXYOffset() = default;
|
||||
GsXYOffset(u64 val) : data(val) {}
|
||||
|
||||
u32 ofx() const { return data & 0xFFFF; }
|
||||
u32 ofy() const { return (data >> 32) & 0xFFFF; }
|
||||
|
||||
std::string print() const;
|
||||
|
||||
u64 data = 0;
|
||||
};
|
||||
|
||||
// not including the giftag
|
||||
struct AdGifData {
|
||||
u64 tex0_data;
|
||||
|
|
|
@ -138,6 +138,7 @@ set(RUNTIME_SOURCE
|
|||
graphics/opengl_renderer/Sprite3.cpp
|
||||
graphics/opengl_renderer/SpriteRenderer.cpp
|
||||
graphics/opengl_renderer/TextureUploadHandler.cpp
|
||||
graphics/opengl_renderer/DepthCue.cpp
|
||||
graphics/texture/jak1_tpage_dir.cpp
|
||||
graphics/texture/TextureConverter.cpp
|
||||
graphics/texture/TexturePool.cpp
|
||||
|
|
684
game/graphics/opengl_renderer/DepthCue.cpp
Normal file
684
game/graphics/opengl_renderer/DepthCue.cpp
Normal file
|
@ -0,0 +1,684 @@
|
|||
#include "DepthCue.h"
|
||||
|
||||
#include "game/graphics/opengl_renderer/dma_helpers.h"
|
||||
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "third-party/imgui/imgui.h"
|
||||
|
||||
namespace {
|
||||
// Converts fixed point (with 4 bits for decimal) to floating point.
|
||||
float fixed_to_floating_point(int fixed) {
|
||||
return fixed / 16.0f;
|
||||
}
|
||||
|
||||
math::Vector2f fixed_to_floating_point(const math::Vector<s32, 2>& fixed_vec) {
|
||||
return math::Vector2f(fixed_to_floating_point(fixed_vec.x()),
|
||||
fixed_to_floating_point(fixed_vec.y()));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Total number of loops depth-cue performs to draw to the framebuffer
|
||||
constexpr int TOTAL_DRAW_SLICES = 16;
|
||||
|
||||
DepthCue::DepthCue(const std::string& name, BucketId my_id) : BucketRenderer(name, my_id) {
|
||||
opengl_setup();
|
||||
|
||||
m_draw_slices.resize(TOTAL_DRAW_SLICES);
|
||||
}
|
||||
|
||||
void DepthCue::opengl_setup() {
|
||||
// Gen texture for sampling the framebuffer
|
||||
glGenFramebuffers(1, &m_ogl.framebuffer_sample_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.framebuffer_sample_fbo);
|
||||
|
||||
glGenTextures(1, &m_ogl.framebuffer_sample_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, m_ogl.framebuffer_sample_tex);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
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_ogl.framebuffer_sample_tex, 0);
|
||||
|
||||
ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Gen framebuffer for depth-cue-base-page
|
||||
glGenFramebuffers(1, &m_ogl.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.fbo);
|
||||
|
||||
glGenTextures(1, &m_ogl.fbo_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_ogl.fbo_texture);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
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_ogl.fbo_texture, 0);
|
||||
|
||||
ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Gen vertex array for drawing to depth-cue-base-page
|
||||
glGenVertexArrays(1, &m_ogl.depth_cue_page_vao);
|
||||
glBindVertexArray(m_ogl.depth_cue_page_vao);
|
||||
glGenBuffers(1, &m_ogl.depth_cue_page_vertex_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.depth_cue_page_vertex_buffer);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(SpriteVertex), nullptr, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, // location 0 in the shader
|
||||
2, // 2 floats per vert
|
||||
GL_FLOAT, // floats
|
||||
GL_FALSE, // don't normalize, ignored
|
||||
sizeof(SpriteVertex), //
|
||||
(void*)offsetof(SpriteVertex, xy) // offset in array
|
||||
);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, // location 1 in the shader
|
||||
2, // 2 floats per vert
|
||||
GL_FLOAT, // floats
|
||||
GL_FALSE, // don't normalize, ignored
|
||||
sizeof(SpriteVertex), //
|
||||
(void*)offsetof(SpriteVertex, st) // offset in array
|
||||
);
|
||||
|
||||
// Gen vertex array for drawing to on-screen framebuffer
|
||||
glGenVertexArrays(1, &m_ogl.on_screen_vao);
|
||||
glBindVertexArray(m_ogl.on_screen_vao);
|
||||
glGenBuffers(1, &m_ogl.on_screen_vertex_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.on_screen_vertex_buffer);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(SpriteVertex), nullptr, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, // location 0 in the shader
|
||||
2, // 2 floats per vert
|
||||
GL_FLOAT, // floats
|
||||
GL_FALSE, // don't normalize, ignored
|
||||
sizeof(SpriteVertex), //
|
||||
(void*)offsetof(SpriteVertex, xy) // offset in array
|
||||
);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, // location 1 in the shader
|
||||
2, // 2 floats per vert
|
||||
GL_FLOAT, // floats
|
||||
GL_FALSE, // don't normalize, ignored
|
||||
sizeof(SpriteVertex), //
|
||||
(void*)offsetof(SpriteVertex, st) // offset in array
|
||||
);
|
||||
|
||||
// Done
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void DepthCue::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
// First thing should be a NEXT with two nops. this is a jump from buckets to depth-cue
|
||||
auto data0 = dma.read_and_advance();
|
||||
ASSERT(data0.vif1() == 0);
|
||||
ASSERT(data0.vif0() == 0);
|
||||
ASSERT(data0.size_bytes == 0);
|
||||
|
||||
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
|
||||
// depth-cue renderer didn't run, let's just get out of here.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
||||
return;
|
||||
}
|
||||
|
||||
// Read DMA
|
||||
{
|
||||
auto prof_node = prof.make_scoped_child("dma");
|
||||
read_dma(dma, render_state, prof_node);
|
||||
}
|
||||
|
||||
if (!m_enabled) {
|
||||
// Renderer disabled, stop early
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up draw info
|
||||
{
|
||||
auto prof_node = prof.make_scoped_child("setup");
|
||||
setup(render_state, prof_node);
|
||||
}
|
||||
|
||||
// Draw
|
||||
{
|
||||
auto prof_node = prof.make_scoped_child("drawing");
|
||||
draw(render_state, prof_node);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Reads all depth-cue DMA packets.
|
||||
*/
|
||||
void DepthCue::read_dma(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& /*prof*/) {
|
||||
// First should be general GS register setup
|
||||
{
|
||||
auto gs_setup = dma.read_and_advance();
|
||||
ASSERT(gs_setup.size_bytes == sizeof(DepthCueGsSetup));
|
||||
ASSERT(gs_setup.vifcode0().kind == VifCode::Kind::NOP);
|
||||
ASSERT(gs_setup.vifcode1().kind == VifCode::Kind::DIRECT);
|
||||
memcpy(&m_gs_setup, gs_setup.data, sizeof(DepthCueGsSetup));
|
||||
|
||||
ASSERT(m_gs_setup.gif_tag.nreg() == 6);
|
||||
ASSERT(m_gs_setup.gif_tag.reg(0) == GifTag::RegisterDescriptor::AD);
|
||||
|
||||
ASSERT(m_gs_setup.test1.ztest() == GsTest::ZTest::ALWAYS);
|
||||
ASSERT(m_gs_setup.zbuf1.zmsk() == true);
|
||||
ASSERT(m_gs_setup.tex1.mmag() == true);
|
||||
ASSERT(m_gs_setup.tex1.mmin() == 1);
|
||||
ASSERT(m_gs_setup.miptbp1 == 0);
|
||||
ASSERT(m_gs_setup.alpha1.b_mode() == GsAlpha::BlendMode::DEST);
|
||||
ASSERT(m_gs_setup.alpha1.d_mode() == GsAlpha::BlendMode::DEST);
|
||||
}
|
||||
|
||||
// Next is 64 DMAs to draw to the depth-cue-base-page and back to the on-screen framebuffer
|
||||
// We'll group these by each slice of the framebuffer being drawn to
|
||||
for (int i = 0; i < TOTAL_DRAW_SLICES; i++) {
|
||||
// Each 'slice' should be:
|
||||
// 1. GS setup for drawing from on-screen framebuffer to depth-cue-base-page
|
||||
// 2. Draw to depth-cue-base-page
|
||||
// 3. GS setup for drawing from depth-cue-base-page back to on-screen framebuffer
|
||||
// 4. Draw to on-screen framebuffer
|
||||
DrawSlice& slice = m_draw_slices.at(i);
|
||||
|
||||
// depth-cue-base-page setup
|
||||
{
|
||||
auto depth_cue_page_setup = dma.read_and_advance();
|
||||
ASSERT(depth_cue_page_setup.size_bytes == sizeof(DepthCuePageGsSetup));
|
||||
ASSERT(depth_cue_page_setup.vifcode0().kind == VifCode::Kind::NOP);
|
||||
ASSERT(depth_cue_page_setup.vifcode1().kind == VifCode::Kind::DIRECT);
|
||||
memcpy(&slice.depth_cue_page_setup, depth_cue_page_setup.data, sizeof(DepthCuePageGsSetup));
|
||||
|
||||
ASSERT(slice.depth_cue_page_setup.gif_tag.nreg() == 5);
|
||||
ASSERT(slice.depth_cue_page_setup.gif_tag.reg(0) == GifTag::RegisterDescriptor::AD);
|
||||
|
||||
ASSERT(slice.depth_cue_page_setup.tex01.tcc() == 1);
|
||||
ASSERT(slice.depth_cue_page_setup.test1.ztest() == GsTest::ZTest::ALWAYS);
|
||||
ASSERT(slice.depth_cue_page_setup.alpha1.b_mode() == GsAlpha::BlendMode::SOURCE);
|
||||
ASSERT(slice.depth_cue_page_setup.alpha1.d_mode() == GsAlpha::BlendMode::SOURCE);
|
||||
}
|
||||
|
||||
// depth-cue-base-page draw
|
||||
{
|
||||
auto depth_cue_page_draw = dma.read_and_advance();
|
||||
ASSERT(depth_cue_page_draw.size_bytes == sizeof(DepthCuePageDraw));
|
||||
ASSERT(depth_cue_page_draw.vifcode0().kind == VifCode::Kind::NOP);
|
||||
ASSERT(depth_cue_page_draw.vifcode1().kind == VifCode::Kind::DIRECT);
|
||||
memcpy(&slice.depth_cue_page_draw, depth_cue_page_draw.data, sizeof(DepthCuePageDraw));
|
||||
|
||||
ASSERT(slice.depth_cue_page_draw.gif_tag.nloop() == 1);
|
||||
ASSERT(slice.depth_cue_page_draw.gif_tag.pre() == true);
|
||||
ASSERT(slice.depth_cue_page_draw.gif_tag.prim() == 6);
|
||||
ASSERT(slice.depth_cue_page_draw.gif_tag.flg() == GifTag::Format::PACKED);
|
||||
ASSERT(slice.depth_cue_page_draw.gif_tag.nreg() == 5);
|
||||
ASSERT(slice.depth_cue_page_draw.gif_tag.reg(0) == GifTag::RegisterDescriptor::RGBAQ);
|
||||
}
|
||||
|
||||
// on-screen setup
|
||||
{
|
||||
auto on_screen_setup = dma.read_and_advance();
|
||||
ASSERT(on_screen_setup.size_bytes == sizeof(OnScreenGsSetup));
|
||||
ASSERT(on_screen_setup.vifcode0().kind == VifCode::Kind::NOP);
|
||||
ASSERT(on_screen_setup.vifcode1().kind == VifCode::Kind::DIRECT);
|
||||
memcpy(&slice.on_screen_setup, on_screen_setup.data, sizeof(OnScreenGsSetup));
|
||||
|
||||
ASSERT(slice.on_screen_setup.gif_tag.nreg() == 5);
|
||||
ASSERT(slice.on_screen_setup.gif_tag.reg(0) == GifTag::RegisterDescriptor::AD);
|
||||
|
||||
ASSERT(slice.on_screen_setup.tex01.tcc() == 0);
|
||||
ASSERT(slice.on_screen_setup.texa.ta0() == 0x80);
|
||||
ASSERT(slice.on_screen_setup.texa.ta1() == 0x80);
|
||||
ASSERT(slice.on_screen_setup.alpha1.b_mode() == GsAlpha::BlendMode::DEST);
|
||||
ASSERT(slice.on_screen_setup.alpha1.d_mode() == GsAlpha::BlendMode::DEST);
|
||||
}
|
||||
|
||||
// on-screen draw
|
||||
{
|
||||
auto on_screen_draw = dma.read_and_advance();
|
||||
ASSERT(on_screen_draw.size_bytes == sizeof(OnScreenDraw));
|
||||
ASSERT(on_screen_draw.vifcode0().kind == VifCode::Kind::NOP);
|
||||
ASSERT(on_screen_draw.vifcode1().kind == VifCode::Kind::DIRECT);
|
||||
memcpy(&slice.on_screen_draw, on_screen_draw.data, sizeof(OnScreenDraw));
|
||||
|
||||
ASSERT(slice.on_screen_draw.gif_tag.nloop() == 1);
|
||||
ASSERT(slice.on_screen_draw.gif_tag.pre() == true);
|
||||
ASSERT(slice.on_screen_draw.gif_tag.prim() == 6);
|
||||
ASSERT(slice.on_screen_draw.gif_tag.flg() == GifTag::Format::PACKED);
|
||||
ASSERT(slice.on_screen_draw.gif_tag.nreg() == 5);
|
||||
ASSERT(slice.on_screen_draw.gif_tag.reg(0) == GifTag::RegisterDescriptor::RGBAQ);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, a packet to restore GS state
|
||||
{
|
||||
auto gs_restore = dma.read_and_advance();
|
||||
ASSERT(gs_restore.size_bytes == sizeof(DepthCueGsRestore));
|
||||
ASSERT(gs_restore.vifcode0().kind == VifCode::Kind::NOP);
|
||||
ASSERT(gs_restore.vifcode1().kind == VifCode::Kind::DIRECT);
|
||||
memcpy(&m_gs_restore, gs_restore.data, sizeof(DepthCueGsRestore));
|
||||
|
||||
ASSERT(m_gs_restore.gif_tag.nreg() == 2);
|
||||
ASSERT(m_gs_restore.gif_tag.reg(0) == GifTag::RegisterDescriptor::AD);
|
||||
}
|
||||
|
||||
// End with 'NEXT'
|
||||
{
|
||||
ASSERT(dma.current_tag().kind == DmaTag::Kind::NEXT);
|
||||
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DepthCue::setup(SharedRenderState* render_state, ScopedProfilerNode& /*prof*/) {
|
||||
if (m_debug.cache_setup && (m_ogl.last_draw_region_w == render_state->draw_region_w &&
|
||||
m_ogl.last_draw_region_h == render_state->draw_region_h &&
|
||||
// Also recompute when certain debug settings change
|
||||
m_ogl.last_override_sharpness == m_debug.override_sharpness &&
|
||||
m_ogl.last_custom_sharpness == m_debug.sharpness &&
|
||||
m_ogl.last_force_original_res == m_debug.force_original_res &&
|
||||
m_ogl.last_res_scale == m_debug.res_scale)) {
|
||||
// Draw region didn't change, everything is already set up
|
||||
return;
|
||||
}
|
||||
|
||||
m_ogl.last_draw_region_w = render_state->draw_region_w;
|
||||
m_ogl.last_draw_region_h = render_state->draw_region_h;
|
||||
m_ogl.last_override_sharpness = m_debug.override_sharpness;
|
||||
m_ogl.last_custom_sharpness = m_debug.sharpness;
|
||||
m_ogl.last_force_original_res = m_debug.force_original_res;
|
||||
m_ogl.last_res_scale = m_debug.res_scale;
|
||||
|
||||
// ASSUMPTIONS
|
||||
// --------------------------
|
||||
// Assert some assumptions that most of the data for each depth-cue draw is the same.
|
||||
// The way the game wants to render this effect is very inefficient in OpenGL, we can use these
|
||||
// assumptions to only alter state once, do setup once, and group multiple draw calls.
|
||||
const DrawSlice& first_slice = m_draw_slices[0];
|
||||
|
||||
// 1. Assume each draw slice has the exact same width of 32
|
||||
// We'll compare each slice to the first as we go
|
||||
float slice_width = fixed_to_floating_point(first_slice.on_screen_draw.xyzf2_2.x() -
|
||||
first_slice.on_screen_draw.xyzf2_1.x());
|
||||
// NOTE: Y-coords will range between [0,1/2 output res], usually 224 but not always.
|
||||
// We'll capture it here so we can convert to coords to [0,1] ranges later.
|
||||
float slice_height = fixed_to_floating_point(first_slice.on_screen_draw.xyzf2_2.y());
|
||||
|
||||
ASSERT(slice_width == 32.0f);
|
||||
ASSERT(first_slice.on_screen_draw.xyzf2_1.y() == 0);
|
||||
|
||||
// 2. Assume that the framebuffer is sampled as a 1024x256 texel view and that the game thinks the
|
||||
// framebuffer is 512 pixels wide.
|
||||
int fb_sample_width = (int)pow(2, first_slice.depth_cue_page_setup.tex01.tw());
|
||||
int fb_sample_height = (int)pow(2, first_slice.depth_cue_page_setup.tex01.th());
|
||||
int fb_width = first_slice.depth_cue_page_setup.tex01.tbw() * 64;
|
||||
|
||||
ASSERT(fb_sample_width == 1024);
|
||||
ASSERT(fb_sample_height == 256);
|
||||
ASSERT(fb_width == 512);
|
||||
ASSERT(fb_width * 2 == fb_sample_width);
|
||||
|
||||
// 3. Finally, assert that all slices match the above assumptions
|
||||
for (const DrawSlice& slice : m_draw_slices) {
|
||||
float _slice_width = fixed_to_floating_point(slice.on_screen_draw.xyzf2_2.x() -
|
||||
slice.on_screen_draw.xyzf2_1.x());
|
||||
float _slice_height = fixed_to_floating_point(slice.on_screen_draw.xyzf2_2.y());
|
||||
|
||||
ASSERT(slice_width == _slice_width);
|
||||
ASSERT(slice_height == _slice_height);
|
||||
ASSERT(slice.on_screen_draw.xyzf2_1.y() == 0);
|
||||
|
||||
int _fb_sample_width = (int)pow(2, slice.depth_cue_page_setup.tex01.tw());
|
||||
int _fb_sample_height = (int)pow(2, slice.depth_cue_page_setup.tex01.th());
|
||||
int _fb_width = slice.depth_cue_page_setup.tex01.tbw() * 64;
|
||||
|
||||
ASSERT(fb_sample_width == _fb_sample_width);
|
||||
ASSERT(fb_sample_height == _fb_sample_height);
|
||||
ASSERT(fb_width == _fb_width);
|
||||
}
|
||||
|
||||
// FRAMEBUFFER SAMPLE TEXTURE
|
||||
// --------------------------
|
||||
// We need a copy of the framebuffer to sample from. If the framebuffer wasn't using
|
||||
// multisampling, this wouldn't be necessary and the framebuffer could just be bound. Instead,
|
||||
// we'll just blit to a new texture.
|
||||
//
|
||||
// The original game code would have created this as a view into the framebuffer whose width is 2x
|
||||
// as large, however this isn't necessary for the effect to work.
|
||||
int pc_fb_sample_width = render_state->draw_region_w;
|
||||
int pc_fb_sample_height = render_state->draw_region_h;
|
||||
|
||||
m_ogl.framebuffer_sample_width = pc_fb_sample_width;
|
||||
m_ogl.framebuffer_sample_height = pc_fb_sample_height;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_ogl.framebuffer_sample_tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pc_fb_sample_width, pc_fb_sample_height, 0, GL_RGB,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// DEPTH CUE BASE PAGE FRAMEBUFFER
|
||||
// --------------------------
|
||||
// Next, we need a framebuffer to draw slices of the sample texture to. The depth-cue effect
|
||||
// usually does this in 16 vertical slices that are 32 pixels wide each. The destination
|
||||
// drawn to is smaller than the source by a very small amount (defined by sharpness in the
|
||||
// GOAL code), which kicks in the bilinear filtering effect. Normally, a 32x224 texture will
|
||||
// be reused for each slice but for the sake of efficient rendering, we'll create a framebuffer
|
||||
// that can store all 16 slices side-by-side and draw all slices to it all at once.
|
||||
int pc_depth_cue_fb_width = render_state->draw_region_w;
|
||||
int pc_depth_cue_fb_height = render_state->draw_region_h;
|
||||
|
||||
if (m_debug.force_original_res) {
|
||||
pc_depth_cue_fb_width = 512;
|
||||
}
|
||||
|
||||
pc_depth_cue_fb_width *= m_debug.res_scale;
|
||||
|
||||
m_ogl.fbo_width = pc_depth_cue_fb_width;
|
||||
m_ogl.fbo_height = pc_depth_cue_fb_height;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_ogl.fbo_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pc_depth_cue_fb_width, pc_depth_cue_fb_height, 0, GL_RGB,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// DEPTH CUE BASE PAGE VERTEX DATA
|
||||
// --------------------------
|
||||
// Now that we have a framebuffer to draw each slice to, we need the actual vertex data.
|
||||
// We'll take the exact data DMA'd and scale it up the PC dimensions.
|
||||
std::vector<SpriteVertex> depth_cue_page_vertices;
|
||||
|
||||
// U-coordinates here will range from [0,512], but the maximum U value in the original is
|
||||
// 1024 since the sample texel width is usually 1024. Since we're not using a texture with
|
||||
// 2x the width, the maximum U value used to convert UVs to [0,1] should be 512.
|
||||
float max_u = fb_sample_width / 2.0f;
|
||||
ASSERT(max_u == 512.0f);
|
||||
|
||||
for (const auto& slice : m_draw_slices) {
|
||||
math::Vector2f xyoffset = fixed_to_floating_point(
|
||||
math::Vector2<s32>((s32)slice.depth_cue_page_setup.xyoffset1.ofx(),
|
||||
(s32)slice.depth_cue_page_setup.xyoffset1.ofy()));
|
||||
|
||||
math::Vector2f xy1 = fixed_to_floating_point(slice.depth_cue_page_draw.xyzf2_1.xy());
|
||||
math::Vector2f xy2 = fixed_to_floating_point(slice.depth_cue_page_draw.xyzf2_2.xy());
|
||||
math::Vector2f uv1 = fixed_to_floating_point(slice.depth_cue_page_draw.uv_1.xy());
|
||||
math::Vector2f uv2 = fixed_to_floating_point(slice.depth_cue_page_draw.uv_2.xy());
|
||||
|
||||
ASSERT(xy1.x() == 0);
|
||||
ASSERT(xy1.y() == 0);
|
||||
ASSERT(xy2.x() <= 32.0f);
|
||||
ASSERT(xy2.y() <= slice_height);
|
||||
|
||||
if (m_debug.override_sharpness) {
|
||||
// Undo sharpness from GOAL code and apply custom
|
||||
xy2.x() = 32.0f * m_debug.sharpness;
|
||||
xy2.y() = 224.0f * m_debug.sharpness;
|
||||
}
|
||||
|
||||
// Apply xyoffset GS register
|
||||
xy1.x() += xyoffset.x() / 4096.0f;
|
||||
xy1.y() += xyoffset.y() / 4096.0f;
|
||||
xy2.x() += xyoffset.x() / 4096.0f;
|
||||
xy2.y() += xyoffset.y() / 4096.0f;
|
||||
|
||||
// U-coord will range from [0,512], which is half of the original framebuffer sample width
|
||||
// Let's also use it to determine the X offset into the depth-cue framebuffer since the
|
||||
// original draw assumes each slice is at 0,0.
|
||||
float x_offset = (uv1.x() / 512.0f) * (xy2.x() / 32.0f);
|
||||
|
||||
build_sprite(depth_cue_page_vertices,
|
||||
// Top-left
|
||||
(xy1.x() / 512.0f) + x_offset, // x1
|
||||
xy1.y() / slice_height, // y1
|
||||
uv1.x() / max_u, // s1
|
||||
uv1.y() / slice_height, // t1
|
||||
// Bottom-right
|
||||
(xy2.x() / 512.0f) + x_offset, // x2
|
||||
xy2.y() / slice_height, // y2
|
||||
uv2.x() / max_u, // s2
|
||||
uv2.y() / slice_height // t2
|
||||
);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.depth_cue_page_vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, depth_cue_page_vertices.size() * sizeof(SpriteVertex),
|
||||
depth_cue_page_vertices.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// ON SCREEN VERTEX DATA
|
||||
// --------------------------
|
||||
// Finally, we need to draw pixels from the depth-cue-base-page back to the on-screen
|
||||
// framebuffer. We'll take the same approach as above.
|
||||
std::vector<SpriteVertex> on_screen_vertices;
|
||||
|
||||
for (const auto& slice : m_draw_slices) {
|
||||
math::Vector2f xyoffset = fixed_to_floating_point(math::Vector2<s32>(
|
||||
(s32)slice.on_screen_setup.xyoffset1.ofx(), (s32)slice.on_screen_setup.xyoffset1.ofy()));
|
||||
|
||||
math::Vector2f xy1 = fixed_to_floating_point(slice.on_screen_draw.xyzf2_1.xy());
|
||||
math::Vector2f xy2 = fixed_to_floating_point(slice.on_screen_draw.xyzf2_2.xy());
|
||||
math::Vector2f uv1 = fixed_to_floating_point(slice.on_screen_draw.uv_1.xy());
|
||||
math::Vector2f uv2 = fixed_to_floating_point(slice.on_screen_draw.uv_2.xy());
|
||||
|
||||
ASSERT(uv1.x() == 0);
|
||||
ASSERT(uv1.y() == 0);
|
||||
ASSERT(uv2.x() <= 32.0f);
|
||||
ASSERT(uv2.y() <= slice_height);
|
||||
|
||||
if (m_debug.override_sharpness) {
|
||||
// Undo sharpness from GOAL code and apply custom
|
||||
uv2.x() = 32.0f * m_debug.sharpness;
|
||||
uv2.y() = 224.0f * m_debug.sharpness;
|
||||
}
|
||||
|
||||
// Apply xyoffset GS register
|
||||
xy1.x() += xyoffset.x() / 4096.0f;
|
||||
xy1.y() += xyoffset.y() / 4096.0f;
|
||||
xy2.x() += xyoffset.x() / 4096.0f;
|
||||
xy2.y() += xyoffset.y() / 4096.0f;
|
||||
|
||||
// X-coord will range from [0,512], which is half of the original framebuffer sample width
|
||||
// Let's also use it to determine the U offset into the on-screen framebuffer since the
|
||||
// original draw assumes each slice is at 0,0.
|
||||
float u_offset = (xy1.x() / 512.0f) * (uv2.x() / 32.0f);
|
||||
|
||||
build_sprite(on_screen_vertices,
|
||||
// Top-left
|
||||
xy1.x() / 512.0f, // x1
|
||||
xy1.y() / slice_height, // y1
|
||||
(uv1.x() / 512.0f) + u_offset, // s1
|
||||
uv1.y() / slice_height, // t1
|
||||
// Bottom-right
|
||||
xy2.x() / 512.0f, // x2
|
||||
xy2.y() / slice_height, // y2
|
||||
(uv2.x() / 512.0f) + u_offset, // s2
|
||||
uv2.y() / slice_height // t2
|
||||
);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.on_screen_vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, on_screen_vertices.size() * sizeof(SpriteVertex),
|
||||
on_screen_vertices.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void DepthCue::draw(SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
// Disable depth writing but keep test
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
// Activate shader
|
||||
auto shader = &render_state->shaders[ShaderId::DEPTH_CUE];
|
||||
shader->activate();
|
||||
|
||||
glUniform1i(glGetUniformLocation(shader->id(), "tex"), 0);
|
||||
|
||||
// First, we need to copy the framebuffer into the framebuffer sample texture
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, render_state->render_fb);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_ogl.framebuffer_sample_fbo);
|
||||
|
||||
glBlitFramebuffer(render_state->draw_offset_x, // srcX0
|
||||
render_state->draw_offset_y, // srcY0
|
||||
render_state->draw_offset_x + render_state->draw_region_w, // srcX1
|
||||
render_state->draw_offset_y + render_state->draw_region_h, // srcY1
|
||||
0, // dstX0
|
||||
0, // dstY0
|
||||
m_ogl.framebuffer_sample_width, // dstX1
|
||||
m_ogl.framebuffer_sample_height, // dstY1
|
||||
GL_COLOR_BUFFER_BIT, // mask
|
||||
GL_NEAREST // filter
|
||||
);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
|
||||
|
||||
// Next, we need to draw from the framebuffer sample texture to the depth-cue-base-page
|
||||
// framebuffer
|
||||
{
|
||||
const auto& depth_cue_page_draw = m_draw_slices[0].depth_cue_page_draw;
|
||||
|
||||
math::Vector4f colorf = math::Vector4f(
|
||||
depth_cue_page_draw.rgbaq.x() / 255.0f, depth_cue_page_draw.rgbaq.y() / 255.0f,
|
||||
depth_cue_page_draw.rgbaq.z() / 255.0f, depth_cue_page_draw.rgbaq.w() / 255.0f);
|
||||
glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data());
|
||||
|
||||
glUniform1f(glGetUniformLocation(shader->id(), "u_depth"), 1.0f);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.fbo);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, m_ogl.framebuffer_sample_tex);
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
glViewport(0, 0, m_ogl.fbo_width, m_ogl.fbo_height);
|
||||
|
||||
prof.add_draw_call();
|
||||
prof.add_tri(2 * TOTAL_DRAW_SLICES);
|
||||
|
||||
glBindVertexArray(m_ogl.depth_cue_page_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6 * TOTAL_DRAW_SLICES); // 6 verts per slice
|
||||
}
|
||||
|
||||
// Finally, the contents of depth-cue-base-page need to be overlayed onto the on-screen
|
||||
// framebuffer
|
||||
{
|
||||
const auto& on_screen_draw = m_draw_slices[0].on_screen_draw;
|
||||
|
||||
math::Vector4f colorf =
|
||||
math::Vector4f(on_screen_draw.rgbaq.x() / 255.0f, on_screen_draw.rgbaq.y() / 255.0f,
|
||||
on_screen_draw.rgbaq.z() / 255.0f, on_screen_draw.rgbaq.w() / 255.0f);
|
||||
if (m_debug.override_alpha) {
|
||||
colorf.w() = m_debug.draw_alpha / 2.0f;
|
||||
}
|
||||
glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data());
|
||||
|
||||
if (m_debug.depth == 1.0f) {
|
||||
glUniform1f(glGetUniformLocation(shader->id(), "u_depth"), m_debug.depth);
|
||||
} else {
|
||||
// Scale debug depth expontentially to make the slider easier to use
|
||||
glUniform1f(glGetUniformLocation(shader->id(), "u_depth"), pow(m_debug.depth, 8));
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, m_ogl.fbo_texture);
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
|
||||
|
||||
glViewport(render_state->draw_offset_x, render_state->draw_offset_y,
|
||||
render_state->draw_region_w, render_state->draw_region_h);
|
||||
|
||||
prof.add_draw_call();
|
||||
prof.add_tri(2 * TOTAL_DRAW_SLICES);
|
||||
|
||||
glBindVertexArray(m_ogl.on_screen_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6 * TOTAL_DRAW_SLICES); // 6 verts per slice
|
||||
}
|
||||
|
||||
// Done
|
||||
glDepthMask(GL_TRUE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void DepthCue::build_sprite(std::vector<SpriteVertex>& vertices,
|
||||
float x1,
|
||||
float y1,
|
||||
float s1,
|
||||
float t1,
|
||||
float x2,
|
||||
float y2,
|
||||
float s2,
|
||||
float t2) {
|
||||
// First triangle
|
||||
// -------------
|
||||
// Top-left
|
||||
vertices.push_back(SpriteVertex(x1, y1, s1, t1));
|
||||
|
||||
// Top-right
|
||||
vertices.push_back(SpriteVertex(x2, y1, s2, t1));
|
||||
|
||||
// Bottom-left
|
||||
vertices.push_back(SpriteVertex(x1, y2, s1, t2));
|
||||
|
||||
// Second triangle
|
||||
// -------------
|
||||
// Top-right
|
||||
vertices.push_back(SpriteVertex(x2, y1, s2, t1));
|
||||
|
||||
// Bottom-left
|
||||
vertices.push_back(SpriteVertex(x1, y2, s1, t2));
|
||||
|
||||
// Bottom-right
|
||||
vertices.push_back(SpriteVertex(x2, y2, s2, t2));
|
||||
}
|
||||
|
||||
void DepthCue::draw_debug_window() {
|
||||
ImGui::Text("NOTE: depth-cue may be disabled by '*vu1-enable-user-menu*'!");
|
||||
|
||||
ImGui::Checkbox("Cache setup", &m_debug.cache_setup);
|
||||
ImGui::Checkbox("Force original resolution", &m_debug.force_original_res);
|
||||
|
||||
ImGui::Checkbox("Override alpha", &m_debug.override_alpha);
|
||||
if (m_debug.override_alpha) {
|
||||
ImGui::SliderFloat("Alpha", &m_debug.draw_alpha, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Override sharpness", &m_debug.override_sharpness);
|
||||
if (m_debug.override_sharpness) {
|
||||
ImGui::SliderFloat("Sharpness", &m_debug.sharpness, 0.001f, 1.0f);
|
||||
}
|
||||
|
||||
ImGui::SliderFloat("Depth", &m_debug.depth, 0.0f, 1.0f);
|
||||
ImGui::SliderFloat("Resolution scale", &m_debug.res_scale, 0.001f, 2.0f);
|
||||
|
||||
if (ImGui::Button("Reset")) {
|
||||
m_debug.draw_alpha = 0.4f;
|
||||
m_debug.sharpness = 0.999f;
|
||||
m_debug.depth = 1.0f;
|
||||
m_debug.res_scale = 1.0f;
|
||||
}
|
||||
}
|
183
game/graphics/opengl_renderer/DepthCue.h
Normal file
183
game/graphics/opengl_renderer/DepthCue.h
Normal file
|
@ -0,0 +1,183 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/dma/gs.h"
|
||||
#include "common/math/Vector.h"
|
||||
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
|
||||
class DepthCue : public BucketRenderer {
|
||||
public:
|
||||
DepthCue(const std::string& name, BucketId my_id);
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
|
||||
private:
|
||||
// One-time initial GS setup per frame
|
||||
struct DepthCueGsSetup {
|
||||
GifTag gif_tag;
|
||||
GsTest test1;
|
||||
u64 test1_addr;
|
||||
GsZbuf zbuf1;
|
||||
u64 zbuf1_addr;
|
||||
GsTex1 tex1;
|
||||
u64 tex1_addr;
|
||||
u64 miptbp1;
|
||||
u64 miptbp1_addr;
|
||||
u64 clamp1;
|
||||
u64 clamp1_addr;
|
||||
GsAlpha alpha1;
|
||||
u64 alpha1_addr;
|
||||
};
|
||||
static_assert(sizeof(DepthCueGsSetup) == (7 * 16));
|
||||
|
||||
// One-time GS state restoration at the end of each depth-cue frame
|
||||
struct DepthCueGsRestore {
|
||||
GifTag gif_tag;
|
||||
u64 xyoffset1;
|
||||
u64 xyoffset1_addr;
|
||||
GsFrame frame1;
|
||||
u64 frame1_addr;
|
||||
};
|
||||
static_assert(sizeof(DepthCueGsRestore) == (3 * 16));
|
||||
|
||||
// GS setup for drawing to the depth-cue-base-page framebuffer
|
||||
struct DepthCuePageGsSetup {
|
||||
GifTag gif_tag;
|
||||
GsXYOffset xyoffset1;
|
||||
u64 xyoffset1_addr;
|
||||
GsFrame frame1;
|
||||
u64 frame1_addr;
|
||||
GsTex0 tex01;
|
||||
u64 tex01_addr;
|
||||
GsTest test1;
|
||||
u64 test1_addr;
|
||||
GsAlpha alpha1;
|
||||
u64 alpha1_addr;
|
||||
};
|
||||
static_assert(sizeof(DepthCuePageGsSetup) == (6 * 16));
|
||||
|
||||
// GS setup for drawing to the on-screen framebuffer
|
||||
struct OnScreenGsSetup {
|
||||
GifTag gif_tag;
|
||||
GsXYOffset xyoffset1;
|
||||
u64 xyoffset1_addr;
|
||||
GsFrame frame1;
|
||||
u64 frame1_addr;
|
||||
GsTexa texa;
|
||||
u64 texa_addr;
|
||||
GsTex0 tex01;
|
||||
u64 tex01_addr;
|
||||
GsAlpha alpha1;
|
||||
u64 alpha1_addr;
|
||||
};
|
||||
static_assert(sizeof(OnScreenGsSetup) == (6 * 16));
|
||||
|
||||
// Sprite draw command to the depth-cue-base-page framebuffer
|
||||
struct DepthCuePageDraw {
|
||||
GifTag gif_tag;
|
||||
math::Vector4<s32> rgbaq;
|
||||
math::Vector4<s32> uv_1;
|
||||
math::Vector4<s32> xyzf2_1;
|
||||
math::Vector4<s32> uv_2;
|
||||
math::Vector4<s32> xyzf2_2;
|
||||
};
|
||||
static_assert(sizeof(DepthCuePageDraw) == (6 * 16));
|
||||
|
||||
// Sprite draw command to the on-screen framebuffer
|
||||
struct OnScreenDraw {
|
||||
GifTag gif_tag;
|
||||
math::Vector4<s32> rgbaq;
|
||||
math::Vector4<s32> uv_1;
|
||||
math::Vector4<s32> xyzf2_1;
|
||||
math::Vector4<s32> uv_2;
|
||||
math::Vector4<s32> xyzf2_2;
|
||||
};
|
||||
static_assert(sizeof(OnScreenDraw) == (6 * 16));
|
||||
|
||||
// A draw to the depth-cue-base-page and then back to the on-screen framebuffer.
|
||||
//
|
||||
// This is done 16 times per frame across the entire on-screen framebuffer in vertical strips.
|
||||
struct DrawSlice {
|
||||
DepthCuePageGsSetup depth_cue_page_setup;
|
||||
DepthCuePageDraw depth_cue_page_draw;
|
||||
OnScreenGsSetup on_screen_setup;
|
||||
OnScreenDraw on_screen_draw;
|
||||
};
|
||||
|
||||
struct SpriteVertex {
|
||||
math::Vector2f xy;
|
||||
math::Vector2f st;
|
||||
|
||||
SpriteVertex() = default;
|
||||
SpriteVertex(float x, float y, float s, float t) : xy(x, y), st(s, t) {}
|
||||
};
|
||||
|
||||
DepthCueGsSetup m_gs_setup;
|
||||
DepthCueGsRestore m_gs_restore;
|
||||
std::vector<DrawSlice> m_draw_slices;
|
||||
|
||||
struct {
|
||||
// Framebuffer for depth-cue-base-page
|
||||
GLuint fbo;
|
||||
GLuint fbo_texture;
|
||||
int fbo_width = 0;
|
||||
int fbo_height = 0;
|
||||
|
||||
// Vertex data for drawing to depth-cue-base-page
|
||||
GLuint depth_cue_page_vao;
|
||||
GLuint depth_cue_page_vertex_buffer;
|
||||
|
||||
// Vertex data for drawing to on-screen framebuffer
|
||||
GLuint on_screen_vao;
|
||||
GLuint on_screen_vertex_buffer;
|
||||
|
||||
// Texture to sample the framebuffer from
|
||||
GLuint framebuffer_sample_fbo;
|
||||
GLuint framebuffer_sample_tex;
|
||||
int framebuffer_sample_width = 0;
|
||||
int framebuffer_sample_height = 0;
|
||||
|
||||
int last_draw_region_w = -1;
|
||||
int last_draw_region_h = -1;
|
||||
bool last_override_sharpness = false;
|
||||
float last_custom_sharpness = 0.999f;
|
||||
bool last_force_original_res = false;
|
||||
float last_res_scale = 1.0f;
|
||||
} m_ogl;
|
||||
|
||||
struct {
|
||||
// false = recompute setup each frame
|
||||
// true = only recompute setup when draw dimensions change
|
||||
bool cache_setup = true;
|
||||
// true = render depth-cue at original 512px wide resolution
|
||||
bool force_original_res = false;
|
||||
// true = render with m_draw_alpha alpha
|
||||
bool override_alpha = false;
|
||||
// 0.4 = default in GOAL
|
||||
float draw_alpha = 0.4f;
|
||||
// true = render with m_sharpness sharpness
|
||||
bool override_sharpness = false;
|
||||
// 1.0 = pixel perfect, depth-cue has no effect
|
||||
// 0.999 = default in GOAL
|
||||
float sharpness = 0.999f;
|
||||
// lower to have effect only apply to further away pixels
|
||||
// 1.0 = default (apply to all)
|
||||
float depth = 1.0f;
|
||||
// depth-cue resolution multiplier
|
||||
float res_scale = 1.0f;
|
||||
} m_debug;
|
||||
|
||||
void opengl_setup();
|
||||
void read_dma(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
void setup(SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
void draw(SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
void build_sprite(std::vector<SpriteVertex>& vertices,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float s1,
|
||||
float t1,
|
||||
float s2,
|
||||
float t2);
|
||||
};
|
|
@ -3,6 +3,7 @@
|
|||
#include "common/log/log.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
#include "game/graphics/opengl_renderer/DepthCue.h"
|
||||
#include "game/graphics/opengl_renderer/DirectRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/EyeRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/ShadowRenderer.h"
|
||||
|
@ -256,7 +257,11 @@ void OpenGLRenderer::init_bucket_renderers() {
|
|||
BucketId::GENERIC_WATER_LEVEL1); // 62
|
||||
|
||||
init_bucket_renderer<OceanNear>("ocean-near", BucketCategory::OCEAN, BucketId::OCEAN_NEAR); // 63
|
||||
// 64?
|
||||
|
||||
//-----------------------
|
||||
// DEPTH CUE
|
||||
//-----------------------
|
||||
init_bucket_renderer<DepthCue>("depth-cue", BucketCategory::OTHER, BucketId::DEPTH_CUE); // 64
|
||||
|
||||
//-----------------------
|
||||
// COMMON texture
|
||||
|
|
|
@ -90,6 +90,7 @@ ShaderLibrary::ShaderLibrary() {
|
|||
at(ShaderId::SPRITE_DISTORT) = {"sprite_distort"};
|
||||
at(ShaderId::SPRITE_DISTORT_INSTANCED) = {"sprite_distort_instanced"};
|
||||
at(ShaderId::POST_PROCESSING) = {"post_processing"};
|
||||
at(ShaderId::DEPTH_CUE) = {"depth_cue"};
|
||||
|
||||
for (auto& shader : m_shaders) {
|
||||
ASSERT_MSG(shader.okay(), "Shader compiled");
|
||||
|
|
|
@ -45,6 +45,7 @@ enum class ShaderId {
|
|||
SPRITE_DISTORT = 20,
|
||||
SPRITE_DISTORT_INSTANCED = 21,
|
||||
POST_PROCESSING = 22,
|
||||
DEPTH_CUE = 23,
|
||||
MAX_SHADERS
|
||||
};
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ enum class BucketId {
|
|||
MERC_WATER_LEVEL1 = 61,
|
||||
GENERIC_WATER_LEVEL1 = 62,
|
||||
OCEAN_NEAR = 63,
|
||||
// 64
|
||||
DEPTH_CUE = 64,
|
||||
PRE_SPRITE_TEX = 65, // maybe it's just common textures?
|
||||
SPRITE = 66,
|
||||
DEBUG = 67,
|
||||
|
|
13
game/graphics/opengl_renderer/shaders/depth_cue.frag
Normal file
13
game/graphics/opengl_renderer/shaders/depth_cue.frag
Normal file
|
@ -0,0 +1,13 @@
|
|||
#version 430 core
|
||||
|
||||
in flat vec4 fragment_color;
|
||||
in vec2 tex_coord;
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
void main() {
|
||||
// sample texture
|
||||
out_color = fragment_color * texture(tex, tex_coord);
|
||||
}
|
27
game/graphics/opengl_renderer/shaders/depth_cue.vert
Normal file
27
game/graphics/opengl_renderer/shaders/depth_cue.vert
Normal file
|
@ -0,0 +1,27 @@
|
|||
#version 430 core
|
||||
|
||||
layout (location = 0) in vec2 xy;
|
||||
layout (location = 1) in vec2 st;
|
||||
|
||||
uniform vec4 u_color;
|
||||
uniform float u_depth;
|
||||
|
||||
out flat vec4 fragment_color;
|
||||
out vec2 tex_coord;
|
||||
|
||||
void main() {
|
||||
// Calculate color
|
||||
vec4 color = u_color;
|
||||
color *= 2; // correct
|
||||
|
||||
fragment_color = color;
|
||||
|
||||
// Pass on texture coord
|
||||
tex_coord = st;
|
||||
|
||||
// Calculate vertex position
|
||||
vec4 position = vec4(xy.x, xy.y, u_depth, 1.0);
|
||||
position.xyz = (position.xyz * 2) - 1.0; // convert from [0,1] to clip-space
|
||||
|
||||
gl_Position = position;
|
||||
}
|
|
@ -714,6 +714,10 @@
|
|||
)
|
||||
|
||||
;; depth cue
|
||||
(if (not *progress-process*)
|
||||
(depth-cue disp)
|
||||
)
|
||||
|
||||
;; screen filter
|
||||
|
||||
(with-profiler "post-sync-draw"
|
||||
|
|
|
@ -14,14 +14,42 @@
|
|||
:dma (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt))
|
||||
:vif1 (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1)
|
||||
)
|
||||
:gif (new 'static 'array uint64 2 #x50ab400000008001 #x43431)
|
||||
:gif0 (new 'static 'gif-tag64
|
||||
:nloop 1
|
||||
:eop 1
|
||||
:pre 1
|
||||
:prim (gs-prim-type sprite) ;; actually #b001101010110
|
||||
:flg (gif-flag packed)
|
||||
:nreg 5
|
||||
)
|
||||
:gif1 (new 'static 'gif-tag-regs
|
||||
:regs0 (gif-reg-id rgbaq)
|
||||
:regs1 (gif-reg-id uv)
|
||||
:regs2 (gif-reg-id xyzf2)
|
||||
:regs3 (gif-reg-id uv)
|
||||
:regs4 (gif-reg-id xyzf2)
|
||||
)
|
||||
)
|
||||
:temp-strip-tmpl (new 'static 'dma-gif-packet
|
||||
:dma-vif (new 'static 'dma-packet
|
||||
:dma (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt))
|
||||
:vif1 (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1)
|
||||
)
|
||||
:gif (new 'static 'array uint64 2 #x508b400000008001 #x43431)
|
||||
:gif0 (new 'static 'gif-tag64
|
||||
:nloop 1
|
||||
:eop 1
|
||||
:pre 1
|
||||
:prim (gs-prim-type sprite) ;; actually #b00100010110
|
||||
:flg (gif-flag packed)
|
||||
:nreg 5
|
||||
)
|
||||
:gif1 (new 'static 'gif-tag-regs
|
||||
:regs0 (gif-reg-id rgbaq)
|
||||
:regs1 (gif-reg-id uv)
|
||||
:regs2 (gif-reg-id xyzf2)
|
||||
:regs3 (gif-reg-id uv)
|
||||
:regs4 (gif-reg-id xyzf2)
|
||||
)
|
||||
)
|
||||
:stencil-tmpl (new 'static 'dma-gif-packet
|
||||
:dma-vif (new 'static 'dma-packet
|
||||
|
@ -255,145 +283,93 @@
|
|||
#f
|
||||
)
|
||||
|
||||
(defun depth-cue-draw-front ((arg0 dma-buffer) (arg1 int) (arg2 float) (arg3 float) (arg4 uint) (arg5 int))
|
||||
(set! (-> *depth-cue-work* draw-color w) (the int (* 128.0 arg3)))
|
||||
(let ((v1-1 (the int (* 512.0 arg2)))
|
||||
(a2-1 (the int (* (the float (* (-> *video-parms* screen-sy) 16)) arg2)))
|
||||
(a3-4 0)
|
||||
(t2-0 512)
|
||||
(t3-0 *depth-cue-base-page*)
|
||||
(defun depth-cue-draw-front ((dma-buff dma-buffer) (depth int) (sharpness float) (alpha float) (on-screen-fbp uint) (oddeven int))
|
||||
;; set draw-color alpha
|
||||
(set! (-> *depth-cue-work* draw-color w) (the int (* 128.0 alpha)))
|
||||
|
||||
;; sample the framebuffer in 16 vertical strips shrinking each a little,
|
||||
;; then overlay them back onto the framebuffer
|
||||
(let ((strip-w (the int (* 512.0 sharpness)))
|
||||
(strip-h (the int (* (the float (* (-> *video-parms* screen-sy) 16)) sharpness)))
|
||||
(x-offset 0) ;; incremented by 512 each loop
|
||||
(strip-max-w 512)
|
||||
)
|
||||
(dotimes (t4-0 16)
|
||||
(let* ((t5-0 arg0)
|
||||
(t6-0 (the-as object (-> t5-0 base)))
|
||||
;; repeat for each strip
|
||||
(dotimes (i 16)
|
||||
;; sample strip from framebuffer to depth-cue-base-page
|
||||
;; ------------------------------------------------------
|
||||
;; update GS registers
|
||||
(dma-buffer-add-gs-set dma-buff
|
||||
;; set vertex position offset
|
||||
(xyoffset-1 (new 'static 'gs-xy-offset :ofy (- 8 oddeven)))
|
||||
;; draw to depth-cue-base-page (64px wide)
|
||||
(frame-1 (new 'static 'gs-frame :fbw #x1 :fbp *depth-cue-base-page*))
|
||||
;; use on-screen framebuffer as texture 0
|
||||
;; buffer width = 512 pixels
|
||||
;; USIZE = 1024 texels
|
||||
;; VSIZE = 256 texels
|
||||
;; RGBA
|
||||
(tex0-1 (new 'static 'gs-tex0 :tbw #x8 :tw #xa :th #x8 :tcc #x1 :tbp0 (* on-screen-fbp 32)))
|
||||
;; enable depth test, all pixels pass
|
||||
(test-1 (new 'static 'gs-test :zte #x1 :ztst (gs-ztest always)))
|
||||
;; keep source rgb, no blending
|
||||
(alpha-1 (new 'static 'gs-alpha))
|
||||
)
|
||||
(set! (-> (the-as dma-packet t6-0) dma) (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt)))
|
||||
(set! (-> (the-as dma-packet t6-0) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet t6-0) vif1) (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1))
|
||||
(set! (-> t5-0 base) (the-as pointer (the-as gs-gif-tag (&+ (the-as pointer t6-0) 16))))
|
||||
;; draw sprite
|
||||
(let ((t5-3 (the-as (inline-array vector4w) (-> dma-buff base))))
|
||||
(set! (-> t5-3 0 quad) (-> *depth-cue-work* temp-strip-tmpl dma-vif quad)) ;; cnt direct
|
||||
(set! (-> t5-3 1 quad) (-> *depth-cue-work* temp-strip-tmpl quad 1)) ;; draw sprite, 5 regs
|
||||
(set! (-> t5-3 2 quad) (-> *depth-cue-work* set-color quad)) ;; rgbaq
|
||||
(set-vector! (-> t5-3 3) x-offset 0 0 0) ;; uv
|
||||
(set-vector! (-> t5-3 4) 0 0 0 0) ;; xyzf2
|
||||
(set-vector! (-> t5-3 5) (+ x-offset strip-max-w) (* (-> *video-parms* screen-sy) 16) 0 0) ;; uv
|
||||
(set-vector! (-> t5-3 6) strip-w strip-h 0 #x10000) ;; xyzf2
|
||||
)
|
||||
(let* ((t5-1 arg0)
|
||||
(t6-2 (the-as object (-> t5-1 base)))
|
||||
(&+! (-> dma-buff base) 112)
|
||||
|
||||
;; overlay strip back onto the on-screen framebuffer
|
||||
;; ------------------------------------------------------
|
||||
;; update GS registers
|
||||
(dma-buffer-add-gs-set dma-buff
|
||||
;; set vertex position offset
|
||||
(xyoffset-1 (new 'static 'gs-xy-offset :ofy (+ oddeven 4)))
|
||||
;; draw to on-screen-fbp but only the alpha channel
|
||||
(frame-1 (new 'static 'gs-frame :fbw #x8 :fbmsk #xff000000 :fbp on-screen-fbp))
|
||||
;; use an alpha value of 128
|
||||
(texa (new 'static 'gs-texa :ta0 #x80 :ta1 #x80))
|
||||
;; use depth-cue-base-page as texture 0
|
||||
;; buffer width = 64 pixels
|
||||
;; format = PSMCT24
|
||||
;; USIZE = 32 texels
|
||||
;; VSIZE = 256 texels
|
||||
;; RGB
|
||||
(tex0-1 (new 'static 'gs-tex0 :tbw #x1 :psm #x1 :tw #x5 :th #x8 :tbp0 (* *depth-cue-base-page* 32)))
|
||||
;; blend source and framebuffer RGB
|
||||
(alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1))
|
||||
)
|
||||
(set! (-> (the-as gs-gif-tag t6-2) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x5))
|
||||
(set! (-> (the-as gs-gif-tag t6-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! (-> t5-1 base) (&+ (the-as pointer t6-2) 16))
|
||||
)
|
||||
(let* ((t5-2 arg0)
|
||||
(t6-4 (-> t5-2 base))
|
||||
)
|
||||
(set! (-> (the-as (pointer gs-xy-offset) t6-4) 0) (new 'static 'gs-xy-offset :ofy (- 8 arg5)))
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-4) 1) (gs-reg64 xyoffset-1))
|
||||
(set! (-> (the-as (pointer gs-frame) t6-4) 2) (new 'static 'gs-frame :fbw #x1 :fbp t3-0))
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-4) 3) (gs-reg64 frame-1))
|
||||
(set! (-> (the-as (pointer gs-tex0) t6-4) 4)
|
||||
(new 'static 'gs-tex0 :tbw #x8 :tw #xa :th #x8 :tcc #x1 :tbp0 (* arg4 32))
|
||||
)
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-4) 5) (gs-reg64 tex0-1))
|
||||
(set! (-> (the-as (pointer gs-test) t6-4) 6) (new 'static 'gs-test :zte #x1 :ztst (gs-ztest always)))
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-4) 7) (gs-reg64 test-1))
|
||||
(set! (-> (the-as (pointer gs-alpha) t6-4) 8) (new 'static 'gs-alpha))
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-4) 9) (gs-reg64 alpha-1))
|
||||
(set! (-> t5-2 base) (&+ t6-4 80))
|
||||
)
|
||||
(let ((t5-3 (the-as (inline-array vector4w) (-> arg0 base))))
|
||||
(set! (-> t5-3 0 quad) (-> *depth-cue-work* temp-strip-tmpl dma-vif quad))
|
||||
(set! (-> t5-3 1 quad) (-> *depth-cue-work* temp-strip-tmpl quad 1))
|
||||
(set! (-> t5-3 2 quad) (-> *depth-cue-work* set-color quad))
|
||||
(set-vector! (-> t5-3 3) a3-4 0 0 0)
|
||||
(set-vector! (-> t5-3 4) 0 0 0 0)
|
||||
(set-vector! (-> t5-3 5) (+ a3-4 t2-0) (* (-> *video-parms* screen-sy) 16) 0 0)
|
||||
(set-vector! (-> t5-3 6) v1-1 a2-1 0 #x10000)
|
||||
)
|
||||
(set! (-> arg0 base) (the-as pointer (-> (the-as depth-cue-work (-> arg0 base)) set-color)))
|
||||
(let* ((t5-7 arg0)
|
||||
(t6-16 (the-as object (-> t5-7 base)))
|
||||
)
|
||||
(set! (-> (the-as dma-packet t6-16) dma) (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt)))
|
||||
(set! (-> (the-as dma-packet t6-16) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet t6-16) vif1) (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1))
|
||||
(set! (-> t5-7 base) (the-as pointer (the-as gs-gif-tag (&+ (the-as pointer t6-16) 16))))
|
||||
)
|
||||
(let* ((t5-8 arg0)
|
||||
(t6-18 (the-as object (-> t5-8 base)))
|
||||
)
|
||||
(set! (-> (the-as gs-gif-tag t6-18) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x5))
|
||||
(set! (-> (the-as gs-gif-tag t6-18) 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! (-> t5-8 base) (&+ (the-as pointer t6-18) 16))
|
||||
)
|
||||
(let* ((t5-9 arg0)
|
||||
(t6-20 (-> t5-9 base))
|
||||
)
|
||||
(set! (-> (the-as (pointer gs-xy-offset) t6-20) 0) (new 'static 'gs-xy-offset :ofy (+ arg5 4)))
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-20) 1) (gs-reg64 xyoffset-1))
|
||||
(set! (-> (the-as (pointer gs-frame) t6-20) 2) (new 'static 'gs-frame :fbw #x8 :fbmsk #xff000000 :fbp arg4))
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-20) 3) (gs-reg64 frame-1))
|
||||
(set! (-> (the-as (pointer gs-texa) t6-20) 4) (new 'static 'gs-texa :ta0 #x80 :ta1 #x80))
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-20) 5) (gs-reg64 texa))
|
||||
(set! (-> (the-as (pointer gs-tex0) t6-20) 6)
|
||||
(new 'static 'gs-tex0 :tbw #x1 :psm #x1 :tw #x5 :th #x8 :tbp0 (* t3-0 32))
|
||||
)
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-20) 7) (gs-reg64 tex0-1))
|
||||
(set! (-> (the-as (pointer gs-alpha) t6-20) 8) (new 'static 'gs-alpha :b #x1 :d #x1))
|
||||
(set! (-> (the-as (pointer gs-reg64) t6-20) 9) (gs-reg64 alpha-1))
|
||||
(set! (-> t5-9 base) (&+ t6-20 80))
|
||||
)
|
||||
(let ((t5-10 (the-as object (-> arg0 base))))
|
||||
;; draw sprite
|
||||
(let ((t5-10 (the-as object (-> dma-buff base))))
|
||||
(set! (-> (the-as (inline-array vector4w) t5-10) 0 quad)
|
||||
(-> *depth-cue-work* texture-strip-tmpl dma-vif quad)
|
||||
)
|
||||
(set! (-> (the-as (inline-array vector4w) t5-10) 1 quad) (-> *depth-cue-work* texture-strip-tmpl quad 1))
|
||||
(set! (-> (the-as (inline-array vector4w) t5-10) 2 quad) (-> *depth-cue-work* draw-color quad))
|
||||
(set-vector! (-> (the-as (inline-array vector4w) t5-10) 3) 0 0 0 0)
|
||||
(set-vector! (-> (the-as (inline-array vector4w) t5-10) 4) a3-4 0 0 0)
|
||||
(set-vector! (-> (the-as (inline-array vector4w) t5-10) 5) v1-1 a2-1 0 0)
|
||||
(set-vector!
|
||||
(set! (-> (the-as (inline-array vector4w) t5-10) 2 quad) (-> *depth-cue-work* draw-color quad)) ;; rgbaq
|
||||
(set-vector! (-> (the-as (inline-array vector4w) t5-10) 3) 0 0 0 0) ;; uv
|
||||
(set-vector! (-> (the-as (inline-array vector4w) t5-10) 4) x-offset 0 0 0) ;; xyzf2
|
||||
(set-vector! (-> (the-as (inline-array vector4w) t5-10) 5) strip-w strip-h 0 0) ;; uv
|
||||
(set-vector! ;; xyzf2
|
||||
(the-as vector4w (&+ (the-as pointer t5-10) 96))
|
||||
(+ a3-4 t2-0)
|
||||
(+ x-offset strip-max-w)
|
||||
(* (-> *video-parms* screen-sy) 16)
|
||||
arg1
|
||||
depth
|
||||
#x10000
|
||||
)
|
||||
)
|
||||
(set! (-> arg0 base) (the-as pointer (-> (the-as depth-cue-work (-> arg0 base)) set-color)))
|
||||
(+! a3-4 t2-0)
|
||||
(&+! (-> dma-buff base) 112)
|
||||
|
||||
;; next strip
|
||||
;; ------------------------------------------------------
|
||||
(+! x-offset strip-max-w)
|
||||
)
|
||||
)
|
||||
#f
|
||||
|
@ -407,132 +383,63 @@
|
|||
)
|
||||
)
|
||||
|
||||
(defun depth-cue ((arg0 display))
|
||||
(defun depth-cue ((disp display))
|
||||
;; is depth-cue enabled?
|
||||
(when (logtest? (vu1-renderer-mask depth-cue) *vu1-enable-user*)
|
||||
(let* ((gp-0 (-> *display* frames (-> *display* on-screen) frame global-buf base))
|
||||
(s4-0 (-> *display* frames (-> *display* on-screen) frame global-buf))
|
||||
(s5-0 (-> s4-0 base))
|
||||
(let* ((dma-start (-> *display* frames (-> *display* on-screen) frame global-buf base))
|
||||
(dma-buff (-> *display* frames (-> *display* on-screen) frame global-buf))
|
||||
(s5-0 (-> dma-buff base))
|
||||
)
|
||||
(let ((v1-9 (-> arg0 on-screen)))
|
||||
(let* ((a1-7 s4-0)
|
||||
(a2-0 (the-as object (-> a1-7 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! (-> a1-7 base) (&+ (the-as pointer a2-0) 16))
|
||||
)
|
||||
(let* ((a1-8 s4-0)
|
||||
(a2-2 (the-as object (-> a1-8 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! (-> a1-8 base) (&+ (the-as pointer a2-2) 16))
|
||||
)
|
||||
(let* ((a1-9 s4-0)
|
||||
(a2-4 (-> a1-9 base))
|
||||
)
|
||||
(set! (-> (the-as (pointer gs-test) a2-4) 0) (new 'static 'gs-test :zte #x1 :ztst (gs-ztest always)))
|
||||
(set! (-> (the-as (pointer gs-reg64) a2-4) 1) (gs-reg64 test-1))
|
||||
(set! (-> (the-as (pointer gs-zbuf) a2-4) 2) (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24) :zmsk #x1))
|
||||
(set! (-> (the-as (pointer gs-reg64) a2-4) 3) (gs-reg64 zbuf-1))
|
||||
(set! (-> (the-as (pointer gs-reg64) a2-4) 4) (gs-reg64 signal))
|
||||
(set! (-> (the-as (pointer gs-reg64) a2-4) 5) (gs-reg64 tex1-1))
|
||||
(set! (-> (the-as (pointer gs-tex1) a2-4) 6) (new 'static 'gs-tex1))
|
||||
(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
|
||||
(let ((v1-9 (-> disp on-screen)))
|
||||
;; initial GS register setup
|
||||
(dma-buffer-add-gs-set dma-buff
|
||||
;; depth test on, all pixels pass
|
||||
(test-1 (new 'static 'gs-test :zte #x1 :ztst (gs-ztest always)))
|
||||
;; don't write to depth buffer
|
||||
(zbuf-1 (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24) :zmsk #x1))
|
||||
;; bilinear texture sampling
|
||||
(tex1-1 (new 'static 'gs-tex1 :mmag 1 :mmin 1))
|
||||
;; no mip
|
||||
(miptbp1-1 (new 'static 'gs-miptbp))
|
||||
;; set texture wrap mode to clamp
|
||||
(clamp-1 (new 'static 'gs-clamp
|
||||
:wms (gs-tex-wrap-mode clamp)
|
||||
:wmt (gs-tex-wrap-mode clamp)
|
||||
:maxu #x1ff
|
||||
:maxv (-> *video-parms* screen-masky)
|
||||
))
|
||||
;; blend source and dest
|
||||
(alpha-1 (new 'static 'gs-alpha :b 1 :d 1))
|
||||
)
|
||||
)
|
||||
(set! (-> (the-as (pointer gs-reg64) a2-4) 9) (gs-reg64 clamp-1))
|
||||
(set! (-> (the-as (pointer gs-reg64) a2-4) 10) (gs-reg64 dimx))
|
||||
(set! (-> (the-as (pointer gs-reg64) a2-4) 11) (gs-reg64 alpha-1))
|
||||
(set! (-> a1-9 base) (&+ a2-4 96))
|
||||
)
|
||||
|
||||
(let ((s3-0 (* *oddeven* 8))
|
||||
(s2-0 (-> arg0 frames v1-9 draw frame1 fbp))
|
||||
(on-screen-fbp (-> disp frames v1-9 draw frame1 fbp))
|
||||
)
|
||||
;; draw
|
||||
(depth-cue-draw-front
|
||||
s4-0
|
||||
#xffffff
|
||||
(-> *depth-cue-work* front data x)
|
||||
(-> *depth-cue-work* front data y)
|
||||
s2-0
|
||||
s3-0
|
||||
dma-buff ;; dma-buff
|
||||
#xffffff ;; depth
|
||||
(-> *depth-cue-work* front data x) ;; sharpness
|
||||
(-> *depth-cue-work* front data y) ;; alpha
|
||||
on-screen-fbp ;; on-screen frame pointer
|
||||
s3-0 ;; oddeven * 8
|
||||
)
|
||||
(let* ((v1-19 s4-0)
|
||||
(a0-2 (the-as object (-> v1-19 base)))
|
||||
)
|
||||
(set! (-> (the-as dma-packet a0-2) dma) (new 'static 'dma-tag :qwc #x3 :id (dma-tag-id cnt)))
|
||||
(set! (-> (the-as dma-packet a0-2) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet a0-2) vif1) (new 'static 'vif-tag :imm #x3 :cmd (vif-cmd direct) :msk #x1))
|
||||
(set! (-> v1-19 base) (&+ (the-as pointer a0-2) 16))
|
||||
)
|
||||
(let* ((v1-20 s4-0)
|
||||
(a0-4 (the-as object (-> v1-20 base)))
|
||||
)
|
||||
(set! (-> (the-as gs-gif-tag a0-4) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x2))
|
||||
(set! (-> (the-as gs-gif-tag a0-4) 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-20 base) (&+ (the-as pointer a0-4) 16))
|
||||
)
|
||||
(let* ((v1-21 s4-0)
|
||||
(a0-6 (-> v1-21 base))
|
||||
)
|
||||
(set! (-> (the-as (pointer gs-xy-offset) a0-6) 0)
|
||||
(new 'static 'gs-xy-offset :ofx #x7000 :ofy (+ (* (-> *video-parms* screen-miny) 16) s3-0))
|
||||
)
|
||||
(set! (-> (the-as (pointer gs-reg64) a0-6) 1) (gs-reg64 xyoffset-1))
|
||||
(set! (-> (the-as (pointer gs-frame) a0-6) 2) (new 'static 'gs-frame :fbw #x8 :fbp s2-0))
|
||||
(set! (-> (the-as (pointer gs-reg64) a0-6) 3) (gs-reg64 frame-1))
|
||||
(set! (-> v1-21 base) (&+ a0-6 32))
|
||||
;; restore GS registers
|
||||
(dma-buffer-add-gs-set dma-buff
|
||||
;; restore xyoffset register
|
||||
(xyoffset-1 (new 'static 'gs-xy-offset :ofx #x7000 :ofy (+ (* (-> *video-parms* screen-miny) 16) s3-0)))
|
||||
;; restore drawing destination to on-screen framebuffer
|
||||
(frame-1 (new 'static 'gs-frame :fbw #x8 :fbp on-screen-fbp))
|
||||
)
|
||||
)
|
||||
)
|
||||
(let ((a3-18 (-> s4-0 base)))
|
||||
(let ((v1-22 (the-as object (-> s4-0 base))))
|
||||
(let ((a3-18 (-> dma-buff base)))
|
||||
;; add DMA chain
|
||||
(let ((v1-22 (the-as object (-> dma-buff base))))
|
||||
(set! (-> (the-as dma-packet v1-22) dma) (new 'static 'dma-tag :id (dma-tag-id next)))
|
||||
(set! (-> (the-as dma-packet v1-22) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet v1-22) vif1) (new 'static 'vif-tag))
|
||||
(set! (-> s4-0 base) (&+ (the-as pointer v1-22) 16))
|
||||
(set! (-> dma-buff base) (&+ (the-as pointer v1-22) 16))
|
||||
)
|
||||
(let ((v0-0 (dma-bucket-insert-tag
|
||||
(-> *display* frames (-> *display* on-screen) frame bucket-group)
|
||||
|
@ -542,13 +449,14 @@
|
|||
)
|
||||
)
|
||||
)
|
||||
;; record memory usage
|
||||
(let ((v1-27 *dma-mem-usage*))
|
||||
(when (nonzero? v1-27)
|
||||
(set! (-> v1-27 length) (max 84 (-> v1-27 length)))
|
||||
(set! (-> v1-27 data 83 name) "depth-cue")
|
||||
(+! (-> v1-27 data 83 count) 1)
|
||||
(+! (-> v1-27 data 83 used)
|
||||
(&- (-> *display* frames (-> *display* on-screen) frame global-buf base) (the-as uint gp-0))
|
||||
(&- (-> *display* frames (-> *display* on-screen) frame global-buf base) (the-as uint dma-start))
|
||||
)
|
||||
(set! (-> v1-27 data 83 total) (-> v1-27 data 83 used))
|
||||
)
|
||||
|
|
|
@ -54,6 +54,11 @@
|
|||
)
|
||||
)
|
||||
|
||||
;; disable depth-cue by default for the PC port
|
||||
(#when PC_PORT
|
||||
(logclear! *vu1-enable-user-menu* (vu1-renderer-mask depth-cue))
|
||||
)
|
||||
|
||||
;; by default, all off.
|
||||
;; the menu renderers get copied to this on each frame
|
||||
(define *vu1-enable-user* (the-as vu1-renderer-mask 0))
|
||||
|
|
Loading…
Reference in a new issue