Files
jak-project/game/graphics/opengl_renderer/BucketRenderer.h
T
Tyler Wilding 92c4390f0a jak1: Adjust sprite positioning or hide them where appropriate when using non-standard aspect ratios (#3596)
This attempts to do a best-effort quick fix for the sprite alignment in
the menus and first person views on higher aspect ratios. This:
- Hides the binocular borders completely when using a non-standard ratio
![Screenshot 2024-07-20
021430](https://github.com/user-attachments/assets/c56d3a6c-13b0-43e1-b99b-83292993728c)
- Hides the borders in jak's first person view when using a non-standard
ratio
![Screenshot 2024-07-20
021310](https://github.com/user-attachments/assets/fefca993-960b-4741-87b7-6d7c17efe89d)
- Uses a combination of manual alignment and approximation to get the
pause menu closer.
![Screenshot 2024-07-20
151725](https://github.com/user-attachments/assets/2c8aa759-b33a-4fbe-abc6-b5861fc33208)
> 32:9 screenshot.

I accomplished the last one by manually aligning all of the core sprites
and text for the most popular aspect ratios. This means that from a
practical standpoint, things should align "perfectly". However, I then
used all of those values to derive a polynomial for each adjustment
based on the aspect ratio. This allows the game to do a half-decent
approximation/interpolation for every aspect ratio in-between the common
ones. It won't be perfect, but it will be better than this:

![image](https://github.com/user-attachments/assets/420b1e38-6f88-436a-8e8c-21df6b49428e)
2024-07-26 23:15:51 -04:00

163 lines
5.0 KiB
C++

#pragma once
#include <memory>
#include <string>
#include "common/dma/dma_chain_read.h"
#include "game/graphics/opengl_renderer/Profiler.h"
#include "game/graphics/opengl_renderer/Shader.h"
#include "game/graphics/opengl_renderer/buckets.h"
#include "game/graphics/opengl_renderer/loader/Loader.h"
#include "game/graphics/texture/TexturePool.h"
struct Fbo;
struct LevelVis {
bool valid = false;
u8 data[2048];
};
class EyeRenderer;
/*!
* The main renderer will contain a single SharedRenderState that's passed to all bucket renderers.
* This allows bucket renders to share textures and shaders.
*/
struct SharedRenderState {
explicit SharedRenderState(std::shared_ptr<TexturePool> _texture_pool,
std::shared_ptr<Loader> _loader,
GameVersion _version)
: shaders(_version), texture_pool(_texture_pool), loader(_loader), version(_version) {}
ShaderLibrary shaders;
std::shared_ptr<TexturePool> texture_pool;
std::shared_ptr<Loader> loader;
u32 buckets_base = 0; // address of buckets array.
u32 next_bucket = 0; // address of next bucket that we haven't started rendering in buckets
u32 default_regs_buffer = 0; // address of the default regs chain.
void* ee_main_memory = nullptr;
u32 offset_of_s7;
bool use_sky_cpu = true;
bool use_occlusion_culling = true;
math::Vector<u8, 4> fog_color = math::Vector<u8, 4>{0, 0, 0, 0};
float fog_intensity = 1.f;
bool no_multidraw = false;
void reset();
bool has_pc_data = false;
// limit is arbitrary so let's go ham in case we want more levels in the future
LevelVis occlusion_vis[32];
math::Vector4f camera_planes[4];
// including transformation, rotation, perspective
math::Vector4f camera_matrix[4];
math::Vector4f camera_hvdf_off;
math::Vector4f camera_fog;
math::Vector4f camera_pos;
EyeRenderer* eye_renderer = nullptr;
std::string load_status_debug;
// Information for renderers that need to read framebuffers:
// Most renderers can just use the framebuffer/glViewport set up by OpenGLRenderer, but special
// effects like sprite distort that read the framebuffer will need to know the details of the
// framebuffer setup.
// the framebuffer that bucket renderers should render to.
int render_fb_x = 0;
int render_fb_y = 0;
int render_fb_w = 0;
int render_fb_h = 0;
GLuint render_fb = -1;
// the region within that framebuffer to draw to.
int draw_region_w = 0;
int draw_region_h = 0;
int draw_offset_x = 0;
int draw_offset_y = 0;
int bucket_for_vis_copy = 0;
int num_vis_to_copy = 0;
GameVersion version;
u64 frame_idx = 0;
bool stencil_dirty = false;
};
/*!
* Interface for bucket renders. Each bucket will have its own BucketRenderer.
*/
class BucketRenderer {
public:
BucketRenderer(const std::string& name, int my_id) : m_name(name), m_my_id(my_id) {}
virtual void render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) = 0;
std::string name() const;
std::string name_and_id() const;
virtual ~BucketRenderer() = default;
bool& enabled() { return m_enabled; }
virtual bool empty() const { return false; }
virtual void draw_debug_window() = 0;
virtual void init_shaders(ShaderLibrary&) {}
virtual void init_textures(TexturePool&, GameVersion) {}
protected:
std::string m_name;
int m_my_id;
bool m_enabled = true;
};
class RenderMux : public BucketRenderer {
public:
RenderMux(const std::string& name,
int my_id,
std::vector<std::unique_ptr<BucketRenderer>> renderers);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
void init_shaders(ShaderLibrary&) override;
void init_textures(TexturePool&, GameVersion) override;
void set_idx(u32 i) { m_render_idx = i; };
private:
std::vector<std::unique_ptr<BucketRenderer>> m_renderers;
int m_render_idx = 0;
std::vector<std::string> m_name_strs;
std::vector<const char*> m_name_str_ptrs;
};
/*!
* Renderer that makes sure the bucket is empty and ignores it.
*/
class EmptyBucketRenderer : public BucketRenderer {
public:
EmptyBucketRenderer(const std::string& name, int my_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
bool empty() const override { return true; }
void draw_debug_window() override {}
};
class SkipRenderer : public BucketRenderer {
public:
SkipRenderer(const std::string& name, int my_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
bool empty() const override { return true; }
void draw_debug_window() override {}
};
/*!
* Renderer that ignores and prints all DMA transfers.
*/
class PrintRenderer : public BucketRenderer {
public:
PrintRenderer(const std::string& name, int my_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
bool empty() const override { return true; }
void draw_debug_window() override {}
};