mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 00:57:44 -04:00
parent
b688bdbfd1
commit
79683a44b1
|
@ -10,6 +10,13 @@ void PackedTieVertices::serialize(Serializer& ser) {
|
|||
ser.from_pod_vector(&vertices);
|
||||
}
|
||||
|
||||
void PackedShrubVertices::serialize(Serializer& ser) {
|
||||
ser.from_pod_vector(&matrices);
|
||||
ser.from_pod_vector(&instance_groups);
|
||||
ser.from_pod_vector(&vertices);
|
||||
ser.from_ptr(&total_vertex_count);
|
||||
}
|
||||
|
||||
void StripDraw::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&mode);
|
||||
ser.from_ptr(&tree_tex_id);
|
||||
|
@ -28,6 +35,13 @@ void StripDraw::unpack() {
|
|||
}
|
||||
}
|
||||
|
||||
void ShrubDraw::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&mode);
|
||||
ser.from_ptr(&tree_tex_id);
|
||||
ser.from_pod_vector(&vertex_index_stream);
|
||||
ser.from_ptr(&num_triangles);
|
||||
}
|
||||
|
||||
void InstancedStripDraw::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&mode);
|
||||
ser.from_ptr(&tree_tex_id);
|
||||
|
@ -97,6 +111,29 @@ void TieTree::unpack() {
|
|||
}
|
||||
}
|
||||
|
||||
void ShrubTree::unpack() {
|
||||
unpacked.vertices.resize(packed_vertices.total_vertex_count);
|
||||
size_t i = 0;
|
||||
|
||||
for (const auto& grp : packed_vertices.instance_groups) {
|
||||
const auto& mat = packed_vertices.matrices[grp.matrix_idx];
|
||||
for (u32 src_idx = grp.start_vert; src_idx < grp.end_vert; src_idx++) {
|
||||
auto& vtx = unpacked.vertices[i];
|
||||
vtx.color_index = grp.color_index;
|
||||
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;
|
||||
memcpy(vtx.rgba_base, proto_vtx.rgba, 3);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
ASSERT(i == unpacked.vertices.size());
|
||||
}
|
||||
|
||||
void TfragTree::unpack() {
|
||||
unpacked.vertices.resize(packed_vertices.vertices.size());
|
||||
for (size_t i = 0; i < unpacked.vertices.size(); i++) {
|
||||
|
@ -152,6 +189,19 @@ void TieTree::serialize(Serializer& ser) {
|
|||
bvh.serialize(ser);
|
||||
}
|
||||
|
||||
void ShrubTree::serialize(Serializer& ser) {
|
||||
ser.from_pod_vector(&time_of_day_colors);
|
||||
packed_vertices.serialize(ser);
|
||||
if (ser.is_saving()) {
|
||||
ser.save<size_t>(static_draws.size());
|
||||
} else {
|
||||
static_draws.resize(ser.load<size_t>());
|
||||
}
|
||||
for (auto& draw : static_draws) {
|
||||
draw.serialize(ser);
|
||||
}
|
||||
}
|
||||
|
||||
void BVH::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&first_leaf_node);
|
||||
ser.from_ptr(&last_leaf_node);
|
||||
|
@ -212,6 +262,15 @@ void Level::serialize(Serializer& ser) {
|
|||
}
|
||||
}
|
||||
|
||||
if (ser.is_saving()) {
|
||||
ser.save<size_t>(shrub_trees.size());
|
||||
} else {
|
||||
shrub_trees.resize(ser.load<size_t>());
|
||||
}
|
||||
for (auto& tree : shrub_trees) {
|
||||
tree.serialize(ser);
|
||||
}
|
||||
|
||||
ser.from_ptr(&version2);
|
||||
if (ser.is_loading() && version2 != TFRAG3_VERSION) {
|
||||
fmt::print("version mismatch when loading tfrag3 data (at end). Got {}, expected {}\n",
|
||||
|
@ -271,6 +330,20 @@ std::array<int, MemoryUsageCategory::NUM_CATEGORIES> Level::get_memory_usage() c
|
|||
}
|
||||
}
|
||||
|
||||
// shrub
|
||||
for (const auto& shrub_tree : shrub_trees) {
|
||||
result[SHRUB_TIME_OF_DAY] += shrub_tree.time_of_day_colors.size() * sizeof(TimeOfDayColor);
|
||||
result[SHRUB_VERT] += shrub_tree.packed_vertices.matrices.size() * 4 * 4 * 4;
|
||||
result[SHRUB_VERT] +=
|
||||
shrub_tree.packed_vertices.vertices.size() * sizeof(PackedShrubVertices::Vertex);
|
||||
result[SHRUB_VERT] += shrub_tree.packed_vertices.instance_groups.size() *
|
||||
sizeof(PackedShrubVertices::InstanceGroup);
|
||||
|
||||
for (const auto& draw : shrub_tree.static_draws) {
|
||||
result[SHRUB_IND] += sizeof(u32) * draw.vertex_index_stream.size();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,10 +40,14 @@ enum MemoryUsageCategory {
|
|||
TFRAG_CLUSTER,
|
||||
TFRAG_TIME_OF_DAY,
|
||||
TFRAG_BVH,
|
||||
|
||||
SHRUB_TIME_OF_DAY,
|
||||
SHRUB_VERT,
|
||||
SHRUB_IND,
|
||||
NUM_CATEGORIES
|
||||
};
|
||||
|
||||
constexpr int TFRAG3_VERSION = 12;
|
||||
constexpr int TFRAG3_VERSION = 13;
|
||||
|
||||
// These vertices should be uploaded to the GPU at load time and don't change
|
||||
struct PreloadedVertex {
|
||||
|
@ -73,7 +77,6 @@ struct PackedTieVertices {
|
|||
std::vector<std::array<math::Vector4f, 4>> matrices;
|
||||
std::vector<MatrixGroup> matrix_groups; // todo pack
|
||||
std::vector<Vertex> vertices;
|
||||
float cluster_size = 0;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
|
@ -83,29 +86,44 @@ struct PackedTfragVertices {
|
|||
u16 cluster_idx;
|
||||
u16 s, t;
|
||||
u16 color_index;
|
||||
|
||||
/*
|
||||
bool operator==(const Vertex& other) const {
|
||||
return xoff == other.xoff && yoff == other.yoff && zoff == other.zoff &&
|
||||
cluster_idx == other.cluster_idx && s == other.s && t == other.t &&
|
||||
color_index == other.color_index;
|
||||
}
|
||||
|
||||
struct hash {
|
||||
auto operator()(const Vertex& x) const {
|
||||
return std::hash<uint16_t>()(x.xoff) ^ std::hash<uint16_t>()(x.yoff) ^
|
||||
std::hash<uint16_t>()(x.zoff) ^ std::hash<uint16_t>()(x.cluster_idx) ^
|
||||
std::hash<uint16_t>()(x.s) ^ std::hash<uint16_t>()(x.t) ^
|
||||
std::hash<uint16_t>()(x.color_index);
|
||||
}
|
||||
};
|
||||
*/
|
||||
};
|
||||
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<math::Vector<u16, 3>> cluster_origins;
|
||||
};
|
||||
|
||||
struct ShrubGpuVertex {
|
||||
float x, y, z;
|
||||
float s, t;
|
||||
u32 pad0;
|
||||
u16 color_index;
|
||||
u16 pad1;
|
||||
u8 rgba_base[3];
|
||||
u8 pad2;
|
||||
};
|
||||
static_assert(sizeof(ShrubGpuVertex) == 32, "ShrubGpuVertex size");
|
||||
|
||||
struct PackedShrubVertices {
|
||||
struct Vertex {
|
||||
float x, y, z;
|
||||
float s, t;
|
||||
u8 rgba[3];
|
||||
};
|
||||
|
||||
struct InstanceGroup {
|
||||
s32 matrix_idx;
|
||||
u32 start_vert;
|
||||
u32 end_vert;
|
||||
u16 color_index;
|
||||
};
|
||||
std::vector<std::array<math::Vector4f, 4>> matrices;
|
||||
std::vector<InstanceGroup> instance_groups; // todo pack
|
||||
std::vector<Vertex> vertices;
|
||||
u32 total_vertex_count;
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
// Settings for drawing a group of triangle strips.
|
||||
// This refers to a group of PreloadedVertices that are already uploaded.
|
||||
// All triangles here are drawn in the same "mode" (blending, texture, etc)
|
||||
|
@ -144,6 +162,19 @@ struct StripDraw {
|
|||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
struct ShrubDraw {
|
||||
DrawMode mode; // the OpenGL draw settings.
|
||||
u32 tree_tex_id = 0; // the texture that should be bound for the draw
|
||||
|
||||
// the list of vertices in the draw. This includes the restart code of UINT32_MAX that OpenGL
|
||||
// will use to start a new strip.
|
||||
std::vector<u32> vertex_index_stream;
|
||||
|
||||
// for debug counting.
|
||||
u32 num_triangles = 0;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
struct InstancedStripDraw {
|
||||
DrawMode mode; // the OpenGL draw settings.
|
||||
u32 tree_tex_id = 0; // the texture that should be bound for the draw
|
||||
|
@ -261,6 +292,21 @@ struct TieTree {
|
|||
void unpack();
|
||||
};
|
||||
|
||||
struct ShrubTree {
|
||||
// todo some visibility structure
|
||||
std::vector<TimeOfDayColor> time_of_day_colors; // multiplier colors
|
||||
|
||||
PackedShrubVertices packed_vertices;
|
||||
std::vector<ShrubDraw> static_draws; // the actual topology and settings
|
||||
|
||||
struct {
|
||||
std::vector<ShrubGpuVertex> vertices; // mesh vertices
|
||||
} unpacked;
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
void unpack();
|
||||
};
|
||||
|
||||
constexpr int TFRAG_GEOS = 3;
|
||||
constexpr int TIE_GEOS = 4;
|
||||
|
||||
|
@ -270,6 +316,7 @@ struct Level {
|
|||
std::vector<Texture> textures;
|
||||
std::array<std::vector<TfragTree>, TFRAG_GEOS> tfrag_trees;
|
||||
std::array<std::vector<TieTree>, TIE_GEOS> tie_trees;
|
||||
std::vector<ShrubTree> shrub_trees;
|
||||
u16 version2 = TFRAG3_VERSION;
|
||||
void serialize(Serializer& ser);
|
||||
|
||||
|
|
|
@ -478,33 +478,32 @@
|
|||
:type int32
|
||||
:bitfield #f
|
||||
|
||||
(bucket-1 1)
|
||||
(bucket-2 2)
|
||||
(sky-draw 3)
|
||||
(bucket-4 4) ;; ocean
|
||||
(tfrag-tex0 5)
|
||||
(tfrag-0 6)
|
||||
(tfrag-near-0 7)
|
||||
(tie-near-0 8)
|
||||
(tie-0 9)
|
||||
;; merc0 10
|
||||
;; generic0 11
|
||||
(bucket-10 10)
|
||||
(bucket-11 11)
|
||||
(bucket-0 0) ;; ?
|
||||
(bucket-1 1) ;; ?
|
||||
(bucket-2 2) ;; ?
|
||||
(sky-draw 3) ;; actual sky and cloud framebuffer draws
|
||||
(ocean-mid-and-far 4) ;; actual ocean framebuffer draws for mid/transition/far
|
||||
|
||||
(tfrag-tex1 12)
|
||||
(tfrag-1 13)
|
||||
(tfrag-near-1 14)
|
||||
(tie-near-1 15)
|
||||
(tie-1 16)
|
||||
;; merc1 17
|
||||
;; generic1 18
|
||||
(bucket-17 17)
|
||||
(bucket-18 18)
|
||||
(tfrag-tex0 5) ;; tfrag texture upload, level 0
|
||||
(tfrag-0 6) ;; tfrag draw, level 0
|
||||
(tfrag-near-0 7) ;; tfrag near draw, level 0
|
||||
(tie-near-0 8) ;; tie near draw, level 0
|
||||
(tie-0 9) ;; tie draw, level 0
|
||||
(merc-tfrag-tex0 10) ;; merc, with tfrag textures, level 0
|
||||
(gmerc-tfrag-tex 11) ;; generic merc, with tfrag textures, level 0
|
||||
|
||||
(tfrag-tex1 12) ;; tfrag texture upload, level 1
|
||||
(tfrag-1 13) ;; tfrag draw, level 1
|
||||
(tfrag-near-1 14) ;; tfrag near draw, level 1
|
||||
(tie-near-1 15) ;; tie near draw, level 1
|
||||
(tie-1 16) ;; tie draw, level 1
|
||||
(merc-tfrag-tex1 17) ;; merc, with tfrag textures, level 1
|
||||
(gmerc-tfrag-tex1 18) ;; generic merc, with tfrag textures, level 1
|
||||
(shrub-tex0 19)
|
||||
|
||||
(shrub0 20)
|
||||
|
||||
(shrub-tex1 25)
|
||||
(shrub1 26)
|
||||
|
||||
(generic-foreground 30) ;; ?
|
||||
(alpha-tex0 31)
|
||||
|
|
|
@ -1515,8 +1515,7 @@ std::string Shrubbery::print(const level_tools::PrintSettings& /*settings*/, int
|
|||
std::string GenericShrubFragment::print(const level_tools::PrintSettings& /*settings*/,
|
||||
int indent) const {
|
||||
std::string is(indent, ' ');
|
||||
return fmt::format("{} qwcs: {} {} {} {}: 0x{:x}\n", is, cnt_qwc, vtx_qwc, col_qwc, stq_qwc,
|
||||
vtx_cnt);
|
||||
return fmt::format("{} qwcs: {} {} {} {}: {}\n", is, cnt_qwc, vtx_qwc, col_qwc, stq_qwc, vtx_cnt);
|
||||
}
|
||||
|
||||
void GenericShrubFragment::read_from_file(TypedRef ref,
|
||||
|
|
|
@ -72,7 +72,10 @@ void print_memory_usage(const tfrag3::Level& lev, int uncompressed_data_size) {
|
|||
{"tfrag-vert", memory_use_by_category[tfrag3::MemoryUsageCategory::TFRAG_VERTS]},
|
||||
{"tfrag-colors", memory_use_by_category[tfrag3::MemoryUsageCategory::TFRAG_TIME_OF_DAY]},
|
||||
{"tfrag-cluster", memory_use_by_category[tfrag3::MemoryUsageCategory::TFRAG_CLUSTER]},
|
||||
{"tfrag-bvh", memory_use_by_category[tfrag3::MemoryUsageCategory::TFRAG_BVH]}};
|
||||
{"tfrag-bvh", memory_use_by_category[tfrag3::MemoryUsageCategory::TFRAG_BVH]},
|
||||
{"shrub-colors", memory_use_by_category[tfrag3::MemoryUsageCategory::SHRUB_TIME_OF_DAY]},
|
||||
{"shrub-vert", memory_use_by_category[tfrag3::MemoryUsageCategory::SHRUB_VERT]},
|
||||
{"shrub-ind", memory_use_by_category[tfrag3::MemoryUsageCategory::SHRUB_IND]}};
|
||||
for (auto& known : known_categories) {
|
||||
total_accounted += known.second;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,17 @@ std::array<math::Vector4f, 4> extract_shrub_matrix(const u16* data) {
|
|||
struct ShrubVertex {
|
||||
math::Vector<float, 3> xyz;
|
||||
math::Vector<float, 2> st;
|
||||
math::Vector<u8, 4> rgba_generic;
|
||||
math::Vector<u8, 3> rgba_generic;
|
||||
bool adc = false;
|
||||
};
|
||||
|
||||
struct DrawSettings {
|
||||
DrawMode mode;
|
||||
u32 combo_tex;
|
||||
};
|
||||
struct ShrubDraw {
|
||||
u32 start_vtx_idx = -1;
|
||||
AdGifData adgif;
|
||||
DrawSettings settings;
|
||||
std::vector<ShrubVertex> vertices;
|
||||
};
|
||||
|
||||
|
@ -116,7 +120,127 @@ std::string debug_dump_proto_to_obj(const ShrubProtoInfo& proto) {
|
|||
return result;
|
||||
}
|
||||
|
||||
ShrubProtoInfo extract_proto(const shrub_types::PrototypeBucketShrub& proto) {
|
||||
namespace {
|
||||
/*!
|
||||
* adgif shader texture id's can be "remapped". I think it allows textures to be shared.
|
||||
* So far we haven't seen this feature used, but we do have the texture map and we check it here.
|
||||
*/
|
||||
u32 remap_texture(u32 original, const std::vector<level_tools::TextureRemap>& map) {
|
||||
auto masked = original & 0xffffff00;
|
||||
for (auto& t : map) {
|
||||
if (t.original_texid == masked) {
|
||||
fmt::print("OKAY! remapped!\n");
|
||||
ASSERT(false);
|
||||
return t.new_texid | 20;
|
||||
}
|
||||
}
|
||||
return original;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DrawSettings adgif_to_draw_mode(const AdGifData& ad,
|
||||
const TextureDB& tdb,
|
||||
const std::vector<level_tools::TextureRemap>& map,
|
||||
int count) {
|
||||
// initialize draw mode
|
||||
DrawMode current_mode;
|
||||
current_mode.set_at(true);
|
||||
current_mode.set_alpha_test(DrawMode::AlphaTest::GEQUAL);
|
||||
current_mode.set_aref(0x26);
|
||||
current_mode.set_alpha_fail(GsTest::AlphaFail::KEEP);
|
||||
current_mode.set_zt(true);
|
||||
current_mode.set_depth_test(GsTest::ZTest::GEQUAL);
|
||||
current_mode.set_depth_write_enable(true); // todo, is this actual true
|
||||
current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_SRC_SRC_SRC);
|
||||
current_mode.enable_fog();
|
||||
|
||||
// ADGIF 0
|
||||
bool weird = (u8)ad.tex0_addr != (u32)GsRegisterAddress::TEX0_1;
|
||||
if (weird) {
|
||||
fmt::print("---------------- WEIRD: 0x{:x}\n", ad.tex0_addr);
|
||||
fmt::print("i have {} verts\n", count);
|
||||
} else {
|
||||
ASSERT(ad.tex0_data == 0 || ad.tex0_data == 0x800000000); // note: decal?? todo
|
||||
}
|
||||
|
||||
// tw/th
|
||||
|
||||
// ADGIF 1
|
||||
ASSERT((u8)ad.tex1_addr == (u32)GsRegisterAddress::TEX1_1);
|
||||
u32 original_tex = ad.tex1_addr;
|
||||
u32 new_tex = remap_texture(original_tex, map);
|
||||
// try remapping it
|
||||
if (original_tex != new_tex) {
|
||||
fmt::print("map from 0x{:x} to 0x{:x}\n", original_tex, new_tex);
|
||||
}
|
||||
// texture the texture page/texture index, and convert to a PC port texture ID
|
||||
u32 tpage = new_tex >> 20;
|
||||
u32 tidx = (new_tex >> 8) & 0b1111'1111'1111;
|
||||
u32 tex_combo = (((u32)tpage) << 16) | tidx;
|
||||
// look up the texture to make sure it's valid
|
||||
auto tex = tdb.textures.find(tex_combo);
|
||||
ASSERT(tex != tdb.textures.end());
|
||||
if (weird) {
|
||||
fmt::print("tex: {}\n", tex->second.name);
|
||||
}
|
||||
|
||||
// ADGIF 2
|
||||
ASSERT((u8)ad.mip_addr == (u32)GsRegisterAddress::MIPTBP1_1);
|
||||
|
||||
// ADGIF 3
|
||||
ASSERT((u8)ad.clamp_addr == (u32)GsRegisterAddress::CLAMP_1);
|
||||
{
|
||||
bool clamp_s = ad.clamp_data & 0b001;
|
||||
bool clamp_t = ad.clamp_data & 0b100;
|
||||
current_mode.set_clamp_s_enable(clamp_s);
|
||||
current_mode.set_clamp_t_enable(clamp_t);
|
||||
}
|
||||
|
||||
u64 final_alpha;
|
||||
|
||||
// ADGIF 4
|
||||
if ((u8)ad.alpha_addr == (u32)GsRegisterAddress::ALPHA_1) {
|
||||
final_alpha = ad.alpha_data;
|
||||
} else {
|
||||
ASSERT(false);
|
||||
// ASSERT((u8)ad.alpha_addr == (u32)GsRegisterAddress::MIPTBP2_1);
|
||||
}
|
||||
|
||||
GsAlpha reg(final_alpha);
|
||||
auto a = reg.a_mode();
|
||||
auto b = reg.b_mode();
|
||||
auto c = reg.c_mode();
|
||||
auto d = reg.d_mode();
|
||||
if (a == GsAlpha::BlendMode::SOURCE && b == GsAlpha::BlendMode::DEST &&
|
||||
c == GsAlpha::BlendMode::SOURCE && d == GsAlpha::BlendMode::DEST) {
|
||||
current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
||||
} else if (a == GsAlpha::BlendMode::SOURCE && b == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
||||
c == GsAlpha::BlendMode::SOURCE && d == GsAlpha::BlendMode::DEST) {
|
||||
current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_SRC_DST);
|
||||
} else if (a == GsAlpha::BlendMode::ZERO_OR_FIXED && b == GsAlpha::BlendMode::SOURCE &&
|
||||
c == GsAlpha::BlendMode::SOURCE && d == GsAlpha::BlendMode::DEST) {
|
||||
current_mode.set_alpha_blend(DrawMode::AlphaBlend::ZERO_SRC_SRC_DST);
|
||||
} else if (a == GsAlpha::BlendMode::SOURCE && b == GsAlpha::BlendMode::DEST &&
|
||||
c == GsAlpha::BlendMode::ZERO_OR_FIXED && d == GsAlpha::BlendMode::DEST) {
|
||||
current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_FIX_DST);
|
||||
} else if (a == GsAlpha::BlendMode::SOURCE && b == GsAlpha::BlendMode::SOURCE &&
|
||||
c == GsAlpha::BlendMode::SOURCE && d == GsAlpha::BlendMode::SOURCE) {
|
||||
current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_SRC_SRC_SRC);
|
||||
} else if (a == GsAlpha::BlendMode::SOURCE && b == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
||||
c == GsAlpha::BlendMode::DEST && d == GsAlpha::BlendMode::DEST) {
|
||||
current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
|
||||
} else {
|
||||
// unsupported blend: a 0 b 2 c 2 d 1
|
||||
// lg::error("unsupported blend: a {} b {} c {} d {}", (int)a, (int)b, (int)c, (int)d);
|
||||
// ASSERT(false);
|
||||
}
|
||||
|
||||
return {current_mode, tex_combo};
|
||||
}
|
||||
|
||||
ShrubProtoInfo extract_proto(const shrub_types::PrototypeBucketShrub& proto,
|
||||
const TextureDB& tdb,
|
||||
const std::vector<level_tools::TextureRemap>& map) {
|
||||
ShrubProtoInfo result;
|
||||
for (int frag_idx = 0; frag_idx < proto.generic_geom.length; frag_idx++) {
|
||||
auto& frag_out = result.frags.emplace_back();
|
||||
|
@ -125,8 +249,15 @@ ShrubProtoInfo extract_proto(const shrub_types::PrototypeBucketShrub& proto) {
|
|||
std::vector<AdGifData> adgif_data;
|
||||
adgif_data.resize(frag.textures.size() / sizeof(AdGifData));
|
||||
memcpy(adgif_data.data(), frag.textures.data(), frag.textures.size());
|
||||
|
||||
if (frag_idx == 0 && proto.name == "vil2-cattail.mb") {
|
||||
fmt::print("Skipping broken village2 thing\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < adgif_data.size(); i++) {
|
||||
auto& draw = frag_out.draws.emplace_back();
|
||||
draw.adgif = adgif_data[i];
|
||||
|
||||
const auto& ag = adgif_data[i];
|
||||
int count = (ag.tex1_addr >> 32) & 0xfff; // drop the eop flag
|
||||
|
@ -144,15 +275,18 @@ ShrubProtoInfo extract_proto(const shrub_types::PrototypeBucketShrub& proto) {
|
|||
3 * sizeof(u16));
|
||||
vert_out.xyz = math::Vector3f(vert_data[0], vert_data[1], vert_data[2]);
|
||||
|
||||
u16 st_data[2];
|
||||
s16 st_data[2];
|
||||
memcpy(st_data, frag.stq.data() + sizeof(u16) * 2 * (vert_idx + draw.start_vtx_idx),
|
||||
2 * sizeof(u16));
|
||||
vert_out.st = math::Vector2f(st_data[0], st_data[1]);
|
||||
vert_out.adc = (st_data[0] & 1) == 0; // adc in the low bit of texture coordinate
|
||||
|
||||
memcpy(vert_out.rgba_generic.data(), frag.col.data() + 4 * (vert_idx + draw.start_vtx_idx),
|
||||
4);
|
||||
memcpy(vert_out.rgba_generic.data(), frag.col.data() + 3 * (vert_idx + draw.start_vtx_idx),
|
||||
3);
|
||||
ASSERT(3 * (vert_idx + draw.start_vtx_idx) + 3 <= frag.col.size());
|
||||
}
|
||||
|
||||
draw.settings = adgif_to_draw_mode(ag, tdb, map, count);
|
||||
}
|
||||
|
||||
ASSERT(frag.vtx_cnt * 3 * sizeof(u16) <= frag.vtx.size());
|
||||
|
@ -182,6 +316,7 @@ void extract_instance(const shrub_types::InstanceShrubbery& inst,
|
|||
// result.wind_index = instance.wind_index;
|
||||
|
||||
result.mat[0][3] = 0.f;
|
||||
result.color_idx = inst.color_indices / 4;
|
||||
|
||||
protos.at(result.proto_idx).instances.push_back(result);
|
||||
}
|
||||
|
@ -261,17 +396,200 @@ std::string dump_full_to_obj(const std::vector<ShrubProtoInfo>& protos) {
|
|||
return result;
|
||||
}
|
||||
|
||||
u32 clean_up_vertex_indices(std::vector<u32>& idx) {
|
||||
std::vector<u32> fixed;
|
||||
u32 num_tris = 0;
|
||||
|
||||
bool looking_for_start = true;
|
||||
size_t i_of_start;
|
||||
for (size_t i = 0; i < idx.size(); i++) {
|
||||
if (looking_for_start) {
|
||||
if (idx[i] != UINT32_MAX) {
|
||||
looking_for_start = false;
|
||||
i_of_start = i;
|
||||
}
|
||||
} else {
|
||||
if (idx[i] == UINT32_MAX) {
|
||||
looking_for_start = true;
|
||||
size_t num_verts = i - i_of_start;
|
||||
if (num_verts >= 3) {
|
||||
if (!fixed.empty()) {
|
||||
fixed.push_back(UINT32_MAX);
|
||||
}
|
||||
fixed.insert(fixed.end(), idx.begin() + i_of_start, idx.begin() + i);
|
||||
num_tris += (num_verts - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!looking_for_start) {
|
||||
size_t num_verts = idx.size() - i_of_start;
|
||||
if (num_verts >= 3) {
|
||||
if (!fixed.empty()) {
|
||||
fixed.push_back(UINT32_MAX);
|
||||
}
|
||||
fixed.insert(fixed.end(), idx.begin() + i_of_start, idx.begin() + idx.size());
|
||||
num_tris += (num_verts - 2);
|
||||
}
|
||||
}
|
||||
|
||||
idx = std::move(fixed);
|
||||
|
||||
return num_tris;
|
||||
}
|
||||
|
||||
void make_draws(tfrag3::Level& lev,
|
||||
tfrag3::ShrubTree& tree_out,
|
||||
const std::vector<ShrubProtoInfo>& protos,
|
||||
const TextureDB& tdb) {
|
||||
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
|
||||
size_t global_vert_counter = 0;
|
||||
for (auto& proto : protos) {
|
||||
// packed_vert_indices[frag][draw] = {start, end}
|
||||
std::vector<std::vector<std::pair<int, int>>> packed_vert_indices;
|
||||
|
||||
for (size_t frag_idx = 0; frag_idx < proto.frags.size(); frag_idx++) {
|
||||
auto& frag_inds = packed_vert_indices.emplace_back();
|
||||
auto& frag = proto.frags[frag_idx];
|
||||
|
||||
for (auto& draw : frag.draws) {
|
||||
int start = tree_out.packed_vertices.vertices.size();
|
||||
for (auto& vert : draw.vertices) {
|
||||
tree_out.packed_vertices.vertices.push_back(
|
||||
{vert.xyz.x(),
|
||||
vert.xyz.y(),
|
||||
vert.xyz.z(),
|
||||
vert.st.x(),
|
||||
vert.st.y(),
|
||||
{vert.rgba_generic[0], vert.rgba_generic[1], vert.rgba_generic[2]}});
|
||||
}
|
||||
int end = tree_out.packed_vertices.vertices.size();
|
||||
frag_inds.emplace_back(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& inst : proto.instances) {
|
||||
u32 matrix_idx = tree_out.packed_vertices.matrices.size();
|
||||
tree_out.packed_vertices.matrices.push_back(inst.mat);
|
||||
|
||||
for (size_t frag_idx = 0; frag_idx < proto.frags.size(); frag_idx++) {
|
||||
auto& frag = proto.frags[frag_idx]; // shared info for all instances of this frag
|
||||
|
||||
for (size_t draw_idx = 0; draw_idx < frag.draws.size(); draw_idx++) {
|
||||
auto& draw = frag.draws[draw_idx];
|
||||
|
||||
// what texture are we using?
|
||||
u32 combo_tex = draw.settings.combo_tex;
|
||||
|
||||
// try looking it up in the existing textures that we have in the C++ renderer data.
|
||||
// (this is shared with tfrag)
|
||||
u32 idx_in_lev_data = UINT32_MAX;
|
||||
for (u32 i = 0; i < lev.textures.size(); i++) {
|
||||
if (lev.textures[i].combo_id == combo_tex) {
|
||||
idx_in_lev_data = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx_in_lev_data == UINT32_MAX) {
|
||||
// didn't find it, have to add a new one texture.
|
||||
auto tex_it = tdb.textures.find(combo_tex);
|
||||
if (tex_it == tdb.textures.end()) {
|
||||
bool ok_to_miss = false; // for TIE, there's no missing textures.
|
||||
if (ok_to_miss) {
|
||||
// we're missing a texture, just use the first one.
|
||||
tex_it = tdb.textures.begin();
|
||||
} else {
|
||||
fmt::print(
|
||||
"texture {} wasn't found. make sure it is loaded somehow. You may need to "
|
||||
"include "
|
||||
"ART.DGO or GAME.DGO in addition to the level DGOs for shared textures.\n",
|
||||
combo_tex);
|
||||
fmt::print("tpage is {}\n", combo_tex >> 16);
|
||||
fmt::print("id is {} (0x{:x})\n", combo_tex & 0xffff, combo_tex & 0xffff);
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
// add a new texture to the level data
|
||||
idx_in_lev_data = lev.textures.size();
|
||||
lev.textures.emplace_back();
|
||||
auto& new_tex = lev.textures.back();
|
||||
new_tex.combo_id = combo_tex;
|
||||
new_tex.w = tex_it->second.w;
|
||||
new_tex.h = tex_it->second.h;
|
||||
new_tex.debug_name = tex_it->second.name;
|
||||
new_tex.debug_tpage_name = tdb.tpage_names.at(tex_it->second.page);
|
||||
new_tex.data = tex_it->second.rgba_bytes;
|
||||
}
|
||||
|
||||
DrawMode mode = draw.settings.mode;
|
||||
|
||||
// okay, we now have a texture and draw mode, let's see if we can add to an existing...
|
||||
auto existing_draws_in_tex = static_draws_by_tex.find(idx_in_lev_data);
|
||||
tfrag3::ShrubDraw* draw_to_add_to = nullptr;
|
||||
if (existing_draws_in_tex != static_draws_by_tex.end()) {
|
||||
for (auto idx : existing_draws_in_tex->second) {
|
||||
if (tree_out.static_draws.at(idx).mode == mode) {
|
||||
draw_to_add_to = &tree_out.static_draws[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!draw_to_add_to) {
|
||||
// nope, need to create a new draw
|
||||
tree_out.static_draws.emplace_back();
|
||||
static_draws_by_tex[idx_in_lev_data].push_back(tree_out.static_draws.size() - 1);
|
||||
draw_to_add_to = &tree_out.static_draws.back();
|
||||
draw_to_add_to->mode = mode;
|
||||
draw_to_add_to->tree_tex_id = idx_in_lev_data;
|
||||
}
|
||||
|
||||
// now we have a draw, time to add vertices
|
||||
// draw_to_add_to->num_triangles += draw.vertices.size() - 2;
|
||||
tfrag3::PackedShrubVertices::InstanceGroup grp;
|
||||
grp.matrix_idx = matrix_idx;
|
||||
grp.color_index = inst.color_idx;
|
||||
grp.start_vert = packed_vert_indices.at(frag_idx).at(draw_idx).first;
|
||||
grp.end_vert = packed_vert_indices.at(frag_idx).at(draw_idx).second;
|
||||
tree_out.packed_vertices.instance_groups.push_back(grp);
|
||||
|
||||
for (size_t vidx = 0; vidx < draw.vertices.size(); vidx++) {
|
||||
if (draw.vertices[vidx].adc) {
|
||||
draw_to_add_to->vertex_index_stream.push_back(vidx + global_vert_counter);
|
||||
draw_to_add_to->num_triangles++;
|
||||
} else {
|
||||
draw_to_add_to->vertex_index_stream.push_back(UINT32_MAX);
|
||||
draw_to_add_to->vertex_index_stream.push_back(vidx + global_vert_counter - 1);
|
||||
draw_to_add_to->vertex_index_stream.push_back(vidx + global_vert_counter);
|
||||
}
|
||||
}
|
||||
draw_to_add_to->vertex_index_stream.push_back(UINT32_MAX);
|
||||
|
||||
global_vert_counter += draw.vertices.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& draw : tree_out.static_draws) {
|
||||
draw.num_triangles = clean_up_vertex_indices(draw.vertex_index_stream);
|
||||
}
|
||||
tree_out.packed_vertices.total_vertex_count = global_vert_counter;
|
||||
}
|
||||
|
||||
void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
|
||||
const std::string& debug_name,
|
||||
const std::vector<level_tools::TextureRemap>& /*map*/,
|
||||
const TextureDB& /*tex_db*/,
|
||||
const std::vector<level_tools::TextureRemap>& map,
|
||||
const TextureDB& tex_db,
|
||||
const std::vector<std::pair<int, int>>& /*expected_missing_textures*/,
|
||||
tfrag3::Level& /*out*/,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level) {
|
||||
auto& tree_out = out.shrub_trees.emplace_back();
|
||||
auto& protos = tree->info.prototype_inline_array_shrub;
|
||||
std::vector<ShrubProtoInfo> proto_info;
|
||||
for (auto& proto : protos.data) {
|
||||
proto_info.push_back(extract_proto(proto));
|
||||
proto_info.push_back(extract_proto(proto, tex_db, map));
|
||||
}
|
||||
|
||||
for (auto& arr : tree->discovered_arrays) {
|
||||
|
@ -283,6 +601,17 @@ void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
|
|||
}
|
||||
}
|
||||
|
||||
// time of day colors
|
||||
tree_out.time_of_day_colors.resize(tree->time_of_day.height);
|
||||
for (int k = 0; k < (int)tree->time_of_day.height; k++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
memcpy(tree_out.time_of_day_colors[k].rgba[j].data(), &tree->time_of_day.colors[k * 8 + j],
|
||||
4);
|
||||
}
|
||||
}
|
||||
|
||||
make_draws(out, tree_out, proto_info, tex_db);
|
||||
|
||||
if (dump_level) {
|
||||
auto path = file_util::get_file_path({fmt::format("debug_out/shrub_all/{}.obj", debug_name)});
|
||||
file_util::create_dir_if_needed_for_file(path);
|
||||
|
|
|
@ -79,6 +79,7 @@ set(RUNTIME_SOURCE
|
|||
graphics/display.cpp
|
||||
graphics/sceGraphicsInterface.cpp
|
||||
graphics/opengl_renderer/background/background_common.cpp
|
||||
graphics/opengl_renderer/background/Shrub.cpp
|
||||
graphics/opengl_renderer/background/Tfrag3.cpp
|
||||
graphics/opengl_renderer/background/TFragment.cpp
|
||||
graphics/opengl_renderer/background/Tie3.cpp
|
||||
|
|
|
@ -131,6 +131,10 @@ void Loader::loader_thread() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
@ -276,6 +280,78 @@ bool Loader::init_tfrag(Timer& timer, LevelData& data) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Loader::init_shrub(Timer& timer, LevelData& data) {
|
||||
if (data.shrub_load_done) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (data.level->shrub_trees.empty()) {
|
||||
data.shrub_load_done = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!data.shrub_opengl_created) {
|
||||
for (auto& in_tree : data.level->shrub_trees) {
|
||||
GLuint& tree_out = data.shrub_vertex_data.emplace_back();
|
||||
glGenBuffers(1, &tree_out);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, tree_out);
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
in_tree.unpacked.vertices.size() * sizeof(tfrag3::ShrubGpuVertex), nullptr,
|
||||
GL_STATIC_DRAW);
|
||||
}
|
||||
data.shrub_opengl_created = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr u32 CHUNK_SIZE = 32768;
|
||||
u32 uploaded_bytes = 0;
|
||||
|
||||
while (true) {
|
||||
const auto& tree = data.level->shrub_trees[data.shrub_next_tree];
|
||||
u32 end_vert_in_tree = tree.unpacked.vertices.size();
|
||||
// the number of vertices we'd need to finish the tree right now
|
||||
size_t num_verts_left_in_tree = end_vert_in_tree - data.shrub_next_vert;
|
||||
size_t start_vert_for_chunk;
|
||||
size_t end_vert_for_chunk;
|
||||
|
||||
bool complete_tree;
|
||||
|
||||
if (num_verts_left_in_tree > CHUNK_SIZE) {
|
||||
complete_tree = false;
|
||||
// should only do partial
|
||||
start_vert_for_chunk = data.shrub_next_vert;
|
||||
end_vert_for_chunk = start_vert_for_chunk + CHUNK_SIZE;
|
||||
data.shrub_next_vert += CHUNK_SIZE;
|
||||
} else {
|
||||
// should do all!
|
||||
start_vert_for_chunk = data.shrub_next_vert;
|
||||
end_vert_for_chunk = end_vert_in_tree;
|
||||
complete_tree = true;
|
||||
}
|
||||
|
||||
// glBindVertexArray(m_trees[m_load_state.vert_geo][m_load_state.vert_tree].vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, data.shrub_vertex_data[data.shrub_next_tree]);
|
||||
u32 upload_size = (end_vert_for_chunk - start_vert_for_chunk) * sizeof(tfrag3::ShrubGpuVertex);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, start_vert_for_chunk * sizeof(tfrag3::ShrubGpuVertex),
|
||||
upload_size, tree.unpacked.vertices.data() + start_vert_for_chunk);
|
||||
uploaded_bytes += upload_size;
|
||||
|
||||
if (complete_tree) {
|
||||
// and move on to next tree
|
||||
data.shrub_next_vert = 0;
|
||||
data.shrub_next_tree++;
|
||||
if (data.shrub_next_tree >= data.level->shrub_trees.size()) {
|
||||
data.shrub_load_done = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer.getMs() > Loader::TIE_LOAD_BUDGET || (uploaded_bytes / 1024) > 2048) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Loader::init_tie(Timer& timer, LevelData& data) {
|
||||
if (data.tie_load_done) {
|
||||
return true;
|
||||
|
@ -511,12 +587,14 @@ void Loader::update(TexturePool& texture_pool) {
|
|||
if (upload_textures(loader_timer, lev.data, texture_pool)) {
|
||||
if (init_tie(loader_timer, lev.data)) {
|
||||
if (init_tfrag(loader_timer, lev.data)) {
|
||||
// we're done! lock before removing from loaded.
|
||||
lk.lock();
|
||||
it->second.data.load_id = m_id++;
|
||||
if (init_shrub(loader_timer, lev.data)) {
|
||||
// we're done! lock before removing from loaded.
|
||||
lk.lock();
|
||||
it->second.data.load_id = m_id++;
|
||||
|
||||
m_loaded_tfrag3_levels[name] = std::move(lev);
|
||||
m_initializing_tfrag3_levels.erase(it);
|
||||
m_loaded_tfrag3_levels[name] = std::move(lev);
|
||||
m_initializing_tfrag3_levels.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class Loader {
|
|||
};
|
||||
std::array<std::vector<TieOpenGL>, tfrag3::TIE_GEOS> tie_data;
|
||||
std::array<std::vector<GLuint>, tfrag3::TIE_GEOS> tfrag_vertex_data;
|
||||
std::vector<GLuint> shrub_vertex_data;
|
||||
|
||||
// internal load state
|
||||
bool tie_opengl_created = false;
|
||||
|
@ -45,6 +46,11 @@ class Loader {
|
|||
u32 tfrag_next_geo = 0;
|
||||
u32 tfrag_next_tree = 0;
|
||||
u32 tfrag_next_vert = 0;
|
||||
|
||||
bool shrub_opengl_created = false;
|
||||
bool shrub_load_done = false;
|
||||
u32 shrub_next_tree = 0;
|
||||
u32 shrub_next_vert = 0;
|
||||
};
|
||||
|
||||
const LevelData* get_tfrag3_level(const std::string& level_name);
|
||||
|
@ -63,6 +69,7 @@ class Loader {
|
|||
bool upload_textures(Timer& timer, LevelData& data, TexturePool& texture_pool);
|
||||
bool init_tie(Timer& timer, LevelData& data);
|
||||
bool init_tfrag(Timer& timer, LevelData& data);
|
||||
bool init_shrub(Timer& timer, LevelData& data);
|
||||
|
||||
// used by game and loader thread
|
||||
std::unordered_map<std::string, Level> m_initializing_tfrag3_levels;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "game/graphics/opengl_renderer/Sprite3.h"
|
||||
#include "game/graphics/opengl_renderer/background/TFragment.h"
|
||||
#include "game/graphics/opengl_renderer/background/Tie3.h"
|
||||
#include "game/graphics/opengl_renderer/background/Shrub.h"
|
||||
#include "game/graphics/opengl_renderer/MercRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/EyeRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/ShadowRenderer.h"
|
||||
|
@ -83,68 +84,82 @@ void OpenGLRenderer::init_bucket_renderers() {
|
|||
//-------------
|
||||
// PRE TEXTURE
|
||||
//-------------
|
||||
// 0
|
||||
// 1
|
||||
// 2
|
||||
init_bucket_renderer<SkyRenderer>("sky", BucketCategory::OTHER, BucketId::SKY_DRAW); // 3
|
||||
// 0 : ??
|
||||
// 1 : ??
|
||||
// 2 : ??
|
||||
// 3 : SKY_DRAW
|
||||
init_bucket_renderer<SkyRenderer>("sky", BucketCategory::OTHER, BucketId::SKY_DRAW);
|
||||
// 4 : OCEAN_MID_AND_FAR
|
||||
init_bucket_renderer<OceanMidAndFar>("ocean-mid-far", BucketCategory::OCEAN,
|
||||
BucketId::OCEAN_MID_AND_FAR); // 4
|
||||
BucketId::OCEAN_MID_AND_FAR);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 0 tfrag texture
|
||||
//-----------------------
|
||||
// 5 : TFRAG_TEX_LEVEL0
|
||||
init_bucket_renderer<TextureUploadHandler>("l0-tfrag-tex", BucketCategory::TEX,
|
||||
BucketId::TFRAG_TEX_LEVEL0); // 5
|
||||
BucketId::TFRAG_TEX_LEVEL0);
|
||||
// 6 : TFRAG_LEVEL0
|
||||
init_bucket_renderer<TFragment>("l0-tfrag-tfrag", BucketCategory::TFRAG, BucketId::TFRAG_LEVEL0,
|
||||
normal_tfrags, false,
|
||||
0); // 6
|
||||
// 7
|
||||
// 8
|
||||
init_bucket_renderer<Tie3>("l0-tfrag-tie", BucketCategory::TIE, BucketId::TIE_LEVEL0, 0); // 9
|
||||
normal_tfrags, false, 0);
|
||||
// 7 : TFRAG_NEAR_LEVEL0
|
||||
// 8 : TIE_NEAR_LEVEL0
|
||||
// 9 : TIE_LEVEL0
|
||||
init_bucket_renderer<Tie3>("l0-tfrag-tie", BucketCategory::TIE, BucketId::TIE_LEVEL0, 0);
|
||||
// 10 : MERC_TFRAG_TEX_LEVEL0
|
||||
init_bucket_renderer<MercRenderer>("l0-tfrag-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL0); // 10
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL0);
|
||||
// 11 : GMERC_TFRAG_TEX_LEVEL0
|
||||
init_bucket_renderer<GenericRenderer>("l0-tfrag-gmerc", BucketCategory::GENERIC_MERC,
|
||||
BucketId::GMERC_TFRAG_TEX_LEVEL0); // 11
|
||||
BucketId::GMERC_TFRAG_TEX_LEVEL0);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 1 tfrag texture
|
||||
//-----------------------
|
||||
// 12 : TFRAG_TEX_LEVEL1
|
||||
init_bucket_renderer<TextureUploadHandler>("l1-tfrag-tex", BucketCategory::TEX,
|
||||
BucketId::TFRAG_TEX_LEVEL1); // 12
|
||||
BucketId::TFRAG_TEX_LEVEL1);
|
||||
// 13 : TFRAG_LEVEL1
|
||||
init_bucket_renderer<TFragment>("l1-tfrag-tfrag", BucketCategory::TFRAG, BucketId::TFRAG_LEVEL1,
|
||||
normal_tfrags, false, 1);
|
||||
// 14
|
||||
// 15
|
||||
// 14 : TFRAG_NEAR_LEVEL1
|
||||
// 15 : TIE_NEAR_LEVEL1
|
||||
// 16 : TIE_LEVEL1
|
||||
init_bucket_renderer<Tie3>("l1-tfrag-tie", BucketCategory::TIE, BucketId::TIE_LEVEL1, 1);
|
||||
// 17 : MERC_TFRAG_TEX_LEVEL1
|
||||
init_bucket_renderer<MercRenderer>("l1-tfrag-merc", BucketCategory::MERC,
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL1); // 17
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL1);
|
||||
// 18 : GMERC_TFRAG_TEX_LEVEL1
|
||||
init_bucket_renderer<GenericRenderer>("l1-tfrag-gmerc", BucketCategory::GENERIC_MERC,
|
||||
BucketId::GMERC_TFRAG_TEX_LEVEL1); // 18
|
||||
BucketId::GMERC_TFRAG_TEX_LEVEL1);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 0 shrub texture
|
||||
//-----------------------
|
||||
// 19 : SHRUB_TEX_LEVEL0
|
||||
init_bucket_renderer<TextureUploadHandler>("l0-shrub-tex", BucketCategory::TEX,
|
||||
BucketId::SHRUB_TEX_LEVEL0); // 19
|
||||
// 20
|
||||
// 21
|
||||
// 22
|
||||
// 23
|
||||
// 24
|
||||
BucketId::SHRUB_TEX_LEVEL0);
|
||||
// 20 : SHRUB_NORMAL_LEVEL0
|
||||
init_bucket_renderer<Shrub>("l0-shrub", BucketCategory::SHRUB, BucketId::SHRUB_NORMAL_LEVEL0);
|
||||
// 21 : ???
|
||||
// 22 : SHRUB_BILLBOARD_LEVEL0
|
||||
// 23 : SHRUB_TRANS_LEVEL0
|
||||
// 24 : SHRUB_GENERIC_LEVEL0
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 1 shrub texture
|
||||
//-----------------------
|
||||
// 25 : SHRUB_TEX_LEVEL1
|
||||
init_bucket_renderer<TextureUploadHandler>("l1-shrub-tex", BucketCategory::TEX,
|
||||
BucketId::SHRUB_TEX_LEVEL1); // 25
|
||||
// 26
|
||||
// 27
|
||||
// 28
|
||||
// 29
|
||||
|
||||
// I don't think this is actually used? or it might be wrong.
|
||||
init_bucket_renderer<GenericRenderer>("common-shrub-generic", BucketCategory::GENERIC_MERC,
|
||||
BucketId::GENERIC_SHRUB); // 30
|
||||
BucketId::SHRUB_TEX_LEVEL1);
|
||||
// 26 : SHRUB_NORMAL_LEVEL1
|
||||
init_bucket_renderer<Shrub>("l1-shrub", BucketCategory::SHRUB, BucketId::SHRUB_NORMAL_LEVEL1);
|
||||
// 27 : ???
|
||||
// 28 : SHRUB_BILLBOARD_LEVEL1
|
||||
// 29 : SHRUB_TRANS_LEVEL1
|
||||
// 30 : SHRUB_GENERIC_LEVEL1
|
||||
init_bucket_renderer<GenericRenderer>("mystery-generic", BucketCategory::GENERIC_MERC,
|
||||
BucketId::SHRUB_GENERIC_LEVEL1);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 0 alpha texture
|
||||
|
@ -251,9 +266,9 @@ void OpenGLRenderer::init_bucket_renderers() {
|
|||
init_bucket_renderer<RenderMux>("sprite", BucketCategory::SPRITE, BucketId::SPRITE,
|
||||
std::move(sprite_renderers)); // 66
|
||||
|
||||
init_bucket_renderer<DirectRenderer>("debug-draw-0", BucketCategory::DEBUG_DRAW,
|
||||
init_bucket_renderer<DirectRenderer>("debug-draw-0", BucketCategory::OTHER,
|
||||
BucketId::DEBUG_DRAW_0, 0x20000);
|
||||
init_bucket_renderer<DirectRenderer>("debug-draw-1", BucketCategory::DEBUG_DRAW,
|
||||
init_bucket_renderer<DirectRenderer>("debug-draw-1", BucketCategory::OTHER,
|
||||
BucketId::DEBUG_DRAW_1, 0x8000);
|
||||
|
||||
// for now, for any unset renderers, just set them to an EmptyBucketRenderer.
|
||||
|
|
|
@ -81,5 +81,6 @@ ShaderLibrary::ShaderLibrary() {
|
|||
at(ShaderId::OCEAN_TEXTURE) = {"ocean_texture"};
|
||||
at(ShaderId::OCEAN_TEXTURE_MIPMAP) = {"ocean_texture_mipmap"};
|
||||
at(ShaderId::OCEAN_COMMON) = {"ocean_common"};
|
||||
at(ShaderId::SHRUB) = {"shrub"};
|
||||
at(ShaderId::SHADOW) = {"shadow"};
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ enum class ShaderId {
|
|||
OCEAN_TEXTURE_MIPMAP = 14,
|
||||
OCEAN_COMMON = 15,
|
||||
SHADOW = 16,
|
||||
SHRUB = 17,
|
||||
MAX_SHADERS
|
||||
};
|
||||
|
||||
|
|
303
game/graphics/opengl_renderer/background/Shrub.cpp
Normal file
303
game/graphics/opengl_renderer/background/Shrub.cpp
Normal file
|
@ -0,0 +1,303 @@
|
|||
#include "Shrub.h"
|
||||
|
||||
Shrub::Shrub(const std::string& name, BucketId my_id) : BucketRenderer(name, my_id) {
|
||||
m_color_result.resize(TIME_OF_DAY_COLOR_COUNT);
|
||||
}
|
||||
|
||||
Shrub::~Shrub() {
|
||||
discard_tree_cache();
|
||||
}
|
||||
|
||||
void Shrub::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
if (!m_enabled) {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto data0 = dma.read_and_advance();
|
||||
ASSERT(data0.vif1() == 0);
|
||||
ASSERT(data0.vif0() == 0);
|
||||
ASSERT(data0.size_bytes == 0);
|
||||
|
||||
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
|
||||
// renderer didn't run, let's just get out of here.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
||||
return;
|
||||
}
|
||||
|
||||
auto pc_port_data = dma.read_and_advance();
|
||||
ASSERT(pc_port_data.size_bytes == sizeof(TfragPcPortData));
|
||||
memcpy(&m_pc_port_data, pc_port_data.data, sizeof(TfragPcPortData));
|
||||
m_pc_port_data.level_name[11] = '\0';
|
||||
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
|
||||
TfragRenderSettings settings;
|
||||
settings.hvdf_offset = m_pc_port_data.hvdf_off;
|
||||
settings.fog = m_pc_port_data.fog;
|
||||
|
||||
memcpy(settings.math_camera.data(), m_pc_port_data.camera[0].data(), 64);
|
||||
settings.tree_idx = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
settings.time_of_day_weights[i] =
|
||||
2 * (0xff & m_pc_port_data.itimes[i / 2].data()[2 * (i % 2)]) / 127.f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
settings.planes[i] = m_pc_port_data.planes[i];
|
||||
render_state->camera_planes[i] = m_pc_port_data.planes[i];
|
||||
}
|
||||
render_state->has_camera_planes = true;
|
||||
|
||||
m_has_level = setup_for_level(m_pc_port_data.level_name, render_state);
|
||||
render_all_trees(settings, render_state, prof);
|
||||
}
|
||||
|
||||
void Shrub::update_load(const Loader::LevelData* loader_data) {
|
||||
const tfrag3::Level* lev_data = loader_data->level.get();
|
||||
// We changed level!
|
||||
discard_tree_cache();
|
||||
m_trees.resize(lev_data->shrub_trees.size());
|
||||
|
||||
size_t max_draws = 0;
|
||||
size_t time_of_day_count = 0;
|
||||
for (u32 l_tree = 0; l_tree < lev_data->shrub_trees.size(); l_tree++) {
|
||||
size_t idx_buffer_len = 0;
|
||||
const auto& tree = lev_data->shrub_trees[l_tree];
|
||||
max_draws = std::max(tree.static_draws.size(), max_draws);
|
||||
for (auto& draw : tree.static_draws) {
|
||||
idx_buffer_len += draw.vertex_index_stream.size();
|
||||
}
|
||||
time_of_day_count = std::max(tree.time_of_day_colors.size(), time_of_day_count);
|
||||
u32 verts = tree.unpacked.vertices.size();
|
||||
glGenVertexArrays(1, &m_trees[l_tree].vao);
|
||||
glBindVertexArray(m_trees[l_tree].vao);
|
||||
m_trees[l_tree].vertex_buffer = loader_data->shrub_vertex_data[l_tree];
|
||||
m_trees[l_tree].vert_count = verts;
|
||||
m_trees[l_tree].draws = &tree.static_draws;
|
||||
m_trees[l_tree].colors = &tree.time_of_day_colors;
|
||||
m_trees[l_tree].tod_cache = swizzle_time_of_day(tree.time_of_day_colors);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_trees[l_tree].vertex_buffer);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glEnableVertexAttribArray(3);
|
||||
|
||||
glVertexAttribPointer(0, // location 0 in the shader
|
||||
3, // 3 values per vert
|
||||
GL_FLOAT, // floats
|
||||
GL_FALSE, // normalized
|
||||
sizeof(tfrag3::ShrubGpuVertex), // stride
|
||||
(void*)offsetof(tfrag3::ShrubGpuVertex, x) // offset (0)
|
||||
);
|
||||
|
||||
glVertexAttribPointer(1, // location 1 in the shader
|
||||
2, // 3 values per vert
|
||||
GL_FLOAT, // floats
|
||||
GL_FALSE, // normalized
|
||||
sizeof(tfrag3::ShrubGpuVertex), // stride
|
||||
(void*)offsetof(tfrag3::ShrubGpuVertex, s) // offset (0)
|
||||
);
|
||||
|
||||
glVertexAttribPointer(2, // location 1 in the shader
|
||||
3, // 4 color components
|
||||
GL_UNSIGNED_BYTE, // u8
|
||||
GL_TRUE, // normalized (255 becomes 1)
|
||||
sizeof(tfrag3::ShrubGpuVertex), //
|
||||
(void*)offsetof(tfrag3::ShrubGpuVertex, rgba_base) //
|
||||
);
|
||||
|
||||
glVertexAttribIPointer(3, // location 2 in the shader
|
||||
1, // 1 values per vert
|
||||
GL_UNSIGNED_SHORT, // u16
|
||||
sizeof(tfrag3::ShrubGpuVertex), // stride
|
||||
(void*)offsetof(tfrag3::ShrubGpuVertex, color_index) // offset (0)
|
||||
);
|
||||
|
||||
glGenBuffers(1, &m_trees[l_tree].index_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_trees[l_tree].index_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_len * sizeof(u32), nullptr, GL_STREAM_DRAW);
|
||||
m_trees[l_tree].index_list.resize(idx_buffer_len);
|
||||
|
||||
glActiveTexture(GL_TEXTURE10);
|
||||
glGenTextures(1, &m_trees[l_tree].time_of_day_texture);
|
||||
glBindTexture(GL_TEXTURE_1D, m_trees[l_tree].time_of_day_texture);
|
||||
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, TIME_OF_DAY_COLOR_COUNT, 0, GL_RGBA,
|
||||
GL_UNSIGNED_INT_8_8_8_8, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
m_cache.draw_idx_temp.resize(max_draws);
|
||||
ASSERT(time_of_day_count <= TIME_OF_DAY_COLOR_COUNT);
|
||||
}
|
||||
|
||||
bool Shrub::setup_for_level(const std::string& level, SharedRenderState* render_state) {
|
||||
// make sure we have the level data.
|
||||
Timer tfrag3_setup_timer;
|
||||
auto lev_data = render_state->loader->get_tfrag3_level(level);
|
||||
if (!lev_data || (m_has_level && lev_data->load_id != m_load_id)) {
|
||||
m_has_level = false;
|
||||
m_textures = nullptr;
|
||||
m_level_name = "";
|
||||
discard_tree_cache();
|
||||
return false;
|
||||
}
|
||||
m_textures = &lev_data->textures;
|
||||
m_load_id = lev_data->load_id;
|
||||
|
||||
if (m_level_name != level) {
|
||||
update_load(lev_data);
|
||||
m_has_level = true;
|
||||
m_level_name = level;
|
||||
} else {
|
||||
m_has_level = true;
|
||||
}
|
||||
|
||||
if (tfrag3_setup_timer.getMs() > 5) {
|
||||
fmt::print("Shrub setup: {:.1f}ms\n", tfrag3_setup_timer.getMs());
|
||||
}
|
||||
|
||||
return m_has_level;
|
||||
}
|
||||
|
||||
void Shrub::discard_tree_cache() {
|
||||
for (auto& tree : m_trees) {
|
||||
glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture);
|
||||
glDeleteTextures(1, &tree.time_of_day_texture);
|
||||
glDeleteBuffers(1, &tree.index_buffer);
|
||||
glDeleteVertexArrays(1, &tree.vao);
|
||||
}
|
||||
|
||||
m_trees.clear();
|
||||
}
|
||||
|
||||
void Shrub::render_all_trees(const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
for (u32 i = 0; i < m_trees.size(); i++) {
|
||||
render_tree(i, settings, render_state, prof);
|
||||
}
|
||||
}
|
||||
|
||||
void Shrub::render_tree(int idx,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
Timer tree_timer;
|
||||
auto& tree = m_trees.at(idx);
|
||||
tree.perf.draws = 0;
|
||||
tree.perf.verts = 0;
|
||||
tree.perf.full_draws = 0;
|
||||
tree.perf.wind_draws = 0;
|
||||
if (!m_has_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_color_result.size() < tree.colors->size()) {
|
||||
m_color_result.resize(tree.colors->size());
|
||||
}
|
||||
|
||||
Timer interp_timer;
|
||||
interp_time_of_day_fast(settings.time_of_day_weights, tree.tod_cache, m_color_result.data());
|
||||
tree.perf.tod_time.add(interp_timer.getSeconds());
|
||||
|
||||
Timer setup_timer;
|
||||
glActiveTexture(GL_TEXTURE10);
|
||||
glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture);
|
||||
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, tree.colors->size(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
m_color_result.data());
|
||||
|
||||
first_tfrag_draw_setup(settings, render_state, ShaderId::SHRUB);
|
||||
|
||||
glBindVertexArray(tree.vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, tree.vertex_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tree.index_buffer);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
glPrimitiveRestartIndex(UINT32_MAX);
|
||||
tree.perf.tod_time.add(setup_timer.getSeconds());
|
||||
|
||||
int last_texture = -1;
|
||||
u32 idx_buffer_ptr = 0;
|
||||
|
||||
tree.perf.cull_time.add(0);
|
||||
Timer index_timer;
|
||||
idx_buffer_ptr = make_all_visible_index_list(m_cache.draw_idx_temp.data(), tree.index_list.data(),
|
||||
*tree.draws);
|
||||
tree.perf.index_time.add(index_timer.getSeconds());
|
||||
tree.perf.index_upload = sizeof(u32) * idx_buffer_ptr;
|
||||
|
||||
Timer draw_timer;
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_ptr * sizeof(u32), tree.index_list.data(),
|
||||
GL_STREAM_DRAW);
|
||||
|
||||
for (size_t draw_idx = 0; draw_idx < tree.draws->size(); draw_idx++) {
|
||||
const auto& draw = tree.draws->operator[](draw_idx);
|
||||
const auto& indices = m_cache.draw_idx_temp[draw_idx];
|
||||
|
||||
if (indices.second <= indices.first) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((int)draw.tree_tex_id != last_texture) {
|
||||
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
|
||||
last_texture = draw.tree_tex_id;
|
||||
}
|
||||
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::SHRUB);
|
||||
int draw_size = indices.second - indices.first;
|
||||
void* offset = (void*)(indices.first * sizeof(u32));
|
||||
|
||||
prof.add_draw_call();
|
||||
prof.add_tri(draw.num_triangles * (float)draw_size / draw.vertex_index_stream.size());
|
||||
|
||||
bool is_full = draw_size == (int)draw.vertex_index_stream.size();
|
||||
|
||||
tree.perf.draws++;
|
||||
if (is_full) {
|
||||
tree.perf.full_draws++;
|
||||
}
|
||||
tree.perf.verts += draw_size;
|
||||
|
||||
glDrawElements(GL_TRIANGLE_STRIP, draw_size, GL_UNSIGNED_INT, (void*)offset);
|
||||
|
||||
switch (double_draw.kind) {
|
||||
case DoubleDrawKind::NONE:
|
||||
break;
|
||||
case DoubleDrawKind::AFAIL_NO_DEPTH_WRITE:
|
||||
tree.perf.draws++;
|
||||
tree.perf.verts += draw_size;
|
||||
if (is_full) {
|
||||
tree.perf.full_draws++;
|
||||
}
|
||||
prof.add_draw_call();
|
||||
prof.add_tri(draw_size);
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SHRUB].id(), "alpha_min"),
|
||||
-10.f);
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SHRUB].id(), "alpha_max"),
|
||||
double_draw.aref_second);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDrawElements(GL_TRIANGLE_STRIP, draw_size, GL_UNSIGNED_INT, (void*)offset);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
tree.perf.draw_time.add(draw_timer.getSeconds());
|
||||
tree.perf.tree_time.add(tree_timer.getSeconds());
|
||||
}
|
||||
|
||||
void Shrub::draw_debug_window() {}
|
77
game/graphics/opengl_renderer/background/Shrub.h
Normal file
77
game/graphics/opengl_renderer/background/Shrub.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "game/graphics/gfx.h"
|
||||
#include "game/graphics/opengl_renderer/background/background_common.h"
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
#include "game/graphics/pipelines/opengl.h"
|
||||
#include "common/util/FilteredValue.h"
|
||||
|
||||
class Shrub : public BucketRenderer {
|
||||
public:
|
||||
Shrub(const std::string& name, BucketId my_id);
|
||||
~Shrub();
|
||||
bool setup_for_level(const std::string& level, SharedRenderState* render_state);
|
||||
void render_all_trees(const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof);
|
||||
void render_tree(int idx,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof);
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
|
||||
private:
|
||||
void update_load(const Loader::LevelData* loader_data);
|
||||
void discard_tree_cache();
|
||||
|
||||
struct Tree {
|
||||
GLuint vertex_buffer;
|
||||
GLuint index_buffer;
|
||||
GLuint time_of_day_texture;
|
||||
std::vector<u32> index_list;
|
||||
GLuint vao;
|
||||
u32 vert_count;
|
||||
const std::vector<tfrag3::ShrubDraw>* draws = nullptr;
|
||||
const std::vector<tfrag3::TieWindInstance>* instance_info = nullptr;
|
||||
const std::vector<tfrag3::TimeOfDayColor>* colors = nullptr;
|
||||
SwizzledTimeOfDay tod_cache;
|
||||
|
||||
std::vector<std::array<math::Vector4f, 4>> wind_matrix_cache;
|
||||
|
||||
bool has_wind = false;
|
||||
GLuint wind_vertex_index_buffer;
|
||||
std::vector<u32> wind_vertex_index_offsets;
|
||||
|
||||
struct {
|
||||
u32 index_upload = 0;
|
||||
u32 verts = 0;
|
||||
u32 draws = 0;
|
||||
u32 full_draws = 0; // ones that have all visible
|
||||
u32 wind_draws = 0;
|
||||
Filtered<float> cull_time;
|
||||
Filtered<float> index_time;
|
||||
Filtered<float> tod_time;
|
||||
Filtered<float> setup_time;
|
||||
Filtered<float> draw_time;
|
||||
Filtered<float> tree_time;
|
||||
} perf;
|
||||
};
|
||||
|
||||
std::vector<Tree> m_trees;
|
||||
std::string m_level_name;
|
||||
const std::vector<GLuint>* m_textures;
|
||||
u64 m_load_id = -1;
|
||||
|
||||
std::vector<math::Vector<u8, 4>> m_color_result;
|
||||
|
||||
static constexpr int TIME_OF_DAY_COLOR_COUNT = 8192;
|
||||
bool m_has_level = false;
|
||||
|
||||
struct Cache {
|
||||
std::vector<std::pair<int, int>> draw_idx_temp;
|
||||
} m_cache;
|
||||
TfragPcPortData m_pc_port_data;
|
||||
};
|
|
@ -184,7 +184,7 @@ void Tfrag3::render_tree(int geom,
|
|||
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, tree.colors->size(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
m_color_result.data());
|
||||
|
||||
first_tfrag_draw_setup(settings, render_state);
|
||||
first_tfrag_draw_setup(settings, render_state, ShaderId::TFRAG3);
|
||||
|
||||
glBindVertexArray(tree.vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, tree.vertex_buffer);
|
||||
|
@ -212,7 +212,7 @@ void Tfrag3::render_tree(int geom,
|
|||
|
||||
ASSERT(m_textures);
|
||||
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode);
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::TFRAG3);
|
||||
tree.tris_this_frame += draw.num_triangles;
|
||||
tree.draws_this_frame++;
|
||||
int draw_size = indices.second - indices.first;
|
||||
|
|
|
@ -360,6 +360,7 @@ void Tie3::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfi
|
|||
if (!m_override_level) {
|
||||
m_has_level = setup_for_level(m_pc_port_data.level_name, render_state);
|
||||
}
|
||||
|
||||
render_all_trees(lod(), settings, render_state, prof);
|
||||
}
|
||||
|
||||
|
@ -441,7 +442,7 @@ void Tie3::render_tree_wind(int idx,
|
|||
glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id));
|
||||
last_texture = draw.tree_tex_id;
|
||||
}
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode);
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::TFRAG3);
|
||||
|
||||
int off = 0;
|
||||
for (auto& grp : draw.instance_groups) {
|
||||
|
@ -524,7 +525,7 @@ void Tie3::render_tree(int idx,
|
|||
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, tree.colors->size(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
m_color_result.data());
|
||||
|
||||
first_tfrag_draw_setup(settings, render_state);
|
||||
first_tfrag_draw_setup(settings, render_state, ShaderId::TFRAG3);
|
||||
|
||||
glBindVertexArray(tree.vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, tree.vertex_buffer);
|
||||
|
@ -574,7 +575,7 @@ void Tie3::render_tree(int idx,
|
|||
last_texture = draw.tree_tex_id;
|
||||
}
|
||||
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode);
|
||||
auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::TFRAG3);
|
||||
int draw_size = indices.second - indices.first;
|
||||
void* offset = (void*)(indices.first * sizeof(u32));
|
||||
|
||||
|
|
|
@ -132,30 +132,31 @@ DoubleDraw setup_opengl_from_draw_mode(DrawMode mode, u32 tex_unit, bool mipmap)
|
|||
return double_draw;
|
||||
}
|
||||
|
||||
DoubleDraw setup_tfrag_shader(SharedRenderState* render_state, DrawMode mode) {
|
||||
DoubleDraw setup_tfrag_shader(SharedRenderState* render_state, DrawMode mode, ShaderId shader) {
|
||||
auto draw_settings = setup_opengl_from_draw_mode(mode, GL_TEXTURE0, true);
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "alpha_min"),
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[shader].id(), "alpha_min"),
|
||||
draw_settings.aref_first);
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "alpha_max"),
|
||||
10.f);
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[shader].id(), "alpha_max"), 10.f);
|
||||
return draw_settings;
|
||||
}
|
||||
|
||||
void first_tfrag_draw_setup(const TfragRenderSettings& settings, SharedRenderState* render_state) {
|
||||
render_state->shaders[ShaderId::TFRAG3].activate();
|
||||
glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "tex_T0"), 0);
|
||||
glUniformMatrix4fv(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "camera"),
|
||||
1, GL_FALSE, settings.math_camera.data());
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "hvdf_offset"),
|
||||
void first_tfrag_draw_setup(const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ShaderId shader) {
|
||||
render_state->shaders[shader].activate();
|
||||
glUniform1i(glGetUniformLocation(render_state->shaders[shader].id(), "tex_T0"), 0);
|
||||
glUniformMatrix4fv(glGetUniformLocation(render_state->shaders[shader].id(), "camera"), 1,
|
||||
GL_FALSE, settings.math_camera.data());
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[shader].id(), "hvdf_offset"),
|
||||
settings.hvdf_offset[0], settings.hvdf_offset[1], settings.hvdf_offset[2],
|
||||
settings.hvdf_offset[3]);
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "fog_constant"),
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[shader].id(), "fog_constant"),
|
||||
settings.fog.x());
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "fog_min"),
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[shader].id(), "fog_min"),
|
||||
settings.fog.y());
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "fog_max"),
|
||||
glUniform1f(glGetUniformLocation(render_state->shaders[shader].id(), "fog_max"),
|
||||
settings.fog.z());
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "fog_color"),
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[shader].id(), "fog_color"),
|
||||
render_state->fog_color[0], render_state->fog_color[1], render_state->fog_color[2],
|
||||
render_state->fog_intensity);
|
||||
}
|
||||
|
@ -499,6 +500,23 @@ u32 make_all_visible_index_list(std::pair<int, int>* group_out,
|
|||
return idx_buffer_ptr;
|
||||
}
|
||||
|
||||
u32 make_all_visible_index_list(std::pair<int, int>* group_out,
|
||||
u32* idx_out,
|
||||
const std::vector<tfrag3::ShrubDraw>& draws) {
|
||||
int idx_buffer_ptr = 0;
|
||||
for (size_t i = 0; i < draws.size(); i++) {
|
||||
const auto& draw = draws[i];
|
||||
std::pair<int, int> ds;
|
||||
ds.first = idx_buffer_ptr;
|
||||
memcpy(&idx_out[idx_buffer_ptr], draw.vertex_index_stream.data(),
|
||||
draw.vertex_index_stream.size() * sizeof(u32));
|
||||
idx_buffer_ptr += draw.vertex_index_stream.size();
|
||||
ds.second = idx_buffer_ptr;
|
||||
group_out[i] = ds;
|
||||
}
|
||||
return idx_buffer_ptr;
|
||||
}
|
||||
|
||||
u32 make_index_list_from_vis_string(std::pair<int, int>* group_out,
|
||||
u32* idx_out,
|
||||
const std::vector<tfrag3::StripDraw>& draws,
|
||||
|
|
|
@ -23,10 +23,12 @@ struct DoubleDraw {
|
|||
float aref_second = 0.;
|
||||
};
|
||||
|
||||
DoubleDraw setup_tfrag_shader(SharedRenderState* render_state, DrawMode mode);
|
||||
DoubleDraw setup_tfrag_shader(SharedRenderState* render_state, DrawMode mode, ShaderId shader);
|
||||
DoubleDraw setup_opengl_from_draw_mode(DrawMode mode, u32 tex_unit, bool mipmap);
|
||||
|
||||
void first_tfrag_draw_setup(const TfragRenderSettings& settings, SharedRenderState* render_state);
|
||||
void first_tfrag_draw_setup(const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ShaderId shader);
|
||||
void interp_time_of_day_slow(const float weights[8],
|
||||
const std::vector<tfrag3::TimeOfDayColor>& in,
|
||||
math::Vector<u8, 4>* out);
|
||||
|
@ -64,4 +66,7 @@ u32 make_index_list_from_vis_string(std::pair<int, int>* group_out,
|
|||
const std::vector<u8>& vis_data);
|
||||
u32 make_all_visible_index_list(std::pair<int, int>* group_out,
|
||||
u32* idx_out,
|
||||
const std::vector<tfrag3::StripDraw>& draws);
|
||||
const std::vector<tfrag3::StripDraw>& draws);
|
||||
u32 make_all_visible_index_list(std::pair<int, int>* group_out,
|
||||
u32* idx_out,
|
||||
const std::vector<tfrag3::ShrubDraw>& draws);
|
|
@ -10,30 +10,30 @@ enum class BucketId {
|
|||
OCEAN_MID_AND_FAR = 4,
|
||||
TFRAG_TEX_LEVEL0 = 5,
|
||||
TFRAG_LEVEL0 = 6,
|
||||
// 7
|
||||
// 8
|
||||
TFRAG_NEAR_LEVEL0 = 7,
|
||||
TIE_NEAR_LEVEL0 = 8,
|
||||
TIE_LEVEL0 = 9,
|
||||
MERC_TFRAG_TEX_LEVEL0 = 10,
|
||||
GMERC_TFRAG_TEX_LEVEL0 = 11,
|
||||
TFRAG_TEX_LEVEL1 = 12,
|
||||
TFRAG_LEVEL1 = 13,
|
||||
// 14
|
||||
// 15
|
||||
TFRAG_NEAR_LEVEL1 = 14,
|
||||
TIE_NEAR_LEVEL1 = 15,
|
||||
TIE_LEVEL1 = 16,
|
||||
MERC_TFRAG_TEX_LEVEL1 = 17,
|
||||
GMERC_TFRAG_TEX_LEVEL1 = 18,
|
||||
SHRUB_TEX_LEVEL0 = 19,
|
||||
// 20
|
||||
SHRUB_NORMAL_LEVEL0 = 20,
|
||||
// 21
|
||||
// 22
|
||||
// 23
|
||||
// 24
|
||||
SHRUB_BILLBOARD_LEVEL0 = 22,
|
||||
SHRUB_TRANS_LEVEL0 = 23,
|
||||
SHRUB_GENERIC_LEVEL0 = 24,
|
||||
SHRUB_TEX_LEVEL1 = 25,
|
||||
// 26
|
||||
SHRUB_NORMAL_LEVEL1 = 26,
|
||||
// 27
|
||||
// 28
|
||||
// 29
|
||||
GENERIC_SHRUB = 30,
|
||||
SHRUB_BILLBOARD_LEVEL1 = 28,
|
||||
SHRUB_TRANS_LEVEL1 = 29,
|
||||
SHRUB_GENERIC_LEVEL1 = 30,
|
||||
ALPHA_TEX_LEVEL0 = 31,
|
||||
TFRAG_TRANS0_AND_SKY_BLEND_LEVEL0 = 32,
|
||||
// 33
|
||||
|
@ -78,15 +78,15 @@ enum class BucketId {
|
|||
enum class BucketCategory {
|
||||
TFRAG,
|
||||
TIE,
|
||||
SHRUB,
|
||||
TEX,
|
||||
MERC,
|
||||
GENERIC_MERC,
|
||||
SPRITE,
|
||||
OCEAN,
|
||||
DEBUG_DRAW,
|
||||
OTHER,
|
||||
MAX_CATEGORIES
|
||||
};
|
||||
|
||||
constexpr const char* BUCKET_CATEGORY_NAMES[(int)BucketCategory::MAX_CATEGORIES] = {
|
||||
"tfrag", "tie", "tex", "merc", "mercneric", "sprite", "ocean", "debug", "other"};
|
||||
"tfrag", "tie", "shrub", "tex", "merc", "mercneric", "sprite", "ocean", "other"};
|
28
game/graphics/opengl_renderer/shaders/shrub.frag
Normal file
28
game/graphics/opengl_renderer/shaders/shrub.frag
Normal file
|
@ -0,0 +1,28 @@
|
|||
#version 430 core
|
||||
|
||||
out vec4 color;
|
||||
|
||||
in vec4 fragment_color;
|
||||
in vec3 tex_coord;
|
||||
in float fogginess;
|
||||
uniform sampler2D tex_T0;
|
||||
|
||||
uniform float alpha_min;
|
||||
uniform float alpha_max;
|
||||
uniform vec4 fog_color;
|
||||
|
||||
void main() {
|
||||
vec4 T0 = texture(tex_T0, tex_coord.xy / 4096.f);
|
||||
color = fragment_color * T0 * 2.0;
|
||||
color.w *= 2;
|
||||
|
||||
if (color.a < alpha_min * 2) {
|
||||
discard;
|
||||
}
|
||||
|
||||
if (color.a > alpha_max) {
|
||||
discard;
|
||||
}
|
||||
|
||||
color.xyz = mix(color.xyz, fog_color.xyz / 255., clamp(fogginess/255 * fog_color.w, 0., 1.));
|
||||
}
|
86
game/graphics/opengl_renderer/shaders/shrub.vert
Normal file
86
game/graphics/opengl_renderer/shaders/shrub.vert
Normal file
|
@ -0,0 +1,86 @@
|
|||
#version 430 core
|
||||
|
||||
layout (location = 0) in vec3 position_in;
|
||||
layout (location = 1) in vec3 tex_coord_in;
|
||||
layout (location = 2) in vec3 rgba_base;
|
||||
layout (location = 3) in int time_of_day_index;
|
||||
|
||||
uniform vec4 hvdf_offset;
|
||||
uniform mat4 camera;
|
||||
uniform float fog_constant;
|
||||
uniform float fog_min;
|
||||
uniform float fog_max;
|
||||
layout (binding = 10) uniform sampler1D tex_T1; // note, sampled in the vertex shader on purpose.
|
||||
|
||||
out vec4 fragment_color;
|
||||
out vec3 tex_coord;
|
||||
out float fogginess;
|
||||
|
||||
void main() {
|
||||
|
||||
|
||||
// old system:
|
||||
// - load vf12
|
||||
// - itof0 vf12
|
||||
// - multiply with camera matrix (add trans)
|
||||
// - let Q = fogx / vf12.w
|
||||
// - xyz *= Q
|
||||
// - xyzw += hvdf_offset
|
||||
// - clip w.
|
||||
// - ftoi4 vf12
|
||||
// use in gs.
|
||||
// gs is 12.4 fixed point, set up with 2048.0 as the center.
|
||||
|
||||
// the itof0 is done in the preprocessing step. now we have floats.
|
||||
|
||||
// Step 3, the camera transform
|
||||
vec4 transformed = -camera[3].xyzw;
|
||||
transformed += -camera[0] * position_in.x;
|
||||
transformed += -camera[1] * position_in.y;
|
||||
transformed += -camera[2] * position_in.z;
|
||||
|
||||
// compute Q
|
||||
float Q = fog_constant / transformed[3];
|
||||
|
||||
float fog1 = -transformed.w + hvdf_offset.w;
|
||||
float fog2 = min(fog1, fog_max);
|
||||
float fog3 = max(fog2, fog_min);
|
||||
fogginess = 255 - fog3;
|
||||
|
||||
// perspective divide!
|
||||
transformed.xyz *= Q;
|
||||
|
||||
// offset
|
||||
transformed.xyz += hvdf_offset.xyz;
|
||||
|
||||
// ftoi4
|
||||
//transformed.xyzw *= 16;
|
||||
|
||||
// correct xy offset
|
||||
transformed.xy -= (2048.);
|
||||
|
||||
// correct z scale
|
||||
transformed.z /= (8388608);
|
||||
transformed.z -= 1;
|
||||
|
||||
// correct xy scale
|
||||
transformed.x /= (256);
|
||||
transformed.y /= -(128);
|
||||
|
||||
// hack
|
||||
transformed.xyz *= transformed.w;
|
||||
|
||||
gl_Position = transformed;
|
||||
// scissoring area adjust
|
||||
gl_Position.y *= 512.0/448.0;
|
||||
|
||||
// time of day lookup
|
||||
// start with the vertex color (only rgb, VIF filled in the 255.)
|
||||
fragment_color = vec4(rgba_base, 1);
|
||||
// get the time of day multiplier
|
||||
vec4 tod_color = texelFetch(tex_T1, time_of_day_index, 0);
|
||||
// combine
|
||||
fragment_color *= tod_color * 2;
|
||||
|
||||
tex_coord = tex_coord_in;
|
||||
}
|
|
@ -213,31 +213,34 @@
|
|||
:type int32
|
||||
:bitfield #f
|
||||
|
||||
(bucket-1 1)
|
||||
(bucket-2 2)
|
||||
(sky-draw 3)
|
||||
(bucket-4 4) ;; ocean
|
||||
(tfrag-tex0 5)
|
||||
(tfrag-0 6)
|
||||
(tfrag-near-0 7)
|
||||
(tie-near-0 8)
|
||||
(tie-0 9)
|
||||
(bucket-10 10) ;; merc
|
||||
(bucket-11 11)
|
||||
(bucket-0 0) ;; ?
|
||||
(bucket-1 1) ;; ?
|
||||
(bucket-2 2) ;; ?
|
||||
(sky-draw 3) ;; actual sky and cloud framebuffer draws
|
||||
(ocean-mid-and-far 4) ;; actual ocean framebuffer draws for mid/transition/far
|
||||
|
||||
(tfrag-tex1 12)
|
||||
(tfrag-1 13)
|
||||
(tfrag-near-1 14)
|
||||
(tie-near-1 15)
|
||||
(tie-1 16)
|
||||
;; merc1 17
|
||||
;; generic1 18
|
||||
(bucket-17 17) ;; merc
|
||||
(bucket-18 18)
|
||||
(tfrag-tex0 5) ;; tfrag texture upload, level 0
|
||||
(tfrag-0 6) ;; tfrag draw, level 0
|
||||
(tfrag-near-0 7) ;; tfrag near draw, level 0
|
||||
(tie-near-0 8) ;; tie near draw, level 0
|
||||
(tie-0 9) ;; tie draw, level 0
|
||||
(merc-tfrag-tex0 10) ;; merc, with tfrag textures, level 0
|
||||
(gmerc-tfrag-tex 11) ;; generic merc, with tfrag textures, level 0
|
||||
|
||||
(tfrag-tex1 12) ;; tfrag texture upload, level 1
|
||||
(tfrag-1 13) ;; tfrag draw, level 1
|
||||
(tfrag-near-1 14) ;; tfrag near draw, level 1
|
||||
(tie-near-1 15) ;; tie near draw, level 1
|
||||
(tie-1 16) ;; tie draw, level 1
|
||||
(merc-tfrag-tex1 17) ;; merc, with tfrag textures, level 1
|
||||
(gmerc-tfrag-tex1 18) ;; generic merc, with tfrag textures, level 1
|
||||
(shrub-tex0 19)
|
||||
|
||||
(shrub0 20)
|
||||
|
||||
|
||||
(shrub-tex1 25)
|
||||
(shrub1 26)
|
||||
|
||||
|
||||
(generic-foreground 30) ;; ?
|
||||
(alpha-tex0 31)
|
||||
|
|
|
@ -37,3 +37,6 @@
|
|||
:size-assert #x248
|
||||
:flag-assert #x900000248
|
||||
)
|
||||
|
||||
|
||||
(define-extern add-pc-tfrag3-data (function dma-buffer level pointer))
|
|
@ -593,7 +593,7 @@
|
|||
"Setup merc DMA buffers. Call this _after_ drawing."
|
||||
(when (logtest? *vu1-enable-user* (vu1-renderer-mask merc))
|
||||
(merc-vu1-init-buffer
|
||||
(bucket-id bucket-10)
|
||||
(bucket-id merc-tfrag-tex0)
|
||||
(new 'static 'gs-test
|
||||
:ate #x1
|
||||
:atst (gs-atest greater-equal)
|
||||
|
@ -615,7 +615,7 @@
|
|||
0
|
||||
)
|
||||
(merc-vu1-init-buffer
|
||||
(bucket-id bucket-17)
|
||||
(bucket-id merc-tfrag-tex1)
|
||||
(new 'static 'gs-test
|
||||
:ate #x1
|
||||
:atst (gs-atest greater-equal)
|
||||
|
|
|
@ -661,7 +661,7 @@
|
|||
)
|
||||
(dma-bucket-insert-tag
|
||||
(-> *display* frames (-> *display* on-screen) frame bucket-group)
|
||||
(bucket-id bucket-4)
|
||||
(bucket-id ocean-mid-and-far)
|
||||
gp-1
|
||||
(the-as (pointer dma-tag) a3-0)
|
||||
)
|
||||
|
|
|
@ -475,6 +475,37 @@
|
|||
; (-> (the-as drawable-group (-> arg0 data 0)) length)
|
||||
; s3-0
|
||||
; )
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; NOTE: this part is completely rewritten for PC
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(when (logtest? *vu1-enable-user* (vu1-renderer-mask shrubbery))
|
||||
(let* ((s2-1 (-> *display* frames (-> *display* on-screen) frame global-buf))
|
||||
(s3-1 (-> s2-1 base))
|
||||
)
|
||||
(add-pc-tfrag3-data s2-1 (-> *level* data (-> (scratchpad-object terrain-context) bsp lev-index)))
|
||||
(let ((a3-22 (-> s2-1 base)))
|
||||
(let ((v1-57 (the-as object (-> s2-1 base))))
|
||||
(set! (-> (the-as dma-packet v1-57) dma) (new 'static 'dma-tag :id (dma-tag-id next)))
|
||||
(set! (-> (the-as dma-packet v1-57) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet v1-57) vif1) (new 'static 'vif-tag))
|
||||
(set! (-> s2-1 base) (&+ (the-as pointer v1-57) 16))
|
||||
)
|
||||
(dma-bucket-insert-tag
|
||||
(-> *display* frames (-> *display* on-screen) frame bucket-group)
|
||||
(the-as bucket-id (if (zero? (-> (scratchpad-object terrain-context) bsp lev-index))
|
||||
(bucket-id shrub0)
|
||||
(bucket-id shrub1)
|
||||
)
|
||||
)
|
||||
s3-1
|
||||
(the-as (pointer dma-tag) a3-22)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(read! (-> *perf-stats* data (perf-stat-bucket inst-shrub)))
|
||||
(reset! (-> *perf-stats* data (perf-stat-bucket proto-shrub)))
|
||||
; (draw-prototype-inline-array-shrub s4-0 s3-0)
|
||||
|
|
4
test/decompiler/reference/engine/gfx/merc/merc_REF.gc
generated
vendored
4
test/decompiler/reference/engine/gfx/merc/merc_REF.gc
generated
vendored
|
@ -493,7 +493,7 @@
|
|||
(defun merc-vu1-init-buffers ()
|
||||
(when (logtest? *vu1-enable-user* (vu1-renderer-mask merc))
|
||||
(merc-vu1-init-buffer
|
||||
(bucket-id bucket-10)
|
||||
(bucket-id merc-tfrag-tex0)
|
||||
(new 'static 'gs-test
|
||||
:ate #x1
|
||||
:atst (gs-atest greater-equal)
|
||||
|
@ -515,7 +515,7 @@
|
|||
0
|
||||
)
|
||||
(merc-vu1-init-buffer
|
||||
(bucket-id bucket-17)
|
||||
(bucket-id merc-tfrag-tex1)
|
||||
(new 'static 'gs-test
|
||||
:ate #x1
|
||||
:atst (gs-atest greater-equal)
|
||||
|
|
8
test/decompiler/reference/engine/level/level-h_REF.gc
generated
vendored
8
test/decompiler/reference/engine/level/level-h_REF.gc
generated
vendored
|
@ -339,8 +339,8 @@
|
|||
(new 'static 'dma-foreground-sink-group
|
||||
:sink
|
||||
(new 'static 'array dma-foreground-sink 3
|
||||
(new 'static 'dma-foreground-sink :bucket (bucket-id bucket-10))
|
||||
(new 'static 'generic-dma-foreground-sink :bucket (bucket-id bucket-11) :foreground-output-bucket 1)
|
||||
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-tfrag-tex0))
|
||||
(new 'static 'generic-dma-foreground-sink :bucket (bucket-id gmerc-tfrag-tex) :foreground-output-bucket 1)
|
||||
)
|
||||
)
|
||||
(new 'static 'dma-foreground-sink-group
|
||||
|
@ -380,9 +380,9 @@
|
|||
(new 'static 'dma-foreground-sink-group
|
||||
:sink
|
||||
(new 'static 'array dma-foreground-sink 3
|
||||
(new 'static 'dma-foreground-sink :bucket (bucket-id bucket-17) :foreground-texture-level 1)
|
||||
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-tfrag-tex1) :foreground-texture-level 1)
|
||||
(new 'static 'generic-dma-foreground-sink
|
||||
:bucket (bucket-id bucket-18)
|
||||
:bucket (bucket-id gmerc-tfrag-tex1)
|
||||
:foreground-texture-level 1
|
||||
:foreground-output-bucket 1
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue