mirror of
https://github.com/open-goal/jak-project
synced 2026-06-16 06:46:07 -04:00
e26efcc4f3
Implements the jak 2 lightning renderer as an alternate path through Generic2. Also set up some generic stuff in the goal code. There is a problem with the texture pool, which doesn't support the case where two textures have the same tbp, but different cluts. So lightning is often the wrong color (usually red).
334 lines
13 KiB
C++
334 lines
13 KiB
C++
#include "common/log/log.h"
|
|
|
|
#include "Generic2.h"
|
|
|
|
void Generic2::opengl_setup() {
|
|
// create OpenGL objects
|
|
glGenBuffers(1, &m_ogl.vertex_buffer);
|
|
glGenBuffers(1, &m_ogl.index_buffer);
|
|
glGenVertexArrays(1, &m_ogl.vao);
|
|
|
|
// set up the vertex array
|
|
glBindVertexArray(m_ogl.vao);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(u32), nullptr, GL_STREAM_DRAW);
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
|
|
glBufferData(GL_ARRAY_BUFFER, m_verts.size() * sizeof(Vertex), nullptr, GL_STREAM_DRAW);
|
|
|
|
// xyz
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(0, // location 0 in the shader
|
|
3, // 3 floats per vert
|
|
GL_FLOAT, // floats
|
|
GL_TRUE, // normalized, ignored,
|
|
sizeof(Vertex), //
|
|
(void*)offsetof(Vertex, xyz) // offset in array
|
|
);
|
|
|
|
// rgba
|
|
glEnableVertexAttribArray(1);
|
|
glVertexAttribPointer(1, // location 1 in the shader
|
|
4, // 4 color components
|
|
GL_UNSIGNED_BYTE, // u8
|
|
GL_TRUE, // normalized (255 becomes 1)
|
|
sizeof(Vertex), //
|
|
(void*)offsetof(Vertex, rgba) //
|
|
);
|
|
|
|
// stq
|
|
glEnableVertexAttribArray(2);
|
|
glVertexAttribPointer(2, // location 2 in the shader
|
|
2, // 2 floats per vert
|
|
GL_FLOAT, // floats
|
|
GL_FALSE, // normalized, ignored
|
|
sizeof(Vertex), //
|
|
(void*)offsetof(Vertex, st) // offset in array
|
|
);
|
|
|
|
// byte data
|
|
glEnableVertexAttribArray(3);
|
|
glVertexAttribIPointer(3, // location 3 in the shader
|
|
4, //
|
|
GL_UNSIGNED_BYTE, // u8's
|
|
sizeof(Vertex), //
|
|
(void*)offsetof(Vertex, tex_unit) // offset in array
|
|
);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
void Generic2::opengl_cleanup() {
|
|
glDeleteBuffers(1, &m_ogl.vertex_buffer);
|
|
glDeleteBuffers(1, &m_ogl.index_buffer);
|
|
glDeleteVertexArrays(1, &m_ogl.vao);
|
|
}
|
|
|
|
void Generic2::init_shaders(ShaderLibrary& shaders) {
|
|
const auto& shader = shaders[ShaderId::GENERIC];
|
|
auto id = shader.id();
|
|
|
|
shader.activate();
|
|
m_ogl.alpha_reject = glGetUniformLocation(id, "alpha_reject");
|
|
m_ogl.color_mult = glGetUniformLocation(id, "color_mult");
|
|
m_ogl.fog_color = glGetUniformLocation(id, "fog_color");
|
|
|
|
m_ogl.scale = glGetUniformLocation(id, "scale");
|
|
m_ogl.mat_23 = glGetUniformLocation(id, "mat_23");
|
|
m_ogl.mat_32 = glGetUniformLocation(id, "mat_32");
|
|
m_ogl.mat_33 = glGetUniformLocation(id, "mat_33");
|
|
m_ogl.fog_consts = glGetUniformLocation(id, "fog_constants");
|
|
m_ogl.hvdf_offset = glGetUniformLocation(id, "hvdf_offset");
|
|
m_ogl.gfx_hack_no_tex = glGetUniformLocation(id, "gfx_hack_no_tex");
|
|
}
|
|
|
|
void Generic2::opengl_bind_and_setup_proj(SharedRenderState* render_state) {
|
|
render_state->shaders[ShaderId::GENERIC].activate();
|
|
glUniform4f(m_ogl.fog_color, render_state->fog_color[0] / 255.f,
|
|
render_state->fog_color[1] / 255.f, render_state->fog_color[2] / 255.f,
|
|
render_state->fog_intensity / 255);
|
|
glUniform4f(m_ogl.scale, m_drawing_config.proj_scale[0], m_drawing_config.proj_scale[1],
|
|
m_drawing_config.proj_scale[2], 0);
|
|
glUniform1f(m_ogl.mat_23, m_drawing_config.proj_mat_23);
|
|
glUniform1f(m_ogl.mat_32, m_drawing_config.proj_mat_32);
|
|
glUniform1f(m_ogl.mat_33, 0);
|
|
glUniform3f(m_ogl.fog_consts, m_drawing_config.pfog0, m_drawing_config.fog_min,
|
|
m_drawing_config.fog_max);
|
|
glUniform4f(m_ogl.hvdf_offset, m_drawing_config.hvdf_offset[0], m_drawing_config.hvdf_offset[1],
|
|
m_drawing_config.hvdf_offset[2], m_drawing_config.hvdf_offset[3]);
|
|
glUniform1i(m_ogl.gfx_hack_no_tex, Gfx::g_global_settings.hack_no_tex);
|
|
}
|
|
|
|
void Generic2::setup_opengl_for_draw_mode(const DrawMode& draw_mode,
|
|
u8 fix,
|
|
SharedRenderState* render_state) {
|
|
// compute alpha_reject:
|
|
float alpha_reject = 0.f;
|
|
if (draw_mode.get_at_enable()) {
|
|
switch (draw_mode.get_alpha_test()) {
|
|
case DrawMode::AlphaTest::ALWAYS:
|
|
break;
|
|
case DrawMode::AlphaTest::GEQUAL:
|
|
alpha_reject = draw_mode.get_aref() / 128.f;
|
|
break;
|
|
case DrawMode::AlphaTest::NEVER:
|
|
break;
|
|
default:
|
|
ASSERT_MSG(false, fmt::format("unknown alpha test: {}", (int)draw_mode.get_alpha_test()));
|
|
}
|
|
}
|
|
|
|
// setup blending and color mult
|
|
float color_mult = 1.f;
|
|
if (!draw_mode.get_ab_enable()) {
|
|
glDisable(GL_BLEND);
|
|
} else {
|
|
glEnable(GL_BLEND);
|
|
glBlendColor(1, 1, 1, 1);
|
|
if (draw_mode.get_alpha_blend() == DrawMode::AlphaBlend::SRC_DST_SRC_DST) {
|
|
// (Cs - Cd) * As + Cd
|
|
// Cs * As + (1 - As) * Cd
|
|
// s, d
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
} else if (draw_mode.get_alpha_blend() == DrawMode::AlphaBlend::SRC_0_SRC_DST) {
|
|
// (Cs - 0) * As + Cd
|
|
// Cs * As + (1) * Cd
|
|
// s, d
|
|
// fix is ignored. it's usually 0, except for lightning, which sets it to 0x80.
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
} else if (draw_mode.get_alpha_blend() == DrawMode::AlphaBlend::ZERO_SRC_SRC_DST) {
|
|
// (0 - Cs) * As + Cd
|
|
// Cd - Cs * As
|
|
// s, d
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
|
} else if (draw_mode.get_alpha_blend() == DrawMode::AlphaBlend::SRC_DST_FIX_DST) {
|
|
// (Cs - Cd) * fix + Cd
|
|
// Cs * fix + (1 - fx) * Cd
|
|
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
|
|
glBlendColor(0, 0, 0, fix / 127.f);
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
} else if (draw_mode.get_alpha_blend() == DrawMode::AlphaBlend::SRC_SRC_SRC_SRC) {
|
|
// this is very weird...
|
|
// Cs
|
|
glBlendFunc(GL_ONE, GL_ZERO);
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
} else if (draw_mode.get_alpha_blend() == DrawMode::AlphaBlend::SRC_0_DST_DST) {
|
|
// (Cs - 0) * Ad + Cd
|
|
glBlendFunc(GL_DST_ALPHA, GL_ONE);
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
color_mult = 0.5f;
|
|
} else if (draw_mode.get_alpha_blend() == DrawMode::AlphaBlend::SRC_0_FIX_DST) {
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ZERO);
|
|
} else {
|
|
ASSERT(false);
|
|
}
|
|
}
|
|
|
|
// setup ztest
|
|
if (draw_mode.get_zt_enable()) {
|
|
glEnable(GL_DEPTH_TEST);
|
|
switch (draw_mode.get_depth_test()) {
|
|
case GsTest::ZTest::NEVER:
|
|
glDepthFunc(GL_NEVER);
|
|
break;
|
|
case GsTest::ZTest::ALWAYS:
|
|
glDepthFunc(GL_ALWAYS);
|
|
break;
|
|
case GsTest::ZTest::GEQUAL:
|
|
glDepthFunc(GL_GEQUAL);
|
|
break;
|
|
case GsTest::ZTest::GREATER:
|
|
glDepthFunc(GL_GREATER);
|
|
break;
|
|
default:
|
|
ASSERT(false);
|
|
}
|
|
} else {
|
|
// you aren't supposed to turn off z test enable, the GS had some bugs
|
|
ASSERT(false);
|
|
}
|
|
|
|
if (draw_mode.get_depth_write_enable()) {
|
|
glDepthMask(GL_TRUE);
|
|
} else {
|
|
glDepthMask(GL_FALSE);
|
|
}
|
|
|
|
glUniform1f(m_ogl.alpha_reject, alpha_reject);
|
|
glUniform1f(m_ogl.color_mult, color_mult);
|
|
glUniform4f(m_ogl.fog_color, render_state->fog_color[0] / 255.f,
|
|
render_state->fog_color[1] / 255.f, render_state->fog_color[2] / 255.f,
|
|
render_state->fog_intensity / 255);
|
|
}
|
|
|
|
void Generic2::setup_opengl_tex(u16 unit,
|
|
u16 tbp,
|
|
bool filter,
|
|
bool clamp_s,
|
|
bool clamp_t,
|
|
SharedRenderState* render_state) {
|
|
// look up the texture
|
|
std::optional<u64> tex;
|
|
u32 tbp_to_lookup = tbp & 0x7fff;
|
|
bool use_mt4hh = tbp & 0x8000;
|
|
|
|
if (use_mt4hh) {
|
|
tex = render_state->texture_pool->lookup_mt4hh(tbp_to_lookup);
|
|
} else {
|
|
tex = render_state->texture_pool->lookup(tbp_to_lookup);
|
|
}
|
|
|
|
if (!tex) {
|
|
// TODO Add back
|
|
if (tbp_to_lookup >= 8160 && tbp_to_lookup <= 8600) {
|
|
lg::warn("Failed to find texture at {}, using random (eye zone)", tbp_to_lookup);
|
|
tex = render_state->texture_pool->get_placeholder_texture();
|
|
} else {
|
|
lg::warn("Failed to find texture at {}, using random", tbp_to_lookup);
|
|
tex = render_state->texture_pool->get_placeholder_texture();
|
|
}
|
|
}
|
|
|
|
glActiveTexture(GL_TEXTURE0 + unit);
|
|
glBindTexture(GL_TEXTURE_2D, *tex);
|
|
if (clamp_s) {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
} else {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
}
|
|
|
|
if (clamp_t) {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
} else {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
}
|
|
|
|
if (filter) {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
|
true ? GL_LINEAR : GL_LINEAR_MIPMAP_LINEAR); // todo
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
} else {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
}
|
|
}
|
|
|
|
void Generic2::do_draws_for_alpha(SharedRenderState* render_state,
|
|
ScopedProfilerNode& prof,
|
|
DrawMode::AlphaBlend alpha,
|
|
bool hud) {
|
|
for (u32 i = 0; i < m_next_free_bucket; i++) {
|
|
auto& bucket = m_buckets[i];
|
|
auto& first = m_adgifs[bucket.start];
|
|
if (first.mode.get_alpha_blend() == alpha && first.uses_hud == hud) {
|
|
setup_opengl_for_draw_mode(first.mode, first.fix, render_state);
|
|
setup_opengl_tex(0, first.tbp, first.mode.get_filt_enable(), first.mode.get_clamp_s_enable(),
|
|
first.mode.get_clamp_t_enable(), render_state);
|
|
// if (alpha == DrawMode::AlphaBlend::SRC_0_DST_DST) {
|
|
// glBindTexture(GL_TEXTURE_2D, render_state->texture_pool->get_placeholder_texture());
|
|
// }
|
|
glDrawElements(GL_TRIANGLE_STRIP, bucket.idx_count, GL_UNSIGNED_INT,
|
|
(void*)(sizeof(u32) * bucket.idx_idx));
|
|
prof.add_draw_call();
|
|
prof.add_tri(bucket.tri_count);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Generic2::do_hud_draws(SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
|
for (u32 i = 0; i < m_next_free_bucket; i++) {
|
|
auto& bucket = m_buckets[i];
|
|
auto& first = m_adgifs[bucket.start];
|
|
if (first.uses_hud) {
|
|
setup_opengl_for_draw_mode(first.mode, first.fix, render_state);
|
|
setup_opengl_tex(0, first.tbp, first.mode.get_filt_enable(), first.mode.get_clamp_s_enable(),
|
|
first.mode.get_clamp_t_enable(), render_state);
|
|
glDrawElements(GL_TRIANGLE_STRIP, bucket.idx_count, GL_UNSIGNED_INT,
|
|
(void*)(sizeof(u32) * bucket.idx_idx));
|
|
prof.add_draw_call();
|
|
prof.add_tri(bucket.tri_count);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Generic2::do_draws(SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
|
glBindVertexArray(m_ogl.vao);
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_next_free_idx * sizeof(u32), m_indices.data(),
|
|
GL_STREAM_DRAW);
|
|
glBufferData(GL_ARRAY_BUFFER, m_next_free_vert * sizeof(Vertex), m_verts.data(), GL_STREAM_DRAW);
|
|
|
|
glEnable(GL_PRIMITIVE_RESTART);
|
|
glPrimitiveRestartIndex(UINT32_MAX);
|
|
|
|
opengl_bind_and_setup_proj(render_state);
|
|
constexpr DrawMode::AlphaBlend alpha_order[ALPHA_MODE_COUNT] = {
|
|
DrawMode::AlphaBlend::SRC_0_FIX_DST, DrawMode::AlphaBlend::SRC_SRC_SRC_SRC,
|
|
DrawMode::AlphaBlend::SRC_DST_SRC_DST, DrawMode::AlphaBlend::SRC_0_SRC_DST,
|
|
DrawMode::AlphaBlend::ZERO_SRC_SRC_DST, DrawMode::AlphaBlend::SRC_DST_FIX_DST,
|
|
DrawMode::AlphaBlend::SRC_0_DST_DST,
|
|
};
|
|
|
|
for (int i = 0; i < ALPHA_MODE_COUNT; i++) {
|
|
if (m_alpha_draw_enable[i]) {
|
|
do_draws_for_alpha(render_state, prof, alpha_order[i], false);
|
|
}
|
|
}
|
|
|
|
if (m_drawing_config.uses_hud) {
|
|
glUniform4f(m_ogl.scale, m_drawing_config.hud_scale[0], m_drawing_config.hud_scale[1],
|
|
m_drawing_config.hud_scale[2], 0);
|
|
glUniform1f(m_ogl.mat_23, m_drawing_config.hud_mat_23);
|
|
glUniform1f(m_ogl.mat_32, m_drawing_config.hud_mat_32);
|
|
glUniform1f(m_ogl.mat_33, m_drawing_config.hud_mat_33);
|
|
glUniform1i(m_ogl.gfx_hack_no_tex, false);
|
|
|
|
do_hud_draws(render_state, prof);
|
|
}
|
|
}
|