mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
[jak2] faster startup (#2738)
Trying to make up for some of the startup speed lost in the SDL transition. This saves about 1s from start (from ~3s), and about 500 MB of RAM. - Faster TIE unpack by merging matrix groups, more efficient vertex transforms, and skipping normal transforms on groups with no normals. - Refactor generic merc and merc to use a single renderer with multiple interfaces, rather than many renderers. Removed "LightningRenderer" as a special thing, but Warp is still special - Add more profiling stuff to startup and the loader. - Remove `SDL_INIT_HAPTIC` - this turned out to be needed for force-feedback steering wheels, and not needed for controller vibration - Switched `vag-player` to use quicksort instead of the default GOAL sort (very slow)
This commit is contained in:
parent
1512c6bd9c
commit
6e779d1f1c
|
@ -3,6 +3,8 @@
|
|||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "xmmintrin.h"
|
||||
|
||||
#include "common/util/Assert.h"
|
||||
|
||||
namespace tfrag3 {
|
||||
|
@ -166,6 +168,7 @@ std::array<math::Vector3f, 3> tie_normal_transform_v2(const std::array<math::Vec
|
|||
// vmadday.xyzw acc, vf25, vf18
|
||||
// vmaddz.xyzw vf12, vf26, vf18
|
||||
result[2] = vf18;
|
||||
|
||||
return result;
|
||||
//
|
||||
// sqc2 vf10, -112(t8)
|
||||
|
@ -199,6 +202,22 @@ u32 unpack_tie_normal(const std::array<math::Vector3f, 3>& mat, s8 nx, s8 ny, s8
|
|||
return pack_to_gl_normal(as_int.x(), as_int.y(), as_int.z());
|
||||
}
|
||||
|
||||
/*
|
||||
void tie_normal_v3(__m128* out, const std::array<math::Vector4f, 4>& in) {
|
||||
math::Vector3f x_row = in[0].xyz();
|
||||
math::Vector3f y_row = in[1].xyz();
|
||||
math::Vector3f z_row = in[2].xyz();
|
||||
|
||||
x_row.normalize();
|
||||
y_row = x_row.cross(y_row.cross(x_row)).normalized();
|
||||
z_row = x_row.cross(y_row);
|
||||
|
||||
out[0] = _mm_setr_ps(x_row[0], x_row[1], x_row[2], 0);
|
||||
out[1] = _mm_setr_ps(y_row[0], y_row[1], y_row[2], 0);
|
||||
out[2] = _mm_setr_ps(z_row[0], z_row[1], z_row[2], 0);
|
||||
}
|
||||
*/
|
||||
|
||||
void TieTree::unpack() {
|
||||
unpacked.vertices.resize(packed_vertices.color_indices.size());
|
||||
size_t i = 0;
|
||||
|
@ -222,24 +241,53 @@ void TieTree::unpack() {
|
|||
}
|
||||
} else {
|
||||
const auto& mat = packed_vertices.matrices[grp.matrix_idx];
|
||||
auto nmat = tie_normal_transform_v2(mat);
|
||||
|
||||
for (u32 src_idx = grp.start_vert; src_idx < grp.end_vert; src_idx++) {
|
||||
auto& vtx = unpacked.vertices[i];
|
||||
vtx.color_index = packed_vertices.color_indices[i];
|
||||
const auto& proto_vtx = packed_vertices.vertices[src_idx];
|
||||
auto temp = mat[0] * proto_vtx.x + mat[1] * proto_vtx.y + mat[2] * proto_vtx.z + mat[3];
|
||||
vtx.x = temp.x();
|
||||
vtx.y = temp.y();
|
||||
vtx.z = temp.z();
|
||||
vtx.s = proto_vtx.s;
|
||||
vtx.t = proto_vtx.t;
|
||||
vtx.nor = unpack_tie_normal(nmat, proto_vtx.nx, proto_vtx.ny, proto_vtx.nz);
|
||||
vtx.r = proto_vtx.r;
|
||||
vtx.g = proto_vtx.g;
|
||||
vtx.b = proto_vtx.b;
|
||||
vtx.a = proto_vtx.a;
|
||||
i++;
|
||||
__m128 mat0 = _mm_loadu_ps(mat[0].data());
|
||||
__m128 mat1 = _mm_loadu_ps(mat[1].data());
|
||||
__m128 mat2 = _mm_loadu_ps(mat[2].data());
|
||||
__m128 mat3 = _mm_loadu_ps(mat[3].data());
|
||||
|
||||
if (grp.has_normals) {
|
||||
auto nmat = tie_normal_transform_v2(mat);
|
||||
for (u32 src_idx = grp.start_vert; src_idx < grp.end_vert; src_idx++) {
|
||||
auto& vtx = unpacked.vertices[i];
|
||||
vtx.color_index = packed_vertices.color_indices[i];
|
||||
const auto& proto_vtx = packed_vertices.vertices[src_idx];
|
||||
// auto temp = mat[0] * proto_vtx.x + mat[1] * proto_vtx.y + mat[2] * proto_vtx.z +
|
||||
// mat[3];
|
||||
__m128 transformed = mat3;
|
||||
transformed = _mm_add_ps(transformed, _mm_mul_ps(_mm_set1_ps(proto_vtx.x), mat0));
|
||||
transformed = _mm_add_ps(transformed, _mm_mul_ps(_mm_set1_ps(proto_vtx.y), mat1));
|
||||
transformed = _mm_add_ps(transformed, _mm_mul_ps(_mm_set1_ps(proto_vtx.z), mat2));
|
||||
_mm_storeu_ps(&vtx.x, transformed);
|
||||
vtx.s = proto_vtx.s;
|
||||
vtx.t = proto_vtx.t;
|
||||
vtx.nor = unpack_tie_normal(nmat, proto_vtx.nx, proto_vtx.ny, proto_vtx.nz);
|
||||
vtx.r = proto_vtx.r;
|
||||
vtx.g = proto_vtx.g;
|
||||
vtx.b = proto_vtx.b;
|
||||
vtx.a = proto_vtx.a;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
for (u32 src_idx = grp.start_vert; src_idx < grp.end_vert; src_idx++) {
|
||||
auto& vtx = unpacked.vertices[i];
|
||||
vtx.color_index = packed_vertices.color_indices[i];
|
||||
const auto& proto_vtx = packed_vertices.vertices[src_idx];
|
||||
__m128 transformed = mat3;
|
||||
transformed = _mm_add_ps(transformed, _mm_mul_ps(_mm_set1_ps(proto_vtx.x), mat0));
|
||||
transformed = _mm_add_ps(transformed, _mm_mul_ps(_mm_set1_ps(proto_vtx.y), mat1));
|
||||
transformed = _mm_add_ps(transformed, _mm_mul_ps(_mm_set1_ps(proto_vtx.z), mat2));
|
||||
_mm_storeu_ps(&vtx.x, transformed);
|
||||
vtx.s = proto_vtx.s;
|
||||
vtx.t = proto_vtx.t;
|
||||
vtx.nor = 0;
|
||||
vtx.r = proto_vtx.r;
|
||||
vtx.g = proto_vtx.g;
|
||||
vtx.b = proto_vtx.b;
|
||||
vtx.a = proto_vtx.a;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace tfrag3 {
|
|||
// - if changing any large things (vertices, vis, bvh, colors, textures) update get_memory_usage
|
||||
// - if adding a new category to the memory usage, update extract_level to print it.
|
||||
|
||||
constexpr int TFRAG3_VERSION = 36;
|
||||
constexpr int TFRAG3_VERSION = 37;
|
||||
|
||||
enum MemoryUsageCategory {
|
||||
TEXTURE,
|
||||
|
@ -115,6 +115,7 @@ struct PackedTieVertices {
|
|||
s32 matrix_idx;
|
||||
u32 start_vert;
|
||||
u32 end_vert;
|
||||
bool has_normals = false;
|
||||
};
|
||||
|
||||
std::vector<u16> color_indices;
|
||||
|
|
|
@ -2489,6 +2489,14 @@ void handle_draw_for_strip(tfrag3::TieTree& tree,
|
|||
grp.matrix_idx = matrix_idx;
|
||||
grp.start_vert = packed_vert_indices.at(frag_idx).at(strip_idx).first;
|
||||
grp.end_vert = packed_vert_indices.at(frag_idx).at(strip_idx).second;
|
||||
grp.has_normals = false;
|
||||
for (auto i = grp.start_vert; i < grp.end_vert; i++) {
|
||||
auto& v = tree.packed_vertices.vertices.at(i);
|
||||
if (v.nx || v.ny || v.nz) {
|
||||
grp.has_normals = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tree.packed_vertices.matrix_groups.push_back(grp);
|
||||
tfrag3::StripDraw::VertexRun run;
|
||||
|
@ -2697,6 +2705,25 @@ void merge_groups(std::vector<tfrag3::StripDraw::VisGroup>& grps) {
|
|||
std::swap(result, grps);
|
||||
}
|
||||
|
||||
void merge_groups(std::vector<tfrag3::PackedTieVertices::MatrixGroup>& grps) {
|
||||
std::vector<tfrag3::PackedTieVertices::MatrixGroup> result;
|
||||
result.push_back(grps.at(0));
|
||||
|
||||
for (size_t i = 1; i < grps.size(); i++) {
|
||||
auto& this_group = grps[i];
|
||||
auto& maybe_merge = result.back();
|
||||
if (this_group.start_vert == maybe_merge.end_vert &&
|
||||
this_group.matrix_idx == maybe_merge.matrix_idx &&
|
||||
this_group.has_normals == maybe_merge.has_normals) {
|
||||
maybe_merge.end_vert = this_group.end_vert;
|
||||
} else {
|
||||
result.push_back(this_group);
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(result, grps);
|
||||
}
|
||||
|
||||
void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
const std::string& debug_name,
|
||||
const std::vector<level_tools::TextureRemap>& tex_map,
|
||||
|
@ -2798,6 +2825,8 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
|
|||
merge_groups(draw.instance_groups);
|
||||
}
|
||||
|
||||
merge_groups(this_tree.packed_vertices.matrix_groups);
|
||||
|
||||
this_tree.colors = full_palette.colors;
|
||||
out.tie_trees[geo].push_back(std::move(this_tree));
|
||||
}
|
||||
|
|
|
@ -30,9 +30,10 @@ set(RUNTIME_SOURCE
|
|||
graphics/opengl_renderer/foreground/Generic2_DMA.cpp
|
||||
graphics/opengl_renderer/foreground/Generic2_OpenGL.cpp
|
||||
graphics/opengl_renderer/foreground/Generic2.cpp
|
||||
graphics/opengl_renderer/foreground/Generic2BucketRenderer.cpp
|
||||
graphics/opengl_renderer/foreground/Merc2.cpp
|
||||
graphics/opengl_renderer/foreground/Merc2BucketRenderer.cpp
|
||||
graphics/opengl_renderer/foreground/Shadow2.cpp
|
||||
graphics/opengl_renderer/LightningRenderer.cpp
|
||||
graphics/opengl_renderer/loader/Loader.cpp
|
||||
graphics/opengl_renderer/loader/LoaderStages.cpp
|
||||
graphics/opengl_renderer/ocean/CommonOceanRenderer.cpp
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
#include "LightningRenderer.h"
|
||||
|
||||
LightningRenderer::LightningRenderer(const std::string& name, int id)
|
||||
: BucketRenderer(name, id), m_generic(name, id) {}
|
||||
|
||||
LightningRenderer::~LightningRenderer() {}
|
||||
|
||||
void LightningRenderer::draw_debug_window() {
|
||||
m_generic.draw_debug_window();
|
||||
}
|
||||
|
||||
void LightningRenderer::render(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
m_generic.render_in_mode(dma, render_state, prof, Generic2::Mode::LIGHTNING);
|
||||
}
|
||||
|
||||
void LightningRenderer::init_shaders(ShaderLibrary& shaders) {
|
||||
m_generic.init_shaders(shaders);
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Generic2.h"
|
||||
|
||||
class LightningRenderer : public BucketRenderer {
|
||||
public:
|
||||
LightningRenderer(const std::string& name, int id);
|
||||
~LightningRenderer();
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
void init_shaders(ShaderLibrary& shaders) override;
|
||||
|
||||
private:
|
||||
Generic2 m_generic;
|
||||
};
|
|
@ -8,7 +8,6 @@
|
|||
#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/LightningRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/ProgressRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/ShadowRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/SkyRenderer.h"
|
||||
|
@ -19,7 +18,8 @@
|
|||
#include "game/graphics/opengl_renderer/background/TFragment.h"
|
||||
#include "game/graphics/opengl_renderer/background/Tie3.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Generic2.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Merc2.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Generic2BucketRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Merc2BucketRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Shadow2.h"
|
||||
#include "game/graphics/opengl_renderer/ocean/OceanMidAndFar.h"
|
||||
#include "game/graphics/opengl_renderer/ocean/OceanNear.h"
|
||||
|
@ -78,7 +78,11 @@ OpenGLRenderer::OpenGLRenderer(std::shared_ptr<TexturePool> texture_pool,
|
|||
|
||||
lg::debug("OpenGL context information: {}", (const char*)glGetString(GL_VERSION));
|
||||
|
||||
m_merc2 = std::make_shared<Merc2>(m_render_state.shaders);
|
||||
m_generic2 = std::make_shared<Generic2>(m_render_state.shaders);
|
||||
|
||||
// initialize all renderers
|
||||
auto p = scoped_prof("init-bucket-renderers");
|
||||
switch (m_version) {
|
||||
case GameVersion::Jak1:
|
||||
init_bucket_renderers_jak1();
|
||||
|
@ -121,12 +125,13 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
fmt::format("etie-l{}-tfrag", i), BucketCategory::TIE,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_L0_TFRAG, BucketId::ETIE_L1_TFRAG, i), tie,
|
||||
tfrag3::TieCategory::NORMAL_ENVMAP);
|
||||
init_bucket_renderer<Merc2>(
|
||||
init_bucket_renderer<Merc2BucketRenderer>(
|
||||
fmt::format("merc-l{}-tfrag", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_TFRAG, BucketId::MERC_L1_TFRAG, i));
|
||||
init_bucket_renderer<Generic2>(
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_TFRAG, BucketId::MERC_L1_TFRAG, i), m_merc2);
|
||||
init_bucket_renderer<Generic2BucketRenderer>(
|
||||
fmt::format("gmerc-l{}-tfrag", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_TFRAG, BucketId::GMERC_L1_TFRAG, i));
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_TFRAG, BucketId::GMERC_L1_TFRAG, i), m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
init_bucket_renderer<TextureUploadHandler>(
|
||||
fmt::format("tex-l{}-shrub", i), BucketCategory::TEX,
|
||||
|
@ -134,12 +139,13 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
init_bucket_renderer<Shrub>(
|
||||
fmt::format("shrub-l{}-shrub", i), BucketCategory::SHRUB,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::SHRUB_L0_SHRUB, BucketId::SHRUB_L1_SHRUB, i));
|
||||
init_bucket_renderer<Merc2>(
|
||||
init_bucket_renderer<Merc2BucketRenderer>(
|
||||
fmt::format("merc-l{}-shrub", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_SHRUB, BucketId::MERC_L1_SHRUB, i));
|
||||
init_bucket_renderer<Generic2>(
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_SHRUB, BucketId::MERC_L1_SHRUB, i), m_merc2);
|
||||
init_bucket_renderer<Generic2BucketRenderer>(
|
||||
fmt::format("gmerc-l{}-shrub", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_SHRUB, BucketId::GMERC_L1_SHRUB, i));
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_SHRUB, BucketId::GMERC_L1_SHRUB, i), m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
init_bucket_renderer<TextureUploadHandler>(
|
||||
fmt::format("tex-l{}-alpha", i), BucketCategory::TEX,
|
||||
|
@ -156,42 +162,46 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
fmt::format("etie-t-l{}-alpha", i), BucketCategory::TIE,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_T_L0_ALPHA, BucketId::ETIE_T_L1_ALPHA, i), tie,
|
||||
tfrag3::TieCategory::TRANS_ENVMAP);
|
||||
init_bucket_renderer<Merc2>(
|
||||
init_bucket_renderer<Merc2BucketRenderer>(
|
||||
fmt::format("merc-l{}-alpha", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_ALPHA, BucketId::MERC_L1_ALPHA, i));
|
||||
init_bucket_renderer<Generic2>(
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_ALPHA, BucketId::MERC_L1_ALPHA, i), m_merc2);
|
||||
init_bucket_renderer<Generic2BucketRenderer>(
|
||||
fmt::format("gmerc-l{}-alpha", i), BucketCategory::GENERIC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_ALPHA, BucketId::GMERC_L1_ALPHA, i));
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_ALPHA, BucketId::GMERC_L1_ALPHA, i), m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
init_bucket_renderer<TextureUploadHandler>(
|
||||
fmt::format("tex-l{}-pris", i), BucketCategory::TEX,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TEX_L0_PRIS, BucketId::TEX_L1_PRIS, i));
|
||||
init_bucket_renderer<Merc2>(
|
||||
init_bucket_renderer<Merc2BucketRenderer>(
|
||||
fmt::format("merc-l{}-pris", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_PRIS, BucketId::MERC_L1_PRIS, i));
|
||||
init_bucket_renderer<Generic2>(
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_PRIS, BucketId::MERC_L1_PRIS, i), m_merc2);
|
||||
init_bucket_renderer<Generic2BucketRenderer>(
|
||||
fmt::format("gmerc-l{}-pris", i), BucketCategory::GENERIC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_PRIS, BucketId::GMERC_L1_PRIS, i));
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_PRIS, BucketId::GMERC_L1_PRIS, i), m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
init_bucket_renderer<TextureUploadHandler>(
|
||||
fmt::format("tex-l{}-pris2", i), BucketCategory::TEX,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TEX_L0_PRIS2, BucketId::TEX_L1_PRIS2, i));
|
||||
init_bucket_renderer<Merc2>(
|
||||
init_bucket_renderer<Merc2BucketRenderer>(
|
||||
fmt::format("merc-l{}-pris2", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_PRIS2, BucketId::MERC_L1_PRIS2, i));
|
||||
init_bucket_renderer<Generic2>(
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_PRIS2, BucketId::MERC_L1_PRIS2, i), m_merc2);
|
||||
init_bucket_renderer<Generic2BucketRenderer>(
|
||||
fmt::format("gmerc-l{}-pris2", i), BucketCategory::GENERIC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_PRIS2, BucketId::GMERC_L1_PRIS2, i));
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_PRIS2, BucketId::GMERC_L1_PRIS2, i), m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
init_bucket_renderer<TextureUploadHandler>(
|
||||
fmt::format("tex-l{}-water", i), BucketCategory::TEX,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TEX_L0_WATER, BucketId::TEX_L1_WATER, i));
|
||||
init_bucket_renderer<Merc2>(
|
||||
init_bucket_renderer<Merc2BucketRenderer>(
|
||||
fmt::format("merc-l{}-water", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_WATER, BucketId::MERC_L1_WATER, i));
|
||||
init_bucket_renderer<Generic2>(
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_WATER, BucketId::MERC_L1_WATER, i), m_merc2);
|
||||
init_bucket_renderer<Generic2BucketRenderer>(
|
||||
fmt::format("gmerc-l{}-water", i), BucketCategory::GENERIC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_WATER, BucketId::GMERC_L1_WATER, i));
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_WATER, BucketId::GMERC_L1_WATER, i), m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
init_bucket_renderer<TFragment>(
|
||||
fmt::format("tfrag-w-l{}-alpha", i), BucketCategory::TFRAG,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TFRAG_W_L0_WATER, BucketId::TFRAG_W_L1_WATER, i),
|
||||
|
@ -209,21 +219,26 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
// 180
|
||||
init_bucket_renderer<TextureUploadHandler>("tex-lcom-tfrag", BucketCategory::TEX,
|
||||
BucketId::TEX_LCOM_TFRAG);
|
||||
init_bucket_renderer<Merc2>("merc-lcom-tfrag", BucketCategory::MERC, BucketId::MERC_LCOM_TFRAG);
|
||||
init_bucket_renderer<Merc2BucketRenderer>("merc-lcom-tfrag", BucketCategory::MERC,
|
||||
BucketId::MERC_LCOM_TFRAG, m_merc2);
|
||||
// 190
|
||||
init_bucket_renderer<TextureUploadHandler>("tex-lcom-shrub", BucketCategory::TEX,
|
||||
BucketId::TEX_LCOM_SHRUB);
|
||||
init_bucket_renderer<Merc2>("merc-lcom-shrub", BucketCategory::MERC, BucketId::MERC_LCOM_SHRUB);
|
||||
init_bucket_renderer<Generic2>("gmerc-lcom-tfrag", BucketCategory::GENERIC,
|
||||
BucketId::GMERC_LCOM_TFRAG);
|
||||
init_bucket_renderer<Merc2BucketRenderer>("merc-lcom-shrub", BucketCategory::MERC,
|
||||
BucketId::MERC_LCOM_SHRUB, m_merc2);
|
||||
init_bucket_renderer<Generic2BucketRenderer>("gmerc-lcom-tfrag", BucketCategory::GENERIC,
|
||||
BucketId::GMERC_LCOM_TFRAG, m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
init_bucket_renderer<Shadow2>("shadow", BucketCategory::OTHER, BucketId::SHADOW);
|
||||
// 220
|
||||
init_bucket_renderer<TextureUploadHandler>("tex-lcom-pris", BucketCategory::TEX,
|
||||
BucketId::TEX_LCOM_PRIS);
|
||||
init_bucket_renderer<Merc2>("merc-lcom-pris", BucketCategory::MERC, BucketId::MERC_LCOM_PRIS);
|
||||
init_bucket_renderer<Merc2BucketRenderer>("merc-lcom-pris", BucketCategory::MERC,
|
||||
BucketId::MERC_LCOM_PRIS, m_merc2);
|
||||
init_bucket_renderer<TextureUploadHandler>("tex-lcom-water", BucketCategory::TEX,
|
||||
BucketId::TEX_LCOM_WATER);
|
||||
init_bucket_renderer<Merc2>("merc-lcom-water", BucketCategory::MERC, BucketId::MERC_LCOM_WATER);
|
||||
init_bucket_renderer<Merc2BucketRenderer>("merc-lcom-water", BucketCategory::MERC,
|
||||
BucketId::MERC_LCOM_WATER, m_merc2);
|
||||
init_bucket_renderer<TextureUploadHandler>("tex-lcom-sky-post", BucketCategory::TEX,
|
||||
BucketId::TEX_LCOM_SKY_POST);
|
||||
// 310
|
||||
|
@ -232,10 +247,11 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
BucketId::TEX_ALL_SPRITE);
|
||||
init_bucket_renderer<Sprite3>("particles", BucketCategory::SPRITE, BucketId::PARTICLES);
|
||||
init_bucket_renderer<Shadow2>("shadow2", BucketCategory::OTHER, BucketId::SHADOW2);
|
||||
init_bucket_renderer<LightningRenderer>("effects", BucketCategory::OTHER, BucketId::EFFECTS);
|
||||
init_bucket_renderer<Generic2BucketRenderer>("effects", BucketCategory::OTHER, BucketId::EFFECTS,
|
||||
m_generic2, Generic2::Mode::LIGHTNING);
|
||||
init_bucket_renderer<TextureUploadHandler>("tex-all-warp", BucketCategory::TEX,
|
||||
BucketId::TEX_ALL_WARP);
|
||||
init_bucket_renderer<Warp>("warp", BucketCategory::GENERIC, BucketId::GMERC_WARP);
|
||||
init_bucket_renderer<Warp>("warp", BucketCategory::GENERIC, BucketId::GMERC_WARP, m_generic2);
|
||||
init_bucket_renderer<DirectRenderer>("debug-no-zbuf1", BucketCategory::OTHER,
|
||||
BucketId::DEBUG_NO_ZBUF1, 0x8000);
|
||||
init_bucket_renderer<TextureUploadHandler>("tex-all-map", BucketCategory::TEX,
|
||||
|
@ -256,20 +272,23 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
m_render_state.eye_renderer = eye_renderer.get();
|
||||
m_jak2_eye_renderer = std::move(eye_renderer);
|
||||
|
||||
// for now, for any unset renderers, just set them to an EmptyBucketRenderer.
|
||||
for (size_t i = 0; i < m_bucket_renderers.size(); i++) {
|
||||
if (!m_bucket_renderers[i]) {
|
||||
init_bucket_renderer<EmptyBucketRenderer>(fmt::format("bucket-{}", i), BucketCategory::OTHER,
|
||||
i);
|
||||
}
|
||||
{
|
||||
auto p = scoped_prof("render-inits");
|
||||
// for now, for any unset renderers, just set them to an EmptyBucketRenderer.
|
||||
for (size_t i = 0; i < m_bucket_renderers.size(); i++) {
|
||||
if (!m_bucket_renderers[i]) {
|
||||
init_bucket_renderer<EmptyBucketRenderer>(fmt::format("bucket-{}", i),
|
||||
BucketCategory::OTHER, i);
|
||||
}
|
||||
|
||||
m_bucket_renderers[i]->init_shaders(m_render_state.shaders);
|
||||
m_bucket_renderers[i]->init_textures(*m_render_state.texture_pool, GameVersion::Jak2);
|
||||
m_bucket_renderers[i]->init_shaders(m_render_state.shaders);
|
||||
m_bucket_renderers[i]->init_textures(*m_render_state.texture_pool, GameVersion::Jak2);
|
||||
}
|
||||
m_jak2_eye_renderer->init_shaders(m_render_state.shaders);
|
||||
m_jak2_eye_renderer->init_textures(*m_render_state.texture_pool, GameVersion::Jak2);
|
||||
}
|
||||
|
||||
m_jak2_eye_renderer->init_shaders(m_render_state.shaders);
|
||||
m_jak2_eye_renderer->init_textures(*m_render_state.texture_pool, GameVersion::Jak2);
|
||||
|
||||
auto p = scoped_prof("load-common");
|
||||
m_render_state.loader->load_common(*m_render_state.texture_pool, "GAME");
|
||||
}
|
||||
/*!
|
||||
|
@ -314,11 +333,12 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
|
|||
init_bucket_renderer<Tie3WithEnvmapJak1>("l0-tfrag-tie", BucketCategory::TIE,
|
||||
BucketId::TIE_LEVEL0, 0);
|
||||
// 10 : MERC_TFRAG_TEX_LEVEL0
|
||||
init_bucket_renderer<Merc2>("l0-tfrag-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL0);
|
||||
init_bucket_renderer<Merc2BucketRenderer>("l0-tfrag-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL0, m_merc2);
|
||||
// 11 : GMERC_TFRAG_TEX_LEVEL0
|
||||
init_bucket_renderer<Generic2>("l0-tfrag-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_TFRAG_TEX_LEVEL0, 1500000, 10000, 10000, 800);
|
||||
init_bucket_renderer<Generic2BucketRenderer>("l0-tfrag-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_TFRAG_TEX_LEVEL0, m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 1 tfrag texture
|
||||
|
@ -335,11 +355,12 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
|
|||
init_bucket_renderer<Tie3WithEnvmapJak1>("l1-tfrag-tie", BucketCategory::TIE,
|
||||
BucketId::TIE_LEVEL1, 1);
|
||||
// 17 : MERC_TFRAG_TEX_LEVEL1
|
||||
init_bucket_renderer<Merc2>("l1-tfrag-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL1);
|
||||
init_bucket_renderer<Merc2BucketRenderer>("l1-tfrag-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL1, m_merc2);
|
||||
// 18 : GMERC_TFRAG_TEX_LEVEL1
|
||||
init_bucket_renderer<Generic2>("l1-tfrag-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_TFRAG_TEX_LEVEL1, 1500000, 10000, 10000, 800);
|
||||
init_bucket_renderer<Generic2BucketRenderer>("l1-tfrag-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_TFRAG_TEX_LEVEL1, m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 0 shrub texture
|
||||
|
@ -353,8 +374,9 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
|
|||
// 22 : SHRUB_BILLBOARD_LEVEL0
|
||||
// 23 : SHRUB_TRANS_LEVEL0
|
||||
// 24 : SHRUB_GENERIC_LEVEL0
|
||||
init_bucket_renderer<Generic2>("l0-shrub-generic", BucketCategory::GENERIC,
|
||||
BucketId::SHRUB_GENERIC_LEVEL0);
|
||||
init_bucket_renderer<Generic2BucketRenderer>("l0-shrub-generic", BucketCategory::GENERIC,
|
||||
BucketId::SHRUB_GENERIC_LEVEL0, m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 1 shrub texture
|
||||
|
@ -368,8 +390,9 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
|
|||
// 28 : SHRUB_BILLBOARD_LEVEL1
|
||||
// 29 : SHRUB_TRANS_LEVEL1
|
||||
// 30 : SHRUB_GENERIC_LEVEL1
|
||||
init_bucket_renderer<Generic2>("l1-shrub-generic", BucketCategory::GENERIC,
|
||||
BucketId::SHRUB_GENERIC_LEVEL1);
|
||||
init_bucket_renderer<Generic2BucketRenderer>("l1-shrub-generic", BucketCategory::GENERIC,
|
||||
BucketId::SHRUB_GENERIC_LEVEL1, m_generic2,
|
||||
Generic2::Mode::NORMAL);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 0 alpha texture
|
||||
|
@ -405,11 +428,12 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
|
|||
BucketId::TFRAG_ICE_LEVEL1, ice_tfrags, false, 1);
|
||||
// 44
|
||||
|
||||
init_bucket_renderer<Merc2>("common-alpha-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_AFTER_ALPHA);
|
||||
init_bucket_renderer<Merc2BucketRenderer>("common-alpha-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_AFTER_ALPHA, m_merc2);
|
||||
|
||||
init_bucket_renderer<Generic2>("common-alpha-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_ALPHA); // 46
|
||||
init_bucket_renderer<Generic2BucketRenderer>("common-alpha-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_ALPHA, m_generic2,
|
||||
Generic2::Mode::NORMAL); // 46
|
||||
init_bucket_renderer<ShadowRenderer>("shadow", BucketCategory::OTHER, BucketId::SHADOW); // 47
|
||||
|
||||
//-----------------------
|
||||
|
@ -417,50 +441,55 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
|
|||
//-----------------------
|
||||
init_bucket_renderer<TextureUploadHandler>("l0-pris-tex", BucketCategory::TEX,
|
||||
BucketId::PRIS_TEX_LEVEL0); // 48
|
||||
init_bucket_renderer<Merc2>("l0-pris-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_PRIS_LEVEL0); // 49
|
||||
init_bucket_renderer<Generic2>("l0-pris-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_PRIS_LEVEL0); // 50
|
||||
init_bucket_renderer<Merc2BucketRenderer>("l0-pris-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_PRIS_LEVEL0, m_merc2); // 49
|
||||
init_bucket_renderer<Generic2BucketRenderer>("l0-pris-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_PRIS_LEVEL0, m_generic2,
|
||||
Generic2::Mode::NORMAL); // 50
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 1 pris texture
|
||||
//-----------------------
|
||||
init_bucket_renderer<TextureUploadHandler>("l1-pris-tex", BucketCategory::TEX,
|
||||
BucketId::PRIS_TEX_LEVEL1); // 51
|
||||
init_bucket_renderer<Merc2>("l1-pris-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_PRIS_LEVEL1); // 52
|
||||
init_bucket_renderer<Generic2>("l1-pris-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_PRIS_LEVEL1); // 53
|
||||
init_bucket_renderer<Merc2BucketRenderer>("l1-pris-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_PRIS_LEVEL1, m_merc2); // 52
|
||||
init_bucket_renderer<Generic2BucketRenderer>("l1-pris-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_PRIS_LEVEL1, m_generic2,
|
||||
Generic2::Mode::NORMAL); // 53
|
||||
|
||||
// other renderers may output to the eye renderer
|
||||
m_render_state.eye_renderer = init_bucket_renderer<EyeRenderer>(
|
||||
"common-pris-eyes", BucketCategory::OTHER, BucketId::MERC_EYES_AFTER_PRIS); // 54
|
||||
|
||||
// hack: set to merc2 for debugging
|
||||
init_bucket_renderer<Merc2>("common-pris-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_AFTER_PRIS); // 55
|
||||
init_bucket_renderer<Generic2>("common-pris-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_PRIS); // 56
|
||||
init_bucket_renderer<Merc2BucketRenderer>("common-pris-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_AFTER_PRIS, m_merc2); // 55
|
||||
init_bucket_renderer<Generic2BucketRenderer>("common-pris-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_PRIS, m_generic2,
|
||||
Generic2::Mode::NORMAL); // 56
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 0 water texture
|
||||
//-----------------------
|
||||
init_bucket_renderer<TextureUploadHandler>("l0-water-tex", BucketCategory::TEX,
|
||||
BucketId::WATER_TEX_LEVEL0); // 57
|
||||
init_bucket_renderer<Merc2>("l0-water-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_WATER_LEVEL0); // 58
|
||||
init_bucket_renderer<Generic2>("l0-water-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_WATER_LEVEL0); // 59
|
||||
init_bucket_renderer<Merc2BucketRenderer>("l0-water-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_WATER_LEVEL0, m_merc2); // 58
|
||||
init_bucket_renderer<Generic2BucketRenderer>("l0-water-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_WATER_LEVEL0, m_generic2,
|
||||
Generic2::Mode::NORMAL); // 59
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 1 water texture
|
||||
//-----------------------
|
||||
init_bucket_renderer<TextureUploadHandler>("l1-water-tex", BucketCategory::TEX,
|
||||
BucketId::WATER_TEX_LEVEL1); // 60
|
||||
init_bucket_renderer<Merc2>("l1-water-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_WATER_LEVEL1); // 61
|
||||
init_bucket_renderer<Generic2>("l1-water-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_WATER_LEVEL1); // 62
|
||||
init_bucket_renderer<Merc2BucketRenderer>("l1-water-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_WATER_LEVEL1, m_merc2); // 61
|
||||
init_bucket_renderer<Generic2BucketRenderer>("l1-water-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_WATER_LEVEL1, m_generic2,
|
||||
Generic2::Mode::NORMAL); // 62
|
||||
|
||||
init_bucket_renderer<OceanNear>("ocean-near", BucketCategory::OCEAN, BucketId::OCEAN_NEAR); // 63
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "game/graphics/opengl_renderer/CollideMeshRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/Profiler.h"
|
||||
#include "game/graphics/opengl_renderer/Shader.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Generic2.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Merc2.h"
|
||||
#include "game/graphics/opengl_renderer/opengl_utils.h"
|
||||
#include "game/tools/filter_menu/filter_menu.h"
|
||||
#include "game/tools/subtitles/subtitle_editor.h"
|
||||
|
@ -146,6 +148,8 @@ class OpenGLRenderer {
|
|||
Subtitle2Editor* m_subtitle2_editor = nullptr;
|
||||
FiltersMenu m_filters_menu;
|
||||
|
||||
std::shared_ptr<Merc2> m_merc2;
|
||||
std::shared_ptr<Generic2> m_generic2;
|
||||
std::vector<std::unique_ptr<BucketRenderer>> m_bucket_renderers;
|
||||
std::vector<BucketCategory> m_bucket_categories;
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#include "Warp.h"
|
||||
|
||||
Warp::Warp(const std::string& name, int id) : BucketRenderer(name, id), m_generic(name, id) {}
|
||||
|
||||
Warp::~Warp() {}
|
||||
Warp::Warp(const std::string& name, int id, std::shared_ptr<Generic2> generic)
|
||||
: BucketRenderer(name, id), m_generic(generic) {}
|
||||
|
||||
void Warp::draw_debug_window() {
|
||||
m_generic.draw_debug_window();
|
||||
m_generic->draw_debug_window();
|
||||
}
|
||||
|
||||
void Warp::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
|
@ -13,11 +12,7 @@ void Warp::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfi
|
|||
render_state->render_fb_x, render_state->render_fb_y,
|
||||
render_state->render_fb);
|
||||
render_state->texture_pool->move_existing_to_vram(m_warp_src_tex, m_tbp);
|
||||
m_generic.render_in_mode(dma, render_state, prof, Generic2::Mode::NORMAL);
|
||||
}
|
||||
|
||||
void Warp::init_shaders(ShaderLibrary& shaders) {
|
||||
m_generic.init_shaders(shaders);
|
||||
m_generic->render_in_mode(dma, render_state, prof, Generic2::Mode::NORMAL);
|
||||
}
|
||||
|
||||
void Warp::init_textures(TexturePool& tex_pool, GameVersion version) {
|
||||
|
@ -30,6 +25,4 @@ void Warp::init_textures(TexturePool& tex_pool, GameVersion version) {
|
|||
in.debug_name = "PC-WARP";
|
||||
in.id = tex_pool.allocate_pc_port_texture(version);
|
||||
m_warp_src_tex = tex_pool.give_texture_and_load_to_vram(in, m_tbp);
|
||||
|
||||
m_generic.init_textures(tex_pool, version);
|
||||
}
|
|
@ -7,15 +7,13 @@
|
|||
|
||||
class Warp : public BucketRenderer {
|
||||
public:
|
||||
Warp(const std::string& name, int id);
|
||||
~Warp();
|
||||
Warp(const std::string& name, int id, std::shared_ptr<Generic2> generic);
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
void init_shaders(ShaderLibrary& shaders) override;
|
||||
void init_textures(TexturePool& tex_pool, GameVersion version) override;
|
||||
|
||||
private:
|
||||
Generic2 m_generic;
|
||||
std::shared_ptr<Generic2> m_generic;
|
||||
FramebufferCopier m_fb_copier;
|
||||
GpuTexture* m_warp_src_tex = nullptr;
|
||||
u32 m_tbp = 1216; // hack, jak 2
|
||||
|
|
|
@ -4,20 +4,18 @@
|
|||
|
||||
#include "third-party/imgui/imgui.h"
|
||||
|
||||
Generic2::Generic2(const std::string& name,
|
||||
int my_id,
|
||||
Generic2::Generic2(ShaderLibrary& shaders,
|
||||
u32 num_verts,
|
||||
u32 num_frags,
|
||||
u32 num_adgif,
|
||||
u32 num_buckets)
|
||||
: BucketRenderer(name, my_id) {
|
||||
u32 num_buckets) {
|
||||
m_verts.resize(num_verts);
|
||||
m_fragments.resize(num_frags);
|
||||
m_adgifs.resize(num_adgif);
|
||||
m_buckets.resize(num_buckets);
|
||||
m_indices.resize(num_verts * 3);
|
||||
|
||||
opengl_setup();
|
||||
opengl_setup(shaders);
|
||||
}
|
||||
|
||||
Generic2::~Generic2() {
|
||||
|
@ -52,28 +50,10 @@ void Generic2::draw_debug_window() {
|
|||
* generic renderer. This renderer is expected to follow the chain until it reaches "next_bucket"
|
||||
* and then return.
|
||||
*/
|
||||
void Generic2::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
render_in_mode(dma, render_state, prof, Mode::NORMAL);
|
||||
}
|
||||
|
||||
void Generic2::render_in_mode(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
Mode mode) {
|
||||
// completely clear out state. These will get populated by the rendering functions, then displayed
|
||||
// by draw_debug_window() if the user opens that window
|
||||
m_debug.clear();
|
||||
m_stats = Stats();
|
||||
|
||||
// if the user has asked to disable the renderer, just advance the dma follower to the next
|
||||
// bucket and return immediately.
|
||||
if (!m_enabled) {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Generic2 has 3 passes.
|
||||
{
|
||||
// our first pass is to go over the DMA chain from the game and extract the data into buffers
|
||||
|
|
|
@ -2,16 +2,14 @@
|
|||
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
|
||||
class Generic2 : public BucketRenderer {
|
||||
class Generic2 {
|
||||
public:
|
||||
Generic2(const std::string& name,
|
||||
int my_id,
|
||||
u32 num_verts = 200000,
|
||||
u32 num_frags = 2000,
|
||||
u32 num_adgif = 6000,
|
||||
Generic2(ShaderLibrary& shaders,
|
||||
u32 num_verts = 500000,
|
||||
u32 num_frags = 10000,
|
||||
u32 num_adgif = 10000,
|
||||
u32 num_buckets = 800);
|
||||
~Generic2();
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
|
||||
enum class Mode { NORMAL, LIGHTNING };
|
||||
|
||||
|
@ -20,8 +18,7 @@ class Generic2 : public BucketRenderer {
|
|||
ScopedProfilerNode& prof,
|
||||
Mode mode);
|
||||
|
||||
void draw_debug_window() override;
|
||||
void init_shaders(ShaderLibrary& shaders) override;
|
||||
void draw_debug_window();
|
||||
|
||||
struct Vertex {
|
||||
math::Vector<float, 3> xyz;
|
||||
|
@ -56,7 +53,7 @@ class Generic2 : public BucketRenderer {
|
|||
void final_vertex_update();
|
||||
bool handle_bucket_setup_dma(DmaFollower& dma, u32 next_bucket);
|
||||
|
||||
void opengl_setup();
|
||||
void opengl_setup(ShaderLibrary& shaders);
|
||||
void opengl_cleanup();
|
||||
void opengl_bind_and_setup_proj(SharedRenderState* render_state);
|
||||
void setup_opengl_for_draw_mode(const DrawMode& draw_mode,
|
||||
|
@ -193,12 +190,6 @@ class Generic2 : public BucketRenderer {
|
|||
ASSERT(m_next_free_vert < m_verts.size());
|
||||
}
|
||||
|
||||
std::string m_debug;
|
||||
|
||||
struct Stats {
|
||||
u32 dma_tags = 0;
|
||||
} m_stats;
|
||||
|
||||
static constexpr int ALPHA_MODE_COUNT = 7;
|
||||
bool m_alpha_draw_enable[ALPHA_MODE_COUNT] = {true, true, true, true, true, true, true};
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#include "Generic2BucketRenderer.h"
|
||||
|
||||
Generic2BucketRenderer::Generic2BucketRenderer(const std::string& name,
|
||||
int id,
|
||||
std::shared_ptr<Generic2> renderer,
|
||||
Generic2::Mode mode)
|
||||
: BucketRenderer(name, id), m_generic(renderer), m_mode(mode) {}
|
||||
|
||||
void Generic2BucketRenderer::draw_debug_window() {
|
||||
m_generic->draw_debug_window();
|
||||
}
|
||||
|
||||
void Generic2BucketRenderer::render(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
// if the user has asked to disable the renderer, just advance the dma follower to the next
|
||||
// bucket and return immediately.
|
||||
if (!m_enabled) {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
m_generic->render_in_mode(dma, render_state, prof, m_mode);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Generic2.h"
|
||||
|
||||
class Generic2BucketRenderer : public BucketRenderer {
|
||||
public:
|
||||
Generic2BucketRenderer(const std::string& name,
|
||||
int id,
|
||||
std::shared_ptr<Generic2> renderer,
|
||||
Generic2::Mode mode);
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Generic2> m_generic;
|
||||
Generic2::Mode m_mode;
|
||||
};
|
|
@ -16,12 +16,10 @@ bool Generic2::check_for_end_of_generic_data(DmaFollower& dma, u32 next_bucket)
|
|||
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dma.read_and_advance();
|
||||
m_stats.dma_tags++;
|
||||
}
|
||||
ASSERT(dma.current_tag_offset() == next_bucket);
|
||||
return true;
|
||||
}
|
||||
m_stats.dma_tags++;
|
||||
dma.read_and_advance();
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "Generic2.h"
|
||||
|
||||
void Generic2::opengl_setup() {
|
||||
void Generic2::opengl_setup(ShaderLibrary& shaders) {
|
||||
// create OpenGL objects
|
||||
glGenBuffers(1, &m_ogl.vertex_buffer);
|
||||
glGenBuffers(1, &m_ogl.index_buffer);
|
||||
|
@ -56,15 +56,7 @@ void Generic2::opengl_setup() {
|
|||
|
||||
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();
|
||||
|
||||
|
@ -83,6 +75,12 @@ void Generic2::init_shaders(ShaderLibrary& shaders) {
|
|||
m_ogl.warp_sample_mode = glGetUniformLocation(id, "warp_sample_mode");
|
||||
}
|
||||
|
||||
void Generic2::opengl_cleanup() {
|
||||
glDeleteBuffers(1, &m_ogl.vertex_buffer);
|
||||
glDeleteBuffers(1, &m_ogl.index_buffer);
|
||||
glDeleteVertexArrays(1, &m_ogl.vao);
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -224,8 +222,7 @@ void Generic2::setup_opengl_tex(u16 unit,
|
|||
}
|
||||
|
||||
if (!tex) {
|
||||
lg::warn("Failed to find texture at {}, using random (generic2: {})", tbp_to_lookup,
|
||||
name_and_id());
|
||||
lg::warn("Failed to find texture at {}, using random (generic2)", tbp_to_lookup);
|
||||
tex = render_state->texture_pool->get_placeholder_texture();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
std::mutex g_merc_data_mutex;
|
||||
|
||||
Merc2::Merc2(const std::string& name, int my_id) : BucketRenderer(name, my_id) {
|
||||
Merc2::Merc2(ShaderLibrary& shaders) {
|
||||
// Set up main vertex array. This will point to the data stored in the .FR3 level file, and will
|
||||
// be uploaded to the GPU by the Loader.
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
|
@ -93,6 +93,10 @@ Merc2::Merc2(const std::string& name, int my_id) : BucketRenderer(name, my_id) {
|
|||
for (auto& x : m_effect_debug_mask) {
|
||||
x = true;
|
||||
}
|
||||
|
||||
init_shader_common(shaders[ShaderId::MERC2], &m_merc_uniforms, true);
|
||||
init_shader_common(shaders[ShaderId::EMERC], &m_emerc_uniforms, false);
|
||||
m_emerc_uniforms.fade = glGetUniformLocation(shaders[ShaderId::EMERC].id(), "fade");
|
||||
}
|
||||
|
||||
Merc2::~Merc2() {
|
||||
|
@ -161,7 +165,8 @@ void Merc2::model_mod_blerc_draws(int num_effects,
|
|||
const tfrag3::MercModel* model,
|
||||
const LevelData* lev,
|
||||
ModBuffers* mod_opengl_buffers,
|
||||
const float* blerc_weights) {
|
||||
const float* blerc_weights,
|
||||
MercDebugStats* stats) {
|
||||
// loop over effects.
|
||||
for (int ei = 0; ei < num_effects; ei++) {
|
||||
const auto& effect = model->effects[ei];
|
||||
|
@ -192,8 +197,8 @@ void Merc2::model_mod_blerc_draws(int num_effects,
|
|||
blerc_avx(i_data, i_data_end, f_data, blerc_weights, m_mod_vtx_temp.data(), blerc_multiplier);
|
||||
|
||||
// and upload to GPU
|
||||
m_stats.num_uploads++;
|
||||
m_stats.num_upload_bytes += effect.mod.vertices.size() * sizeof(tfrag3::MercVertex);
|
||||
stats->num_uploads++;
|
||||
stats->num_upload_bytes += effect.mod.vertices.size() * sizeof(tfrag3::MercVertex);
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, opengl_buffers.vertex);
|
||||
glBufferData(GL_ARRAY_BUFFER, effect.mod.vertices.size() * sizeof(tfrag3::MercVertex),
|
||||
|
@ -212,7 +217,8 @@ void Merc2::model_mod_draws(int num_effects,
|
|||
const LevelData* lev,
|
||||
const u8* input_data,
|
||||
const DmaTransfer& setup,
|
||||
ModBuffers* mod_opengl_buffers) {
|
||||
ModBuffers* mod_opengl_buffers,
|
||||
MercDebugStats* stats) {
|
||||
auto p = scoped_prof("update-verts");
|
||||
|
||||
// loop over effects. Mod vertices are done per effect (possibly a bad idea?)
|
||||
|
@ -368,8 +374,8 @@ void Merc2::model_mod_draws(int num_effects,
|
|||
}
|
||||
|
||||
// and upload to GPU
|
||||
m_stats.num_uploads++;
|
||||
m_stats.num_upload_bytes += effect.mod.vertices.size() * sizeof(tfrag3::MercVertex);
|
||||
stats->num_uploads++;
|
||||
stats->num_upload_bytes += effect.mod.vertices.size() * sizeof(tfrag3::MercVertex);
|
||||
{
|
||||
auto pp = scoped_prof("update-verts-upload");
|
||||
glBindBuffer(GL_ARRAY_BUFFER, opengl_buffers.vertex);
|
||||
|
@ -384,7 +390,8 @@ void Merc2::model_mod_draws(int num_effects,
|
|||
*/
|
||||
void Merc2::handle_pc_model(const DmaTransfer& setup,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& proff) {
|
||||
ScopedProfilerNode& proff,
|
||||
MercDebugStats* stats) {
|
||||
auto p = scoped_prof("init-pc");
|
||||
|
||||
// the format of the data is:
|
||||
|
@ -409,7 +416,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
auto model_ref = render_state->loader->get_merc_model(name);
|
||||
if (!model_ref) {
|
||||
// it can fail, if the game is faster than the loader. In this case, we just don't draw.
|
||||
m_stats.num_missing_models++;
|
||||
stats->num_missing_models++;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -420,7 +427,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
// each model uses only 1 light.
|
||||
if (m_next_free_light >= MAX_LIGHTS) {
|
||||
fmt::print("MERC2 out of lights, consider increasing MAX_LIGHTS\n");
|
||||
flush_draw_buckets(render_state, proff);
|
||||
flush_draw_buckets(render_state, proff, stats);
|
||||
}
|
||||
|
||||
// models use many bones. First check if we need to flush:
|
||||
|
@ -428,7 +435,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
if (m_next_free_bone_vector + m_opengl_buffer_alignment + bone_count * 8 >
|
||||
MAX_SHADER_BONE_VECTORS) {
|
||||
fmt::print("MERC2 out of bones, consider increasing MAX_SHADER_BONE_VECTORS\n");
|
||||
flush_draw_buckets(render_state, proff);
|
||||
flush_draw_buckets(render_state, proff, stats);
|
||||
}
|
||||
|
||||
// also sanity check that we have enough to draw the model
|
||||
|
@ -453,7 +460,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
if (m_next_free_level_bucket >= m_level_draw_buckets.size()) {
|
||||
// out of room, flush
|
||||
// fmt::print("MERC2 out of levels, consider increasing MAX_LEVELS\n");
|
||||
flush_draw_buckets(render_state, proff);
|
||||
flush_draw_buckets(render_state, proff, stats);
|
||||
}
|
||||
// alloc a new one
|
||||
lev_bucket = &m_level_draw_buckets[m_next_free_level_bucket++];
|
||||
|
@ -465,7 +472,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
if (lev_bucket->next_free_draw + model->max_draws >= lev_bucket->draws.size()) {
|
||||
// out of room, flush
|
||||
fmt::print("MERC2 out of draws, consider increasing MAX_DRAWS_PER_LEVEL\n");
|
||||
flush_draw_buckets(render_state, proff);
|
||||
flush_draw_buckets(render_state, proff, stats);
|
||||
if (model->max_draws >= lev_bucket->draws.size()) {
|
||||
ASSERT_NOT_REACHED_MSG("MERC2 draw buffer not big enough");
|
||||
}
|
||||
|
@ -475,7 +482,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
if (lev_bucket->next_free_envmap_draw + model->max_draws >= lev_bucket->envmap_draws.size()) {
|
||||
// out of room, flush
|
||||
fmt::print("MERC2 out of envmap draws, consider increasing MAX_ENVMAP_DRAWS_PER_LEVEL\n");
|
||||
flush_draw_buckets(render_state, proff);
|
||||
flush_draw_buckets(render_state, proff, stats);
|
||||
if (model->max_draws >= lev_bucket->envmap_draws.size()) {
|
||||
ASSERT_NOT_REACHED_MSG("MERC2 envmap draw buffer not big enough");
|
||||
}
|
||||
|
@ -550,31 +557,31 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
// will hold opengl buffers for the updated vertices
|
||||
ModBuffers mod_opengl_buffers[kMaxEffect];
|
||||
if (model_uses_pc_blerc) {
|
||||
model_mod_blerc_draws(num_effects, model, lev, mod_opengl_buffers, blerc_weights);
|
||||
model_mod_blerc_draws(num_effects, model, lev, mod_opengl_buffers, blerc_weights, stats);
|
||||
} else if (model_uses_mod) { // only if we've enabled, this path is slow.
|
||||
model_mod_draws(num_effects, model, lev, input_data, setup, mod_opengl_buffers);
|
||||
model_mod_draws(num_effects, model, lev, input_data, setup, mod_opengl_buffers, stats);
|
||||
}
|
||||
|
||||
// stats
|
||||
m_stats.num_models++;
|
||||
stats->num_models++;
|
||||
for (const auto& effect : model_ref->model->effects) {
|
||||
bool envmap = effect.has_envmap;
|
||||
m_stats.num_effects++;
|
||||
m_stats.num_predicted_draws += effect.all_draws.size();
|
||||
stats->num_effects++;
|
||||
stats->num_predicted_draws += effect.all_draws.size();
|
||||
if (envmap) {
|
||||
m_stats.num_envmap_effects++;
|
||||
m_stats.num_predicted_draws += effect.all_draws.size();
|
||||
stats->num_envmap_effects++;
|
||||
stats->num_predicted_draws += effect.all_draws.size();
|
||||
}
|
||||
for (const auto& draw : effect.all_draws) {
|
||||
m_stats.num_predicted_tris += draw.num_triangles;
|
||||
stats->num_predicted_tris += draw.num_triangles;
|
||||
if (envmap) {
|
||||
m_stats.num_predicted_tris += draw.num_triangles;
|
||||
stats->num_predicted_tris += draw.num_triangles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_debug_mode) {
|
||||
auto& d = m_debug.model_list.emplace_back();
|
||||
if (stats->collect_debug_model_list) {
|
||||
auto& d = stats->model_list.emplace_back();
|
||||
d.name = model->name;
|
||||
d.level = model_ref->level->level->level_name;
|
||||
for (auto& e : model->effects) {
|
||||
|
@ -594,6 +601,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
|
||||
// allocate lights
|
||||
u32 lights = alloc_lights(current_lights);
|
||||
stats->num_lights++;
|
||||
|
||||
// loop over effects, creating draws for each
|
||||
for (size_t ei = 0; ei < model->effects.size(); ei++) {
|
||||
|
@ -657,31 +665,31 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
|||
}
|
||||
}
|
||||
|
||||
void Merc2::draw_debug_window() {
|
||||
ImGui::Text("Models : %d", m_stats.num_models);
|
||||
ImGui::Text("Effects : %d", m_stats.num_effects);
|
||||
ImGui::Text("Draws (p): %d", m_stats.num_predicted_draws);
|
||||
ImGui::Text("Tris (p): %d", m_stats.num_predicted_tris);
|
||||
ImGui::Text("Bones : %d", m_stats.num_bones_uploaded);
|
||||
ImGui::Text("Lights : %d", m_stats.num_lights);
|
||||
ImGui::Text("Dflush : %d", m_stats.num_draw_flush);
|
||||
void Merc2::draw_debug_window(MercDebugStats* stats) {
|
||||
ImGui::Text("Models : %d", stats->num_models);
|
||||
ImGui::Text("Effects : %d", stats->num_effects);
|
||||
ImGui::Text("Draws (p): %d", stats->num_predicted_draws);
|
||||
ImGui::Text("Tris (p): %d", stats->num_predicted_tris);
|
||||
ImGui::Text("Bones : %d", stats->num_bones_uploaded);
|
||||
ImGui::Text("Lights : %d", stats->num_lights);
|
||||
ImGui::Text("Dflush : %d", stats->num_draw_flush);
|
||||
|
||||
ImGui::Text("EEffects : %d", m_stats.num_envmap_effects);
|
||||
ImGui::Text("ETris : %d", m_stats.num_envmap_tris);
|
||||
ImGui::Text("EEffects : %d", stats->num_envmap_effects);
|
||||
ImGui::Text("ETris : %d", stats->num_envmap_tris);
|
||||
|
||||
ImGui::Text("Uploads : %d", m_stats.num_uploads);
|
||||
ImGui::Text("Upload kB: %d", m_stats.num_upload_bytes / 1024);
|
||||
ImGui::Text("Uploads : %d", stats->num_uploads);
|
||||
ImGui::Text("Upload kB: %d", stats->num_upload_bytes / 1024);
|
||||
|
||||
ImGui::Checkbox("Debug", &m_debug_mode);
|
||||
ImGui::Checkbox("Debug", &stats->collect_debug_model_list);
|
||||
|
||||
ImGui::SliderFloat("blerc-nightmare", &blerc_multiplier, -3, 3);
|
||||
|
||||
if (m_debug_mode) {
|
||||
if (stats->collect_debug_model_list) {
|
||||
for (int i = 0; i < kMaxEffect; i++) {
|
||||
ImGui::Checkbox(fmt::format("e{:02d}", i).c_str(), &m_effect_debug_mask[i]);
|
||||
}
|
||||
|
||||
for (const auto& model : m_debug.model_list) {
|
||||
for (const auto& model : stats->model_list) {
|
||||
if (ImGui::TreeNode(model.name.c_str())) {
|
||||
ImGui::Text("Level: %s\n", model.level.c_str());
|
||||
for (const auto& e : model.effects) {
|
||||
|
@ -696,12 +704,6 @@ void Merc2::draw_debug_window() {
|
|||
}
|
||||
}
|
||||
|
||||
void Merc2::init_shaders(ShaderLibrary& shaders) {
|
||||
init_shader_common(shaders[ShaderId::MERC2], &m_merc_uniforms, true);
|
||||
init_shader_common(shaders[ShaderId::EMERC], &m_emerc_uniforms, false);
|
||||
m_emerc_uniforms.fade = glGetUniformLocation(shaders[ShaderId::EMERC].id(), "fade");
|
||||
}
|
||||
|
||||
void Merc2::init_shader_common(Shader& shader, Uniforms* uniforms, bool include_lights) {
|
||||
auto id = shader.id();
|
||||
shader.activate();
|
||||
|
@ -749,37 +751,32 @@ void Merc2::switch_to_emerc(SharedRenderState* render_state) {
|
|||
/*!
|
||||
* Main merc2 rendering.
|
||||
*/
|
||||
void Merc2::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
m_stats = {};
|
||||
if (m_debug_mode) {
|
||||
m_debug = {};
|
||||
void Merc2::render(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats) {
|
||||
*stats = {};
|
||||
if (stats->collect_debug_model_list) {
|
||||
stats->model_list.clear();
|
||||
}
|
||||
|
||||
// skip if disabled
|
||||
if (!m_enabled) {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch_to_merc2(render_state);
|
||||
|
||||
{
|
||||
auto pp = scoped_prof("handle-all-dma");
|
||||
// iterate through the dma chain, filling buckets
|
||||
handle_all_dma(dma, render_state, prof);
|
||||
handle_all_dma(dma, render_state, prof, stats);
|
||||
}
|
||||
|
||||
{
|
||||
auto pp = scoped_prof("flush-buckets");
|
||||
// flush buckets to draws
|
||||
flush_draw_buckets(render_state, prof);
|
||||
flush_draw_buckets(render_state, prof, stats);
|
||||
}
|
||||
}
|
||||
|
||||
u32 Merc2::alloc_lights(const VuLights& lights) {
|
||||
ASSERT(m_next_free_light < MAX_LIGHTS);
|
||||
m_stats.num_lights++;
|
||||
u32 light_idx = m_next_free_light;
|
||||
m_lights_buffer[m_next_free_light++] = lights;
|
||||
static_assert(sizeof(VuLights) == 7 * 16);
|
||||
|
@ -797,7 +794,8 @@ std::string Merc2::ShaderMercMat::to_string() const {
|
|||
*/
|
||||
void Merc2::handle_all_dma(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats) {
|
||||
// process the first tag. this is just jumping to the merc-specific dma.
|
||||
auto data0 = dma.read_and_advance();
|
||||
ASSERT(data0.vif1() == 0 || data0.vifcode1().kind == VifCode::Kind::NOP);
|
||||
|
@ -822,7 +820,7 @@ void Merc2::handle_all_dma(DmaFollower& dma,
|
|||
|
||||
// handle each merc transfer
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
handle_merc_chain(dma, render_state, prof);
|
||||
handle_merc_chain(dma, render_state, prof, stats);
|
||||
}
|
||||
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
||||
}
|
||||
|
@ -930,7 +928,8 @@ bool tag_is_nothing_next(const DmaFollower& dma) {
|
|||
|
||||
void Merc2::handle_merc_chain(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats) {
|
||||
while (tag_is_nothing_next(dma)) {
|
||||
auto nothing = dma.read_and_advance();
|
||||
ASSERT(nothing.size_bytes == 0);
|
||||
|
@ -950,7 +949,7 @@ void Merc2::handle_merc_chain(DmaFollower& dma,
|
|||
|
||||
while (init.vifcode1().kind == VifCode::Kind::PC_PORT) {
|
||||
// flush_pending_model(render_state, prof);
|
||||
handle_pc_model(init, render_state, prof);
|
||||
handle_pc_model(init, render_state, prof, stats);
|
||||
for (int i = 0; i < skip_count; i++) {
|
||||
auto link = dma.read_and_advance();
|
||||
ASSERT(link.vifcode0().kind == VifCode::Kind::NOP);
|
||||
|
@ -1157,8 +1156,10 @@ void Merc2::setup_merc_vao() {
|
|||
);
|
||||
}
|
||||
|
||||
void Merc2::flush_draw_buckets(SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
m_stats.num_draw_flush++;
|
||||
void Merc2::flush_draw_buckets(SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats) {
|
||||
stats->num_draw_flush++;
|
||||
for (u32 li = 0; li < m_next_free_level_bucket; li++) {
|
||||
const auto& lev_bucket = m_level_draw_buckets[li];
|
||||
const auto* lev = lev_bucket.level;
|
||||
|
@ -1166,7 +1167,7 @@ void Merc2::flush_draw_buckets(SharedRenderState* render_state, ScopedProfilerNo
|
|||
glBindBuffer(GL_ARRAY_BUFFER, lev->merc_vertices);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lev->merc_indices);
|
||||
setup_merc_vao();
|
||||
m_stats.num_bones_uploaded += m_next_free_bone_vector;
|
||||
stats->num_bones_uploaded += m_next_free_bone_vector;
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_bones_buffer);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, m_next_free_bone_vector * sizeof(math::Vector4f),
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
#pragma once
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
|
||||
class Merc2 : public BucketRenderer {
|
||||
public:
|
||||
Merc2(const std::string& name, int my_id);
|
||||
~Merc2();
|
||||
void draw_debug_window() override;
|
||||
void init_shaders(ShaderLibrary& shaders) override;
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
static constexpr int kMaxBlerc = 40;
|
||||
struct MercDebugStats {
|
||||
int num_models = 0;
|
||||
int num_missing_models = 0;
|
||||
int num_chains = 0;
|
||||
int num_effects = 0;
|
||||
int num_predicted_draws = 0;
|
||||
int num_predicted_tris = 0;
|
||||
int num_bones_uploaded = 0;
|
||||
int num_lights = 0;
|
||||
int num_draw_flush = 0;
|
||||
|
||||
int num_envmap_effects = 0;
|
||||
int num_envmap_tris = 0;
|
||||
|
||||
int num_upload_bytes = 0;
|
||||
int num_uploads = 0;
|
||||
|
||||
private:
|
||||
bool m_debug_mode = false;
|
||||
struct DrawDebug {
|
||||
DrawMode mode;
|
||||
int num_tris;
|
||||
|
@ -26,9 +32,24 @@ class Merc2 : public BucketRenderer {
|
|||
std::string level;
|
||||
std::vector<EffectDebug> effects;
|
||||
};
|
||||
struct {
|
||||
std::vector<ModelDebug> model_list;
|
||||
} m_debug;
|
||||
|
||||
std::vector<ModelDebug> model_list;
|
||||
|
||||
bool collect_debug_model_list = false;
|
||||
};
|
||||
|
||||
class Merc2 {
|
||||
public:
|
||||
Merc2(ShaderLibrary& shaders);
|
||||
~Merc2();
|
||||
void draw_debug_window(MercDebugStats* stats);
|
||||
void render(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats);
|
||||
static constexpr int kMaxBlerc = 40;
|
||||
|
||||
private:
|
||||
enum MercDataMemory {
|
||||
LOW_MEMORY = 0,
|
||||
BUFFER_BASE = 442,
|
||||
|
@ -60,7 +81,8 @@ class Merc2 : public BucketRenderer {
|
|||
|
||||
void handle_pc_model(const DmaTransfer& setup,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof);
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats);
|
||||
u32 alloc_lights(const VuLights& lights);
|
||||
|
||||
struct ModBuffers {
|
||||
|
@ -118,10 +140,14 @@ class Merc2 : public BucketRenderer {
|
|||
|
||||
void init_shader_common(Shader& shader, Uniforms* uniforms, bool include_lights);
|
||||
void handle_setup_dma(DmaFollower& dma, SharedRenderState* render_state);
|
||||
void handle_all_dma(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
void handle_all_dma(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats);
|
||||
void handle_merc_chain(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof);
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats);
|
||||
|
||||
void switch_to_merc2(SharedRenderState* render_state);
|
||||
void switch_to_emerc(SharedRenderState* render_state);
|
||||
|
@ -147,24 +173,6 @@ class Merc2 : public BucketRenderer {
|
|||
|
||||
GLuint m_bones_buffer;
|
||||
|
||||
struct Stats {
|
||||
int num_models = 0;
|
||||
int num_missing_models = 0;
|
||||
int num_chains = 0;
|
||||
int num_effects = 0;
|
||||
int num_predicted_draws = 0;
|
||||
int num_predicted_tris = 0;
|
||||
int num_bones_uploaded = 0;
|
||||
int num_lights = 0;
|
||||
int num_draw_flush = 0;
|
||||
|
||||
int num_envmap_effects = 0;
|
||||
int num_envmap_tris = 0;
|
||||
|
||||
int num_upload_bytes = 0;
|
||||
int num_uploads = 0;
|
||||
} m_stats;
|
||||
|
||||
enum DrawFlags {
|
||||
IGNORE_ALPHA = 1,
|
||||
MOD_VTX = 2,
|
||||
|
@ -230,16 +238,20 @@ class Merc2 : public BucketRenderer {
|
|||
u32 m_next_free_bone_vector = 0;
|
||||
size_t m_opengl_buffer_alignment = 0;
|
||||
|
||||
void flush_draw_buckets(SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
void flush_draw_buckets(SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
MercDebugStats* stats);
|
||||
void model_mod_draws(int num_effects,
|
||||
const tfrag3::MercModel* model,
|
||||
const LevelData* lev,
|
||||
const u8* input_data,
|
||||
const DmaTransfer& setup,
|
||||
ModBuffers* mod_opengl_buffers);
|
||||
ModBuffers* mod_opengl_buffers,
|
||||
MercDebugStats* stats);
|
||||
void model_mod_blerc_draws(int num_effects,
|
||||
const tfrag3::MercModel* model,
|
||||
const LevelData* lev,
|
||||
ModBuffers* mod_opengl_buffers,
|
||||
const float* blerc_weights);
|
||||
const float* blerc_weights,
|
||||
MercDebugStats* stats);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#include "Merc2BucketRenderer.h"
|
||||
|
||||
Merc2BucketRenderer::Merc2BucketRenderer(const std::string& name,
|
||||
int my_id,
|
||||
std::shared_ptr<Merc2> merc)
|
||||
: BucketRenderer(name, my_id), m_renderer(merc) {}
|
||||
|
||||
void Merc2BucketRenderer::render(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
// skip if disabled
|
||||
if (!m_enabled) {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_renderer->render(dma, render_state, prof, &m_debug_stats);
|
||||
}
|
||||
|
||||
void Merc2BucketRenderer::draw_debug_window() {
|
||||
m_renderer->draw_debug_window(&m_debug_stats);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/foreground/Merc2.h"
|
||||
|
||||
class Merc2BucketRenderer : public BucketRenderer {
|
||||
public:
|
||||
Merc2BucketRenderer(const std::string& name, int my_id, std::shared_ptr<Merc2> merc);
|
||||
void draw_debug_window() override;
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Merc2> m_renderer;
|
||||
MercDebugStats m_debug_stats;
|
||||
};
|
|
@ -161,6 +161,7 @@ void Loader::draw_debug_window() {
|
|||
void Loader::loader_thread() {
|
||||
try {
|
||||
while (!m_want_shutdown) {
|
||||
prof().root_event();
|
||||
std::unique_lock<std::mutex> lk(m_loader_mutex);
|
||||
|
||||
// this will keep us asleep until we've got a level to load.
|
||||
|
@ -176,39 +177,57 @@ void Loader::loader_thread() {
|
|||
// std::this_thread::sleep_for(std::chrono::milliseconds(1500));
|
||||
|
||||
// load the fr3 file
|
||||
prof().begin_event("read-file");
|
||||
Timer disk_timer;
|
||||
auto data =
|
||||
file_util::read_binary_file(m_base_path / fmt::format("{}.fr3", uppercase_string(lev)));
|
||||
double disk_load_time = disk_timer.getSeconds();
|
||||
prof().end_event();
|
||||
|
||||
// the FR3 files are compressed
|
||||
prof().begin_event("decompress-file");
|
||||
Timer decomp_timer;
|
||||
auto decomp_data = compression::decompress_zstd(data.data(), data.size());
|
||||
double decomp_time = decomp_timer.getSeconds();
|
||||
prof().end_event();
|
||||
|
||||
// Read back into the tfrag3::Level structure
|
||||
prof().begin_event("deserialize");
|
||||
Timer import_timer;
|
||||
auto result = std::make_unique<tfrag3::Level>();
|
||||
Serializer ser(decomp_data.data(), decomp_data.size());
|
||||
result->serialize(ser);
|
||||
double import_time = import_timer.getSeconds();
|
||||
prof().end_event();
|
||||
|
||||
// and finally "unpack", which creates the vertex data we'll upload to the GPU
|
||||
|
||||
Timer unpack_timer;
|
||||
for (auto& tie_tree : result->tie_trees) {
|
||||
for (auto& tree : tie_tree) {
|
||||
tree.unpack();
|
||||
}
|
||||
}
|
||||
for (auto& t_tree : result->tfrag_trees) {
|
||||
for (auto& tree : t_tree) {
|
||||
tree.unpack();
|
||||
{
|
||||
auto p = scoped_prof("tie-unpack");
|
||||
for (auto& tie_tree : result->tie_trees) {
|
||||
for (auto& tree : tie_tree) {
|
||||
tree.unpack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& shrub_tree : result->shrub_trees) {
|
||||
shrub_tree.unpack();
|
||||
{
|
||||
auto p = scoped_prof("tfrag-unpack");
|
||||
for (auto& t_tree : result->tfrag_trees) {
|
||||
for (auto& tree : t_tree) {
|
||||
tree.unpack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto p = scoped_prof("shrub-unpack");
|
||||
for (auto& shrub_tree : result->shrub_trees) {
|
||||
shrub_tree.unpack();
|
||||
}
|
||||
}
|
||||
|
||||
fmt::print(
|
||||
"------------> Load from file: {:.3f}s, import {:.3f}s, decomp {:.3f}s unpack {:.3f}s\n",
|
||||
disk_load_time, import_time, decomp_time, unpack_timer.getSeconds());
|
||||
|
|
|
@ -97,7 +97,7 @@ static int gl_init(GfxGlobalSettings& settings) {
|
|||
auto p = scoped_prof("startup::sdl::init_sdl");
|
||||
// remove SDL garbage from hooking signal handler.
|
||||
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) != 0) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
sdl_util::log_error("Could not initialize SDL, exiting");
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "kdgo.h"
|
||||
|
||||
#include "common/global_profiler/GlobalProfiler.h"
|
||||
#include "common/log/log.h"
|
||||
|
||||
#include "game/kernel/common/Ptr.h"
|
||||
|
@ -105,7 +106,10 @@ void load_and_link_dgo_from_c(const char* name,
|
|||
lg::debug("[link and exec] {:18s} {} {:6d} heap-use {:8d} {:8d}: 0x{:x}", objName,
|
||||
lastObjectLoaded, objSize, kheapused(kglobalheap),
|
||||
kdebugheap.offset ? kheapused(kdebugheap) : 0, kglobalheap->current.offset);
|
||||
link_and_exec(obj, objName, objSize, heap, linkFlag, jump_from_c_to_goal); // link now!
|
||||
{
|
||||
auto p = scoped_prof(fmt::format("link-{}", objName).c_str());
|
||||
link_and_exec(obj, objName, objSize, heap, linkFlag, jump_from_c_to_goal); // link now!
|
||||
}
|
||||
|
||||
// inform IOP we are done
|
||||
if (!lastObjectLoaded) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "common/global_profiler/GlobalProfiler.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/symbols.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
@ -400,7 +401,10 @@ int InitMachine() {
|
|||
InitRPC();
|
||||
reset_output();
|
||||
clear_print();
|
||||
|
||||
prof().begin_event("init-heap-and-symbol");
|
||||
auto status = InitHeapAndSymbol();
|
||||
prof().end_event();
|
||||
if (status >= 0) {
|
||||
printf("InitListenerConnect\n");
|
||||
InitListenerConnect();
|
||||
|
@ -774,9 +778,13 @@ void InitMachineScheme() {
|
|||
intern_from_c("*kernel-boot-art-group*")->value() = make_string_from_c(DebugBootArtGroup);
|
||||
if (DiskBoot) {
|
||||
*EnableMethodSet = *EnableMethodSet + 1;
|
||||
load_and_link_dgo_from_c("game", kglobalheap,
|
||||
LINK_FLAG_OUTPUT_LOAD | LINK_FLAG_EXECUTE | LINK_FLAG_PRINT_LOGIN,
|
||||
0x400000, true);
|
||||
{
|
||||
auto p = scoped_prof("load-game-dgo");
|
||||
load_and_link_dgo_from_c("game", kglobalheap,
|
||||
LINK_FLAG_OUTPUT_LOAD | LINK_FLAG_EXECUTE | LINK_FLAG_PRINT_LOGIN,
|
||||
0x400000, true);
|
||||
}
|
||||
|
||||
*EnableMethodSet = *EnableMethodSet + -1;
|
||||
using namespace jak2_symbols;
|
||||
kernel_packages->value() =
|
||||
|
@ -789,6 +797,7 @@ void InitMachineScheme() {
|
|||
new_pair(s7.offset + FIX_SYM_GLOBAL_HEAP, *((s7 + FIX_SYM_PAIR_TYPE - 1).cast<u32>()),
|
||||
make_string_from_c("common"), kernel_packages->value());
|
||||
printf("calling play-boot!\n");
|
||||
auto p = scoped_prof("play-boot-func");
|
||||
call_goal_function_by_name("play-boot"); // new function for jak2!
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/global_profiler/GlobalProfiler.h"
|
||||
#include "common/goal_constants.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/symbols.h"
|
||||
|
@ -1718,6 +1719,7 @@ int InitHeapAndSymbol() {
|
|||
// load kernel!
|
||||
|
||||
if (MasterUseKernel) {
|
||||
auto p = scoped_prof("load-kernel-dgo");
|
||||
*EnableMethodSet = *EnableMethodSet + 1;
|
||||
load_and_link_dgo_from_c("kernel", kglobalheap,
|
||||
LINK_FLAG_OUTPUT_LOAD | LINK_FLAG_EXECUTE | LINK_FLAG_PRINT_LOGIN,
|
||||
|
@ -1747,7 +1749,10 @@ int InitHeapAndSymbol() {
|
|||
InitListener();
|
||||
|
||||
// Do final initialization, including loading and initializing the engine.
|
||||
InitMachineScheme();
|
||||
{
|
||||
auto p = scoped_prof("init-machine-scheme");
|
||||
InitMachineScheme();
|
||||
}
|
||||
kmemclose();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -142,6 +142,7 @@ void deci2_runner(SystemThreadInterface& iface) {
|
|||
* SystemThread Function for the EE (PS2 Main CPU)
|
||||
*/
|
||||
void ee_runner(SystemThreadInterface& iface) {
|
||||
prof().root_event();
|
||||
// Allocate Main RAM. Must have execute enabled.
|
||||
if (EE_MEM_LOW_MAP) {
|
||||
g_ee_main_mem =
|
||||
|
|
|
@ -63,35 +63,55 @@
|
|||
;; each representing the name of a vag stream. convert using alloc-vag-list
|
||||
(define *vagdir-names-list* (alloc-vagdir-names 'debug))
|
||||
|
||||
|
||||
(defun sort-string-array ((arr (array string)) (compare-func (function string string object)))
|
||||
"Sort an array, using compare-func to compare elements.
|
||||
The comparison function can return either an integer or a true/false.
|
||||
For integers, use a positive number to represent first > second
|
||||
Ex: (sort lst -) will sort in ascending order
|
||||
For booleans, you must explicitly use #t and not a truthy value.
|
||||
Ex: (sort my-list (lambda ((x int) (y int)) (< x y))) will sort ascending.
|
||||
NOTE: if you use an integer, don't accidentally return #t"
|
||||
(let ((sorted -1))
|
||||
(while (nonzero? sorted)
|
||||
(set! sorted 0)
|
||||
(dotimes (i (1- (-> arr allocated-length)))
|
||||
(let* ((cur (-> arr i))
|
||||
(next (-> arr (1+ i)))
|
||||
(result (compare-func cur next))
|
||||
)
|
||||
(when (and (or (not result) (> (the-as int result) 0)) (!= result #t))
|
||||
(+! sorted 1)
|
||||
(set! (-> arr i) next)
|
||||
(set! (-> arr (1+ i)) cur)
|
||||
)
|
||||
)
|
||||
)
|
||||
(defun strcmp ((a string) (b string))
|
||||
"C-style strcmp. Unlike GOAL's string comparison functions, these actually work:
|
||||
(strcmp 'ab' 'a') and (strcmp 'a' 'ab') give the opposite result."
|
||||
(let ((a-ptr (-> a data))
|
||||
(b-ptr (-> b data)))
|
||||
(while (and (nonzero? (-> a-ptr))
|
||||
(= (-> a-ptr) (-> b-ptr)))
|
||||
(&+! a-ptr 1)
|
||||
(&+! b-ptr 1)
|
||||
)
|
||||
(- (the int (-> a-ptr)) (the int (-> b-ptr)))
|
||||
)
|
||||
)
|
||||
|
||||
(defun string-quicksort-partition ((arr (array string)) (lo int) (hi int))
|
||||
(let ((pivot (-> arr hi))
|
||||
(i (- lo 1))
|
||||
(j lo)
|
||||
)
|
||||
(while (< j hi)
|
||||
(when (< (strcmp (-> arr j) pivot) 0)
|
||||
(+! i 1)
|
||||
(swap! (-> arr i) (-> arr j))
|
||||
)
|
||||
(+! j 1)
|
||||
)
|
||||
(+! i 1)
|
||||
(swap! (-> arr i) (-> arr hi))
|
||||
i
|
||||
)
|
||||
)
|
||||
|
||||
(defun-recursive string-quicksort-run (array string) ((arr (array string)) (lo int) (hi int))
|
||||
(when (or (>= lo hi) (< lo 0))
|
||||
(return arr)
|
||||
)
|
||||
(let ((p (string-quicksort-partition arr lo hi)))
|
||||
(string-quicksort-run arr lo (- p 1))
|
||||
(string-quicksort-run arr (+ p 1) hi)
|
||||
)
|
||||
arr
|
||||
)
|
||||
|
||||
(defun string-quicksort ((arr (array string)))
|
||||
"Sort an array of strings alphabetically using quicksort.
|
||||
This is about 100x faster than the normal GOAL sort."
|
||||
(string-quicksort-run arr 0 (- (-> arr length) 1))
|
||||
)
|
||||
|
||||
|
||||
(defun alloc-vag-list ()
|
||||
"allocates and returns a boxed array with all of the vag names as strings, sorted"
|
||||
|
@ -112,7 +132,7 @@
|
|||
(set! (-> list i) (new 'debug 'string 0 *temp-string*)))
|
||||
|
||||
;; return the allocated, filled and sorted array
|
||||
(sort-string-array list string<=?))
|
||||
(string-quicksort list))
|
||||
)
|
||||
|
||||
|
||||
|
@ -179,7 +199,7 @@
|
|||
|
||||
|
||||
(defstate vag-player-playing (vag-player)
|
||||
|
||||
|
||||
:event (behavior ((from process) (argc int) (msg symbol) (block event-message-block))
|
||||
(case msg
|
||||
(('play)
|
||||
|
@ -195,13 +215,13 @@
|
|||
#t)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
:enter (behavior ((index int))
|
||||
(set! (-> self master-mode) *master-mode*)
|
||||
(set! (-> self debug-menu-hidden) (-> *debug-menu-context* is-hidden))
|
||||
(set! (-> self display-art-control) *display-art-control*)
|
||||
(set! (-> self gui-kick-str) *gui-kick-str*)
|
||||
|
||||
|
||||
(set-master-mode 'menu) ;; put us in menu mode first
|
||||
(true! *display-art-control*) ;; force this on
|
||||
(true! (-> *debug-menu-context* is-hidden)) ;; hide debug menu
|
||||
|
@ -309,7 +329,7 @@
|
|||
(set! (-> self old-speed) (-> self speed))))
|
||||
(suspend))
|
||||
)
|
||||
|
||||
|
||||
(go vag-player-idle)
|
||||
(none))
|
||||
)
|
||||
|
@ -382,14 +402,14 @@
|
|||
"play a vag from its index in the vag list"
|
||||
(if (not *vag-player*)
|
||||
(vag-player-start))
|
||||
|
||||
|
||||
(send-event (ppointer->process *vag-player*) 'play-index index))
|
||||
|
||||
(defun vag-player-play-from-name ((name string))
|
||||
"play a vag from its name"
|
||||
(if (not *vag-player*)
|
||||
(vag-player-start))
|
||||
|
||||
|
||||
(send-event (ppointer->process *vag-player*) 'play name))
|
||||
|
||||
(defun vag-list-to-file ((file-name string))
|
||||
|
|
Loading…
Reference in a new issue