2022-05-11 22:53:53 -04:00
|
|
|
#include "extract_merc.h"
|
2022-06-22 23:37:46 -04:00
|
|
|
|
2022-10-01 11:58:36 -04:00
|
|
|
#include "common/log/log.h"
|
2022-05-11 22:53:53 -04:00
|
|
|
#include "common/util/FileUtil.h"
|
|
|
|
#include "common/util/colors.h"
|
[merc2] Support texscroll, use in jak 1 in more places, fix envmap bug (#2303)
Three main changes:
- Adds support for the texture scrolling effect used on conveyor belts,
and turn it on for jak 2.
- Use merc instead of generic in jak 1 for ripple/water/texscroll stuff
(non-ocean water, lava, dark eco, etc). This is a pretty big speedup in
a lot of places.
- Fix a really old bug with blending mode used to draw environment maps.
The effect is that envmaps were half as bright as they should have been.
As usual, there's a flag to go back to the old behavior on jak 1. Set
these to `#t` to use generic like we used to.
```
*texscroll-force-generic*
*ripple-force-generic*
```
The format has changed, and everything must be rebuilt (C++, FR3's, GOAL
code)
2023-03-09 20:01:22 -05:00
|
|
|
#include "common/util/string_util.h"
|
2022-05-11 22:53:53 -04:00
|
|
|
|
2022-06-22 23:37:46 -04:00
|
|
|
#include "decompiler/level_extractor/MercData.h"
|
|
|
|
#include "decompiler/level_extractor/extract_common.h"
|
|
|
|
#include "decompiler/util/goal_data_reader.h"
|
|
|
|
|
2022-05-11 22:53:53 -04:00
|
|
|
namespace decompiler {
|
|
|
|
|
|
|
|
// number of slots on VU1 data memory to store matrices
|
|
|
|
constexpr int MERC_VU1_MATRIX_SLOTS = 18;
|
|
|
|
// the size of each "matrix". Includes a transformation and rotation matrix (for normals)
|
|
|
|
constexpr int MERC_MATRIX_STRIDE = 7;
|
|
|
|
|
|
|
|
// converts a vu1 address to an index of a matrix slot.
|
|
|
|
// as far as I can tell, nothing in the game uses indices, they are always addresses already
|
|
|
|
u32 vu1_addr_to_matrix_slot(u32 addr) {
|
|
|
|
ASSERT(addr >= 6);
|
|
|
|
ASSERT(addr < (6 + MERC_MATRIX_STRIDE * MERC_VU1_MATRIX_SLOTS));
|
|
|
|
addr -= 6;
|
|
|
|
ASSERT((addr % MERC_MATRIX_STRIDE) == 0);
|
|
|
|
return addr / MERC_MATRIX_STRIDE;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 matrix_slot_to_vu1_addr(u32 slot) {
|
|
|
|
ASSERT(slot < MERC_VU1_MATRIX_SLOTS);
|
|
|
|
return 6 + (slot * MERC_MATRIX_STRIDE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* The GS settings of a merc draw (shader + tex)
|
|
|
|
*/
|
|
|
|
struct MercGsState {
|
|
|
|
// the blending, clamp, etc settings. from adgif shaders
|
|
|
|
DrawMode mode;
|
|
|
|
// the texture to use, as a "pc combo" texture index.
|
|
|
|
u32 pc_combo_tex_id;
|
|
|
|
u64 as_u64() const { return (((u64)pc_combo_tex_id) << 32) | mode.as_int(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* This is all the state that's required to understand how to draw a vertex. including both the GS
|
|
|
|
* state, and stuff (matrices) left behind in VU memory. The matrix slots are matrix indices into
|
|
|
|
* the original bones matrices (all the matrices in the skeleton). An index of -1 indicates that
|
|
|
|
* there is no known matrix in this slot.
|
|
|
|
*/
|
|
|
|
struct MercState {
|
|
|
|
MercGsState merc_draw_mode;
|
|
|
|
// vu1_matrix_slots[x] = y
|
|
|
|
// where x is the slot in VU1 memory, and y is the matrix index for the bones/skeleton stuff.
|
|
|
|
std::array<int, MERC_VU1_MATRIX_SLOTS> vu1_matrix_slots;
|
|
|
|
MercState() { vu1_matrix_slots.fill(-1); }
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Required information for a "draw", consisting of a strip of triangles (represented as indices for
|
|
|
|
* OpenGL triangle strip) and the draw settings.
|
|
|
|
*/
|
|
|
|
struct MercDraw {
|
|
|
|
size_t ctrl_idx; // which merc ctrl in the level we correspond to
|
|
|
|
size_t effect_idx; // which effect within that control
|
|
|
|
size_t frag_idx; // which frag within that effect
|
|
|
|
// note that the above triple isn't enough to uniquely identify a draw - there can be multiple
|
|
|
|
// draws within a fragment.
|
|
|
|
|
|
|
|
// draw settings
|
|
|
|
MercState state;
|
|
|
|
|
|
|
|
// opengl indices. currently into a per-effect vertex list (likely to merge into a giant buffer
|
|
|
|
// eventually)
|
|
|
|
std::vector<u32> indices;
|
|
|
|
|
|
|
|
// where we would be in VU1 data memory (used in construction)
|
|
|
|
u32 vtx_offset; // relative to writing output zone
|
|
|
|
u32 vtx_nloop; // nloop that goes in the gif tag drawing us.
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Merc Vertex. Not the format we'll want in the game data files, but most useful as an intermediate
|
|
|
|
* when building up draws.
|
|
|
|
*/
|
|
|
|
struct MercUnpackedVtx {
|
|
|
|
int kind = 0; // 1, 2, or 3 matrix
|
|
|
|
math::Vector3f pos; // position
|
|
|
|
math::Vector3f nrm; // normal (as input to the merc math, pretty sure legnth is bogus)
|
|
|
|
math::Vector2f st; // texture coordinates
|
|
|
|
math::Vector<u8, 4> rgba;
|
|
|
|
|
|
|
|
int skel_mats[3];
|
|
|
|
float mat_weights[3];
|
|
|
|
|
|
|
|
u16 dst0;
|
|
|
|
u16 dst1;
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
|
|
|
|
bool can_be_modified = false;
|
|
|
|
int idx_in_combined_lump4 = -1; // divided by 3
|
|
|
|
|
|
|
|
int flump4 = -1;
|
|
|
|
int frag = -1;
|
2022-05-11 22:53:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* An entire merc-effect, split into draws.
|
|
|
|
* Note that copied or multiply-placed vertices will be de-deduplicated, but not identical vertices
|
|
|
|
* that actually appear in the input to merc.
|
|
|
|
*/
|
|
|
|
struct ConvertedMercEffect {
|
|
|
|
size_t ctrl_idx;
|
|
|
|
size_t effect_idx;
|
|
|
|
// draws from all fragments.
|
|
|
|
std::vector<MercDraw> draws;
|
|
|
|
std::vector<MercUnpackedVtx> vertices;
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
std::vector<u32> verts_per_frag;
|
2023-01-22 18:30:31 -05:00
|
|
|
bool has_envmap = false;
|
|
|
|
DrawMode envmap_mode;
|
|
|
|
u32 envmap_texture;
|
2023-03-08 18:18:35 -05:00
|
|
|
std::optional<s8> eye_slot;
|
2022-05-11 22:53:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Extract a merc-ctrl data structure. This is mostly just copying the GOAL data to C++ classes,
|
|
|
|
* but does include the effect of processing the DMA data through VIF.
|
|
|
|
*/
|
|
|
|
MercCtrl extract_merc_ctrl(const LinkedObjectFile& file,
|
|
|
|
const DecompilerTypeSystem& dts,
|
|
|
|
int word_idx) {
|
|
|
|
Ref ref;
|
|
|
|
ref.data = &file;
|
|
|
|
ref.seg = 0;
|
|
|
|
ref.byte_offset = word_idx * 4;
|
|
|
|
|
|
|
|
auto tr = typed_ref_from_basic(ref, dts);
|
|
|
|
|
|
|
|
MercCtrl ctrl;
|
2023-03-26 12:30:35 -04:00
|
|
|
ctrl.from_ref(tr, dts, file.version); // the merc data import
|
2022-05-11 22:53:53 -04:00
|
|
|
return ctrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Find the word indices for the merc ctrls (the type tags)
|
|
|
|
*/
|
|
|
|
std::vector<int> find_merc_ctrls(const LinkedObjectFile& file) {
|
|
|
|
std::vector<int> result;
|
|
|
|
for (size_t i = 0; i < file.words_by_seg.at(0).size(); i++) {
|
|
|
|
const auto& word = file.words_by_seg[0][i];
|
|
|
|
if (word.kind() == LinkedWord::TYPE_PTR && word.symbol_name() == "merc-ctrl") {
|
|
|
|
result.push_back(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/*!
|
|
|
|
* Merc models tend to have strange texture ids. I don't really understand why.
|
|
|
|
* On login, the texture is checked against a list of textures in the bsp, and replaced with this.
|
|
|
|
* It doesn't seem to be related to sharing textures between levels - the yakow texture uses this.
|
|
|
|
*/
|
|
|
|
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) {
|
|
|
|
return t.new_texid | 20;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return original;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Set the alpha fields of a DrawMode (for PC renderers) based on gs alpha register
|
|
|
|
*/
|
|
|
|
void update_mode_from_alpha1(GsAlpha reg, DrawMode& mode) {
|
|
|
|
if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && reg.b_mode() == GsAlpha::BlendMode::DEST &&
|
|
|
|
reg.c_mode() == GsAlpha::BlendMode::SOURCE && reg.d_mode() == GsAlpha::BlendMode::DEST) {
|
|
|
|
// (Cs - Cd) * As + Cd
|
|
|
|
// Cs * As + (1 - As) * Cd
|
|
|
|
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
|
|
|
|
|
|
|
} else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE &&
|
|
|
|
reg.b_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
|
|
|
reg.c_mode() == GsAlpha::BlendMode::SOURCE &&
|
|
|
|
reg.d_mode() == GsAlpha::BlendMode::DEST) {
|
|
|
|
// (Cs - 0) * As + Cd
|
|
|
|
// Cs * As + (1) * CD
|
|
|
|
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_SRC_DST);
|
|
|
|
} else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE &&
|
|
|
|
reg.b_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
|
|
|
reg.c_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
|
|
|
reg.d_mode() == GsAlpha::BlendMode::DEST) {
|
|
|
|
ASSERT(reg.fix() == 128);
|
|
|
|
// Cv = (Cs - 0) * FIX + Cd
|
|
|
|
// if fix = 128, it works out to 1.0
|
|
|
|
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_FIX_DST);
|
|
|
|
// src plus dest
|
|
|
|
} else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE &&
|
|
|
|
reg.b_mode() == GsAlpha::BlendMode::DEST &&
|
|
|
|
reg.c_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
|
|
|
reg.d_mode() == GsAlpha::BlendMode::DEST) {
|
|
|
|
// Cv = (Cs - Cd) * FIX + Cd
|
|
|
|
ASSERT(reg.fix() == 64);
|
|
|
|
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_FIX_DST);
|
|
|
|
} else if (reg.a_mode() == GsAlpha::BlendMode::DEST &&
|
|
|
|
reg.b_mode() == GsAlpha::BlendMode::SOURCE &&
|
|
|
|
reg.c_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
|
|
|
reg.d_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED) {
|
2023-01-22 18:30:31 -05:00
|
|
|
} else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE &&
|
|
|
|
reg.b_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
|
|
|
reg.c_mode() == GsAlpha::BlendMode::DEST && reg.d_mode() == GsAlpha::BlendMode::DEST) {
|
|
|
|
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
|
2022-05-11 22:53:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
// unsupported blend: a 0 b 1 c 0 d 2 is this part of generic?
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::warn("unsupported blend: a {} b {} c {} d {}", (int)reg.a_mode(), (int)reg.b_mode(),
|
|
|
|
(int)reg.c_mode(), (int)reg.d_mode());
|
2022-05-11 22:53:53 -04:00
|
|
|
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
|
|
|
// ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Convert merc shader to PC draw mode
|
|
|
|
*/
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
DrawMode process_draw_mode(const MercShader& info,
|
|
|
|
bool enable_alpha_test,
|
2023-03-25 14:00:54 -04:00
|
|
|
bool enable_alpha_blend,
|
2023-03-26 12:30:35 -04:00
|
|
|
bool depth_write,
|
|
|
|
bool fge) {
|
2022-05-11 22:53:53 -04:00
|
|
|
DrawMode mode;
|
|
|
|
/*
|
|
|
|
* (new 'static 'gs-test
|
|
|
|
:ate #x1
|
|
|
|
:atst (gs-atest greater-equal)
|
|
|
|
:aref #x26
|
|
|
|
:zte #x1
|
|
|
|
:ztst (gs-ztest greater-equal)
|
|
|
|
)
|
|
|
|
*/
|
2023-01-22 18:30:31 -05:00
|
|
|
mode.set_at(enable_alpha_test);
|
2022-05-11 22:53:53 -04:00
|
|
|
mode.set_alpha_test(DrawMode::AlphaTest::GEQUAL);
|
|
|
|
mode.set_aref(0x26);
|
|
|
|
mode.set_alpha_fail(GsTest::AlphaFail::KEEP);
|
|
|
|
mode.set_alpha_test(DrawMode::AlphaTest::GEQUAL);
|
|
|
|
mode.enable_zt();
|
2023-03-25 14:00:54 -04:00
|
|
|
mode.set_depth_write_enable(depth_write);
|
2022-05-11 22:53:53 -04:00
|
|
|
mode.set_depth_test(GsTest::ZTest::GEQUAL);
|
|
|
|
|
|
|
|
// check these
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
mode.set_ab(enable_alpha_blend);
|
2022-05-11 22:53:53 -04:00
|
|
|
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
2022-05-28 19:28:19 -04:00
|
|
|
mode.set_tcc(info.tex0.tcc());
|
|
|
|
mode.set_decal(info.tex0.tfx() == GsTex0::TextureFunction::DECAL);
|
2023-01-22 18:30:31 -05:00
|
|
|
if (info.tex0.tfx() != GsTex0::TextureFunction::DECAL) {
|
|
|
|
ASSERT(info.tex0.tfx() == GsTex0::TextureFunction::MODULATE);
|
|
|
|
}
|
|
|
|
|
2022-05-28 19:28:19 -04:00
|
|
|
mode.set_filt_enable(info.tex1.mmag());
|
2022-05-11 22:53:53 -04:00
|
|
|
|
|
|
|
// the alpha matters (maybe?)
|
|
|
|
update_mode_from_alpha1(info.alpha, mode);
|
|
|
|
|
|
|
|
// the clamp matters
|
|
|
|
if (!(info.clamp == 0b101 || info.clamp == 0 || info.clamp == 1 || info.clamp == 0b100)) {
|
|
|
|
ASSERT_MSG(false, fmt::format("clamp: 0x{:x}", info.clamp));
|
|
|
|
}
|
|
|
|
|
|
|
|
mode.set_clamp_s_enable(info.clamp & 0b1);
|
|
|
|
mode.set_clamp_t_enable(info.clamp & 0b100);
|
|
|
|
|
2023-03-26 12:30:35 -04:00
|
|
|
mode.set_fog(fge);
|
|
|
|
|
2022-05-11 22:53:53 -04:00
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
float u32_as_float(u32 in) {
|
|
|
|
float out;
|
|
|
|
memcpy(&out, &in, sizeof(float));
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 float_as_u32(float in) {
|
|
|
|
u32 out;
|
|
|
|
memcpy(&out, &in, sizeof(float));
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Representing something that can be written to the merc output buffer. 1 qw
|
|
|
|
*/
|
|
|
|
struct MercOutputQuadword {
|
|
|
|
enum class Kind {
|
|
|
|
INVALID, // uninitialized, or in the middle of another thing
|
|
|
|
VTX_START, // the first qw of a vertex
|
|
|
|
SHADER_START, // the first qw of a shader (the giftag)
|
|
|
|
PRIM_START // the giftag for a list of vertices
|
|
|
|
} kind = Kind::INVALID;
|
|
|
|
|
|
|
|
// if we're a vertex
|
|
|
|
u32 vtx_idx = -1; // index in the effect's vertex list.
|
|
|
|
bool adc = false; // if our adc flag is set. this differs between copies, so put it here.
|
|
|
|
|
|
|
|
// if we're a primitive giftag, the number of vertices that come after us.
|
|
|
|
u32 nloop_count = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct MercMemory {
|
|
|
|
std::array<MercOutputQuadword, 1024> memory;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Add vertices from a fragment to memory. Emulates the unpacking.
|
|
|
|
*/
|
|
|
|
void handle_frag(const std::string& debug_name,
|
|
|
|
const MercCtrlHeader& ctrl_header,
|
|
|
|
const MercFragment& frag,
|
|
|
|
const MercFragmentControl& frag_ctrl,
|
|
|
|
const MercState& state,
|
|
|
|
std::vector<MercUnpackedVtx>& effect_vertices,
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
MercMemory& memory,
|
|
|
|
bool can_be_modified,
|
|
|
|
int base_lump4,
|
|
|
|
int frag_idx) {
|
2022-05-11 22:53:53 -04:00
|
|
|
(void)frag_ctrl;
|
|
|
|
(void)debug_name;
|
2022-10-01 11:58:36 -04:00
|
|
|
// lg::print("handling frag: {}\n", debug_name);
|
|
|
|
// lg::print("{}\n", frag.print());
|
2022-05-11 22:53:53 -04:00
|
|
|
|
|
|
|
// we'll iterate through the lump and rgba data
|
|
|
|
int lump_ptr = 0; // vertex data starts at the beginning of "lump"
|
|
|
|
int rgba_ptr = frag.header.rgba_off; // rgba is in u4's
|
|
|
|
int perc_ptr = frag.header.perc_off;
|
|
|
|
int last_mat2_perc = perc_ptr - 1;
|
|
|
|
int perc_toggle = 0;
|
|
|
|
|
|
|
|
u32 mat1_cnt = frag.header.mat1_cnt;
|
|
|
|
u32 mat12_cnt = frag.header.mat2_cnt + mat1_cnt;
|
|
|
|
u32 mat123_cnt = frag.header.mat3_cnt + mat12_cnt;
|
|
|
|
|
|
|
|
// loop through vertices.
|
|
|
|
int prev_mat0 = -1;
|
|
|
|
int prev_mat1 = -1;
|
|
|
|
int prev_mat2 = -1;
|
|
|
|
for (size_t i = 0; i < mat123_cnt; i++) {
|
|
|
|
u32 current_vtx_idx = effect_vertices.size(); // idx in effect vertex list.
|
|
|
|
auto& vtx = effect_vertices.emplace_back();
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
vtx.can_be_modified = can_be_modified;
|
|
|
|
vtx.idx_in_combined_lump4 = lump_ptr / 3 + base_lump4;
|
|
|
|
vtx.frag = frag_idx;
|
|
|
|
vtx.flump4 = lump_ptr / 3;
|
2022-05-11 22:53:53 -04:00
|
|
|
|
|
|
|
if (i < mat1_cnt) {
|
|
|
|
vtx.kind = 1; // 1 matrix
|
|
|
|
} else if (i < mat12_cnt) {
|
|
|
|
vtx.kind = 2; // 2 matrix
|
|
|
|
} else {
|
|
|
|
vtx.kind = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the three quadwords in the source data
|
|
|
|
auto v0 = frag.lump4_unpacked.at(lump_ptr);
|
|
|
|
auto v1 = frag.lump4_unpacked.at(lump_ptr + 1);
|
|
|
|
auto v2 = frag.lump4_unpacked.at(lump_ptr + 2);
|
|
|
|
|
|
|
|
// ilwr.x vi08, vi01 ;; load mat0 from vertex
|
|
|
|
u16 mat0_addr;
|
|
|
|
memcpy(&mat0_addr, &v0.x(), 2);
|
|
|
|
u16 mat1_addr;
|
|
|
|
memcpy(&mat1_addr, &v0.y(), 2);
|
|
|
|
|
|
|
|
if (vtx.kind == 1) {
|
|
|
|
vtx.skel_mats[0] = state.vu1_matrix_slots.at(vu1_addr_to_matrix_slot(mat0_addr));
|
2022-05-28 19:28:19 -04:00
|
|
|
vtx.skel_mats[1] = 0;
|
|
|
|
vtx.skel_mats[2] = 0;
|
2022-05-11 22:53:53 -04:00
|
|
|
vtx.mat_weights[0] = 1.f;
|
|
|
|
vtx.mat_weights[1] = 0.f;
|
|
|
|
vtx.mat_weights[2] = 0.f;
|
|
|
|
ASSERT(vtx.skel_mats[0] >= 0);
|
|
|
|
} else if (vtx.kind == 2) {
|
|
|
|
u8 m0 = mat0_addr & 0x7f;
|
|
|
|
u8 m1 = mat1_addr & 0x7f;
|
|
|
|
if (m0 == 0x7f) {
|
|
|
|
ASSERT(prev_mat0 != -1);
|
|
|
|
} else {
|
|
|
|
prev_mat0 = vu1_addr_to_matrix_slot(m0);
|
|
|
|
prev_mat1 = vu1_addr_to_matrix_slot(m1);
|
|
|
|
}
|
|
|
|
vtx.skel_mats[0] = state.vu1_matrix_slots.at(prev_mat0);
|
|
|
|
vtx.skel_mats[1] = state.vu1_matrix_slots.at(prev_mat1);
|
2022-05-28 19:28:19 -04:00
|
|
|
vtx.skel_mats[2] = 0;
|
2022-05-11 22:53:53 -04:00
|
|
|
|
|
|
|
if (m0 != 0x7f && i != mat1_cnt) {
|
|
|
|
if (perc_toggle) {
|
|
|
|
perc_ptr++;
|
|
|
|
}
|
|
|
|
perc_toggle = !perc_toggle;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto perc = frag.unsigned_four_including_header.at(perc_ptr);
|
|
|
|
last_mat2_perc = perc_ptr;
|
|
|
|
|
|
|
|
if (!perc_toggle) {
|
|
|
|
vtx.mat_weights[0] = perc.x() / 255.f;
|
|
|
|
vtx.mat_weights[1] = perc.y() / 255.f;
|
|
|
|
} else {
|
|
|
|
vtx.mat_weights[0] = perc.z() / 255.f;
|
|
|
|
vtx.mat_weights[1] = perc.w() / 255.f;
|
|
|
|
}
|
|
|
|
vtx.mat_weights[2] = 0.f;
|
|
|
|
|
|
|
|
float sum = vtx.mat_weights[0] + vtx.mat_weights[1];
|
|
|
|
ASSERT(std::abs(1.f - sum) < 1e-6);
|
|
|
|
} else if (vtx.kind == 3) {
|
|
|
|
u8 m0 = mat0_addr & 0x7f;
|
|
|
|
u8 m1 = mat1_addr & 0x7f;
|
|
|
|
|
|
|
|
if (i == mat12_cnt) {
|
|
|
|
perc_ptr = last_mat2_perc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m0 == 0x7f) {
|
|
|
|
ASSERT(prev_mat0 != -1);
|
|
|
|
} else {
|
|
|
|
perc_ptr++;
|
|
|
|
prev_mat0 = vu1_addr_to_matrix_slot(m0);
|
|
|
|
prev_mat1 = vu1_addr_to_matrix_slot(m1);
|
|
|
|
prev_mat2 = vu1_addr_to_matrix_slot(frag.unsigned_four_including_header.at(perc_ptr).w());
|
|
|
|
}
|
|
|
|
vtx.skel_mats[0] = state.vu1_matrix_slots.at(prev_mat0);
|
|
|
|
vtx.skel_mats[1] = state.vu1_matrix_slots.at(prev_mat1);
|
|
|
|
vtx.skel_mats[2] = state.vu1_matrix_slots.at(prev_mat2);
|
|
|
|
|
|
|
|
auto perc = frag.unsigned_four_including_header.at(perc_ptr);
|
|
|
|
vtx.mat_weights[0] = perc.x() / 255.f;
|
|
|
|
vtx.mat_weights[1] = perc.y() / 255.f;
|
|
|
|
vtx.mat_weights[2] = perc.z() / 255.f;
|
|
|
|
|
|
|
|
float sum = vtx.mat_weights[0] + vtx.mat_weights[1] + vtx.mat_weights[2];
|
|
|
|
ASSERT(std::abs(1.f - sum) < 1e-6);
|
|
|
|
} else {
|
|
|
|
ASSERT(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
u16 mat1;
|
|
|
|
memcpy(&mat1, &v0.y(), 2);
|
|
|
|
u16 mat0;
|
|
|
|
memcpy(&mat0, &v0.x(), 2);
|
|
|
|
|
|
|
|
// add.zw vf08, vf08, vf17 ;; lump offset
|
|
|
|
// vf17 = [2048, 255, -65537, xyz-add.x] (the ?? is set per fragment)
|
|
|
|
v0.z() += -65537;
|
|
|
|
v0.w() += frag.fp_header.x_add;
|
|
|
|
|
|
|
|
// add.xyzw vf11, vf11, vf18 ;; lump offset
|
|
|
|
// vf18 = [st-out-X, st-out-X, -65537, xyz-add.y] (X = a if xtop = 0, X = b otherwise)
|
|
|
|
v1.x() += u32_as_float(ctrl_header.st_out_a);
|
|
|
|
v1.y() += u32_as_float(ctrl_header.st_out_a);
|
|
|
|
v1.z() += -65537;
|
|
|
|
v1.w() += frag.fp_header.y_add;
|
|
|
|
|
|
|
|
// add.xyzw vf14, vf14, vf19 ;; lump offset
|
|
|
|
// vf19 = [st-magic, st-magic, -65537, xyz-add.z]
|
|
|
|
v2.x() += u32_as_float(ctrl_header.st_magic);
|
|
|
|
v2.y() += u32_as_float(ctrl_header.st_magic);
|
|
|
|
v2.z() += -65537;
|
|
|
|
v2.w() += frag.fp_header.z_add;
|
|
|
|
|
|
|
|
vtx.pos = math::Vector3f(v0.w(), v1.w(), v2.w());
|
|
|
|
vtx.nrm = math::Vector3f(v0.z(), v1.z(), v2.z());
|
|
|
|
|
|
|
|
// vtx.mat1 = 0; // not used like this
|
|
|
|
vtx.dst0 = float_as_u32(v1.x()) - 371; // xtop to output buffer offset
|
|
|
|
vtx.dst1 = float_as_u32(v1.y()) - 371;
|
|
|
|
vtx.rgba = frag.unsigned_four_including_header.at(rgba_ptr);
|
2022-05-28 19:28:19 -04:00
|
|
|
vtx.st = math::Vector2f(v2.x(), v2.y());
|
2022-05-11 22:53:53 -04:00
|
|
|
|
|
|
|
// crazy flag logic to set adc
|
|
|
|
s16 mat1_flag = mat1;
|
|
|
|
s16 mat0_flag = mat0;
|
|
|
|
bool dst0_adc, dst1_adc;
|
|
|
|
if (vtx.kind == 1) {
|
|
|
|
ASSERT(mat1_flag == -1 || mat1_flag == 0 || mat1_flag == 1);
|
|
|
|
dst0_adc = mat1_flag <= 0;
|
|
|
|
dst1_adc = dst0_adc && (mat1_flag != 0);
|
|
|
|
dst0_adc = !dst0_adc;
|
|
|
|
dst1_adc = !dst1_adc;
|
|
|
|
} else {
|
|
|
|
// adc logic
|
|
|
|
// ilw.y vi09, -6(vi01)
|
|
|
|
s16 vi09 = mat1_flag;
|
|
|
|
// move.xyzw vf21, vf08
|
|
|
|
bool vf21_has_adc = false;
|
|
|
|
bool vf08_has_adc = false;
|
|
|
|
if (!(vi09 > 0)) {
|
|
|
|
vf21_has_adc = true;
|
|
|
|
}
|
|
|
|
// ibgtz vi09, L47
|
|
|
|
//
|
|
|
|
// addx.w vf21, vf21, vf17
|
|
|
|
//
|
|
|
|
// L47:
|
|
|
|
// ilw.x vi09, -9(vi01)
|
|
|
|
vi09 = mat0_flag;
|
|
|
|
// ftoi4.xyzw vf21, vf21
|
|
|
|
//
|
|
|
|
// sq.xyzw vf21, 2(vi10)
|
|
|
|
dst0_adc = !vf21_has_adc;
|
|
|
|
if (!(vi09 >= 0)) {
|
|
|
|
vf21_has_adc = vf08_has_adc;
|
|
|
|
}
|
|
|
|
dst1_adc = !vf21_has_adc;
|
|
|
|
// ibgez vi09, L50
|
|
|
|
//
|
|
|
|
// ftoi4.xyzw vf21, vf08
|
|
|
|
//
|
|
|
|
// L50:
|
|
|
|
// sq.xyzw vf21, 2(vi13)
|
|
|
|
|
|
|
|
// dst0_adc = mat1_flag <= 0;
|
|
|
|
// dst1_adc = dst0_adc && (mat0_flag >= 0);
|
|
|
|
// dst0_adc = !dst0_adc;
|
|
|
|
// dst1_adc = !dst1_adc;
|
2022-10-01 11:58:36 -04:00
|
|
|
// lg::print("{}\n", dst1_adc);
|
2022-05-11 22:53:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// write to two spots in memory
|
|
|
|
auto& dst0_mem = memory.memory.at(vtx.dst0);
|
|
|
|
auto& dst1_mem = memory.memory.at(vtx.dst1);
|
|
|
|
|
|
|
|
dst0_mem.kind = MercOutputQuadword::Kind::VTX_START;
|
|
|
|
dst0_mem.vtx_idx = current_vtx_idx;
|
|
|
|
dst0_mem.adc = dst0_adc;
|
|
|
|
memory.memory.at(vtx.dst0 + 1).kind = MercOutputQuadword::Kind::INVALID;
|
|
|
|
memory.memory.at(vtx.dst0 + 2).kind = MercOutputQuadword::Kind::INVALID;
|
|
|
|
|
|
|
|
dst1_mem.kind = MercOutputQuadword::Kind::VTX_START;
|
|
|
|
dst1_mem.vtx_idx = current_vtx_idx;
|
|
|
|
dst1_mem.adc = dst1_adc;
|
|
|
|
memory.memory.at(vtx.dst1 + 1).kind = MercOutputQuadword::Kind::INVALID;
|
|
|
|
memory.memory.at(vtx.dst1 + 2).kind = MercOutputQuadword::Kind::INVALID;
|
|
|
|
|
|
|
|
/*
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::print("place vertex {} @ {} {}: {} (adc {} {}) {}\n", current_vtx_idx, vtx.dst0, vtx.dst1,
|
2022-05-11 22:53:53 -04:00
|
|
|
vtx.pos.to_string_aligned(), dst0_adc, dst1_adc, mat1_flag);
|
|
|
|
*/
|
|
|
|
|
|
|
|
lump_ptr += 3; // advance 3 qw
|
|
|
|
rgba_ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Build OpenGL index list from a single GIF packet.
|
|
|
|
* TODO: should check we aren't putting in x x R x x R
|
|
|
|
*/
|
2022-05-23 18:53:02 -04:00
|
|
|
std::vector<u32> index_list_from_packet(u32 vtx_ptr, u32 nloop, const MercMemory& memory) {
|
2022-05-11 22:53:53 -04:00
|
|
|
std::vector<u32> result;
|
|
|
|
u32 prev_vtx = UINT32_MAX;
|
|
|
|
|
|
|
|
result.push_back(UINT32_MAX);
|
|
|
|
while (nloop) {
|
|
|
|
auto& vtx_mem = memory.memory.at(vtx_ptr);
|
|
|
|
if (vtx_mem.kind == MercOutputQuadword::Kind::VTX_START) {
|
|
|
|
bool adc = vtx_mem.adc;
|
|
|
|
if (adc) {
|
|
|
|
result.push_back(vtx_mem.vtx_idx);
|
|
|
|
} else {
|
|
|
|
result.push_back(UINT32_MAX);
|
|
|
|
result.push_back(prev_vtx);
|
|
|
|
result.push_back(vtx_mem.vtx_idx);
|
|
|
|
}
|
|
|
|
prev_vtx = vtx_mem.vtx_idx;
|
|
|
|
} else {
|
|
|
|
// missing vertex!
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::warn("MISSING VERTEX at {}", vtx_ptr);
|
2022-05-11 22:53:53 -04:00
|
|
|
result.push_back(UINT32_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
vtx_ptr += 3;
|
|
|
|
nloop--;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.push_back(UINT32_MAX);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Dump draws to obj file.
|
|
|
|
*/
|
|
|
|
std::string debug_dump_to_obj(const std::vector<MercDraw>& draws,
|
|
|
|
const std::vector<MercUnpackedVtx>& vertices) {
|
|
|
|
std::string result;
|
|
|
|
std::vector<math::Vector4f> verts;
|
|
|
|
std::vector<math::Vector<int, 3>> faces;
|
|
|
|
|
|
|
|
for (auto& draw : draws) {
|
|
|
|
// add verts...
|
|
|
|
int queue[2];
|
|
|
|
int q_idx = 0;
|
|
|
|
for (size_t ii = 2; ii < draw.indices.size(); ii++) {
|
|
|
|
u32 v0 = draw.indices[ii - 2];
|
|
|
|
u32 v1 = draw.indices[ii - 1];
|
|
|
|
u32 v2 = draw.indices[ii - 0];
|
|
|
|
if (v0 != UINT32_MAX && v1 != UINT32_MAX && v2 != UINT32_MAX) {
|
|
|
|
faces.emplace_back(v0 + 1, v1 + 1, v2 + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto& idx : draw.indices) {
|
|
|
|
if (idx == UINT32_MAX) {
|
|
|
|
q_idx = 0;
|
|
|
|
} else {
|
|
|
|
if (q_idx >= 2) {
|
|
|
|
faces.emplace_back(queue[0] + 1, queue[1] + 1, idx + 1);
|
|
|
|
}
|
|
|
|
queue[(q_idx++) % 2] = idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& vtx : vertices) {
|
|
|
|
result += fmt::format("v {} {} {}\n", vtx.pos.x() / 1024.f, vtx.pos.y() / 1024.f,
|
|
|
|
vtx.pos.z() / 1024.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& face : faces) {
|
|
|
|
result += fmt::format("f {}/{} {}/{} {}/{}\n", face.x(), face.x(), face.y(), face.y(), face.z(),
|
|
|
|
face.z());
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
math::Vector4<u16> vtx_to_rgba_bone_debug(const MercUnpackedVtx& vtx) {
|
|
|
|
math::Vector4<u16> result;
|
|
|
|
result.fill(0);
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
if (vtx.skel_mats[i] == -1 || vtx.mat_weights[i] == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
u32 rgba_packed = colors::common_colors[vtx.skel_mats[i] % colors::COLOR_COUNT];
|
|
|
|
result.x() += ((rgba_packed >> 16) & 0xff) * vtx.mat_weights[i];
|
|
|
|
result.y() += ((rgba_packed >> 8) & 0xff) * vtx.mat_weights[i];
|
|
|
|
result.z() += ((rgba_packed >> 0) & 0xff) * vtx.mat_weights[i];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string debug_dump_to_ply(const std::vector<MercDraw>& draws,
|
|
|
|
const std::vector<MercUnpackedVtx>& vertices) {
|
|
|
|
std::vector<math::Vector4f> verts;
|
|
|
|
std::vector<math::Vector<int, 3>> faces;
|
|
|
|
|
|
|
|
for (auto& draw : draws) {
|
|
|
|
// add verts...
|
|
|
|
for (size_t ii = 2; ii < draw.indices.size(); ii++) {
|
|
|
|
u32 v0 = draw.indices[ii - 2];
|
|
|
|
u32 v1 = draw.indices[ii - 1];
|
|
|
|
u32 v2 = draw.indices[ii - 0];
|
|
|
|
if (v0 != UINT32_MAX && v1 != UINT32_MAX && v2 != UINT32_MAX) {
|
|
|
|
faces.emplace_back(v0, v1, v2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string result = fmt::format(
|
|
|
|
"ply\nformat ascii 1.0\nelement vertex {}\nproperty float x\nproperty float y\nproperty "
|
|
|
|
"float z\nproperty uchar red\nproperty uchar green\nproperty uchar blue\nelement face "
|
|
|
|
"{}\nproperty list uchar int vertex_index\nend_header\n",
|
|
|
|
vertices.size(), faces.size());
|
|
|
|
|
|
|
|
for (auto& vtx : vertices) {
|
|
|
|
auto rgba = vtx_to_rgba_bone_debug(vtx);
|
|
|
|
result += fmt::format("{} {} {} {} {} {}\n", vtx.pos.x() / 1024.f, vtx.pos.y() / 1024.f,
|
|
|
|
vtx.pos.z() / 1024.f, rgba[0], rgba[1], rgba[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& face : faces) {
|
|
|
|
result += fmt::format("3 {} {} {}\n", face.x(), face.y(), face.z());
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-01-22 18:30:31 -05:00
|
|
|
int find_or_add_texture_to_level(tfrag3::Level& out,
|
|
|
|
const TextureDB& tex_db,
|
|
|
|
const std::string& debug_name,
|
2023-03-08 18:18:35 -05:00
|
|
|
u32 pc_combo_tex_id,
|
|
|
|
const MercCtrlHeader& hdr,
|
|
|
|
u8* eye_out,
|
|
|
|
GameVersion version) {
|
2023-01-22 18:30:31 -05:00
|
|
|
u32 idx_in_level_texture = UINT32_MAX;
|
|
|
|
for (u32 i = 0; i < out.textures.size(); i++) {
|
|
|
|
if (out.textures[i].combo_id == pc_combo_tex_id) {
|
|
|
|
idx_in_level_texture = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx_in_level_texture == UINT32_MAX) {
|
|
|
|
// not added to level, add it
|
|
|
|
auto tex_it = tex_db.textures.find(pc_combo_tex_id);
|
|
|
|
if (tex_it == tex_db.textures.end()) {
|
|
|
|
lg::error("merc failed to find texture: 0x{:x} for {}. Should be in tpage {}",
|
|
|
|
pc_combo_tex_id, debug_name, pc_combo_tex_id >> 16);
|
|
|
|
idx_in_level_texture = 0;
|
|
|
|
} else {
|
|
|
|
idx_in_level_texture = out.textures.size();
|
|
|
|
auto& new_tex = out.textures.emplace_back();
|
|
|
|
new_tex.combo_id = pc_combo_tex_id;
|
|
|
|
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 = tex_db.tpage_names.at(tex_it->second.page);
|
|
|
|
new_tex.data = tex_it->second.rgba_bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-08 18:18:35 -05:00
|
|
|
// check eyes
|
|
|
|
u32 eye_tpage = version == GameVersion::Jak2 ? 0x70c : 0x1cf;
|
|
|
|
u32 left_id = version == GameVersion::Jak2 ? 7 : 0x6f;
|
|
|
|
u32 right_id = version == GameVersion::Jak2 ? 8 : 0x70;
|
|
|
|
|
|
|
|
if (eye_out && (pc_combo_tex_id >> 16) == eye_tpage) {
|
|
|
|
auto tex_it = tex_db.textures.find(pc_combo_tex_id);
|
|
|
|
if (tex_it == tex_db.textures.end()) {
|
|
|
|
// fmt::print("{} got dynamic merc texture (no known texture)\n", debug_name);
|
|
|
|
} else {
|
|
|
|
// fmt::print("{} got dynamic merc texture (will overwrite {})\n", debug_name,
|
|
|
|
// tex_it->second.name);
|
|
|
|
}
|
|
|
|
u32 idx = pc_combo_tex_id & 0xffff;
|
|
|
|
|
|
|
|
if (idx == left_id || idx == right_id) {
|
|
|
|
if (!hdr.eye_ctrl) {
|
|
|
|
fmt::print("no eye ctrl, but expected one");
|
|
|
|
if (debug_name != "kor-break-lod0") {
|
|
|
|
ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (idx == left_id) {
|
|
|
|
*eye_out = (hdr.eye_ctrl->eye_slot * 2);
|
|
|
|
} else if (idx == right_id) {
|
|
|
|
*eye_out = (hdr.eye_ctrl->eye_slot * 2) + 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// fmt::print("got unknown tex id in eye page: {}\n", idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-22 18:30:31 -05:00
|
|
|
return idx_in_level_texture;
|
|
|
|
}
|
|
|
|
|
2022-05-11 22:53:53 -04:00
|
|
|
ConvertedMercEffect convert_merc_effect(const MercEffect& input_effect,
|
|
|
|
const MercCtrlHeader& ctrl_header,
|
|
|
|
const std::vector<level_tools::TextureRemap>& map,
|
|
|
|
const std::string& debug_name,
|
|
|
|
size_t ctrl_idx,
|
|
|
|
size_t effect_idx,
|
2023-01-22 18:30:31 -05:00
|
|
|
bool dump,
|
|
|
|
const TextureDB& tex_db,
|
|
|
|
tfrag3::Level& out,
|
|
|
|
GameVersion version) {
|
2022-05-11 22:53:53 -04:00
|
|
|
ConvertedMercEffect result;
|
|
|
|
result.ctrl_idx = ctrl_idx;
|
|
|
|
result.effect_idx = effect_idx;
|
2023-03-08 18:18:35 -05:00
|
|
|
if (ctrl_header.eye_ctrl) {
|
|
|
|
result.eye_slot = ctrl_header.eye_ctrl->eye_slot;
|
|
|
|
}
|
2023-01-22 18:30:31 -05:00
|
|
|
if (input_effect.extra_info.shader) {
|
|
|
|
result.has_envmap = true;
|
2023-03-26 12:30:35 -04:00
|
|
|
result.envmap_mode =
|
|
|
|
process_draw_mode(*input_effect.extra_info.shader, false, false, false, false);
|
2023-01-22 18:30:31 -05:00
|
|
|
result.envmap_mode.set_ab(true);
|
|
|
|
u32 new_tex = remap_texture(input_effect.extra_info.shader->original_tex, map);
|
|
|
|
ASSERT(result.envmap_mode.get_tcc_enable());
|
|
|
|
ASSERT(result.envmap_mode.get_alpha_blend() == DrawMode::AlphaBlend::SRC_0_DST_DST);
|
|
|
|
|
|
|
|
// 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;
|
2023-03-08 18:18:35 -05:00
|
|
|
result.envmap_texture = find_or_add_texture_to_level(out, tex_db, "envmap", tex_combo,
|
|
|
|
ctrl_header, nullptr, version);
|
2023-01-22 18:30:31 -05:00
|
|
|
} else if (input_effect.envmap_or_effect_usage) {
|
|
|
|
u32 tex_combo = 0;
|
|
|
|
switch (version) {
|
|
|
|
case GameVersion::Jak1: {
|
|
|
|
u32 env = 0x10000000; // jak 1, check for jak 2.
|
|
|
|
u32 tpage = env >> 20;
|
|
|
|
u32 tidx = (env >> 8) & 0b1111'1111'1111;
|
|
|
|
tex_combo = (((u32)tpage) << 16) | tidx;
|
|
|
|
} break;
|
|
|
|
case GameVersion::Jak2: {
|
|
|
|
u32 tpage = 0x1f;
|
|
|
|
u32 tidx = 2;
|
|
|
|
tex_combo = (((u32)tpage) << 16) | tidx;
|
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
ASSERT_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
2023-03-08 18:18:35 -05:00
|
|
|
result.envmap_texture = find_or_add_texture_to_level(out, tex_db, "envmap-default", tex_combo,
|
|
|
|
ctrl_header, nullptr, version);
|
2023-01-22 18:30:31 -05:00
|
|
|
|
|
|
|
DrawMode mode;
|
|
|
|
mode.set_at(false);
|
|
|
|
mode.enable_zt();
|
|
|
|
mode.enable_depth_write();
|
|
|
|
mode.set_depth_test(GsTest::ZTest::GEQUAL);
|
|
|
|
|
|
|
|
// check these
|
|
|
|
mode.disable_ab();
|
|
|
|
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
|
|
|
|
mode.set_tcc(true);
|
|
|
|
mode.set_decal(false);
|
|
|
|
mode.set_filt_enable(true);
|
|
|
|
|
|
|
|
mode.set_clamp_s_enable(true);
|
|
|
|
mode.set_clamp_t_enable(true);
|
|
|
|
|
|
|
|
result.has_envmap = true;
|
|
|
|
result.envmap_mode = mode;
|
|
|
|
result.envmap_mode.set_ab(true);
|
|
|
|
}
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
|
|
|
|
bool use_alpha_blend = false;
|
2023-03-25 14:00:54 -04:00
|
|
|
bool depth_write = true;
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
if (version == GameVersion::Jak2) {
|
2023-03-25 14:00:54 -04:00
|
|
|
constexpr int kWaterTexture = 4;
|
|
|
|
constexpr int kAlphaTexture = 3;
|
|
|
|
if (input_effect.texture_index == kAlphaTexture) {
|
|
|
|
use_alpha_blend = true;
|
|
|
|
}
|
|
|
|
if (input_effect.texture_index == kWaterTexture) {
|
|
|
|
depth_write = false;
|
|
|
|
use_alpha_blend = true;
|
|
|
|
}
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
}
|
|
|
|
|
2022-05-11 22:53:53 -04:00
|
|
|
// full reset of state per effect.
|
|
|
|
// we have no idea what the previous effect draw will be - it might be given to
|
|
|
|
// mercneric.
|
|
|
|
bool shader_set = false; // no previous shader can reliably be known
|
|
|
|
MercState merc_state; // current gs settings/matrix slots
|
|
|
|
MercMemory merc_memories[2]; // double buffered output
|
|
|
|
int memory_buffer_toggle = 0; // which output we're in
|
|
|
|
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
int combined_lump4_addr = 0;
|
|
|
|
|
2022-05-11 22:53:53 -04:00
|
|
|
for (size_t fi = 0; fi < input_effect.frag_ctrl.size(); fi++) {
|
|
|
|
const auto& frag = input_effect.frag_geo[fi];
|
|
|
|
const auto& frag_ctrl = input_effect.frag_ctrl[fi];
|
|
|
|
|
|
|
|
// first, deal with matrices
|
|
|
|
for (size_t mi = 0; mi < frag_ctrl.mat_xfer_count; mi++) {
|
|
|
|
const auto& xfer = frag_ctrl.mat_dest_data[mi];
|
|
|
|
merc_state.vu1_matrix_slots[vu1_addr_to_matrix_slot(xfer.matrix_dest)] = xfer.matrix_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!shader_set) {
|
|
|
|
// if we don't have a shader set, we shouldn't have anything that reuses the last shader
|
|
|
|
ASSERT(frag.header.strip_len == 0);
|
|
|
|
// and we should set the shader
|
|
|
|
ASSERT(frag.fp_header.shader_cnt > 0);
|
|
|
|
shader_set = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// run the frag.
|
|
|
|
// this will add vertices to the per-effect vertex lists and also update the merc memory
|
|
|
|
// to point to these.
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
bool can_be_modified = false;
|
|
|
|
if (fi < input_effect.blend_ctrl.size()) {
|
|
|
|
can_be_modified = input_effect.blend_ctrl.at(fi).blend_vtx_count > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (input_effect.effect_bits & kRippleEffectBit) {
|
|
|
|
can_be_modified = true;
|
|
|
|
}
|
2022-05-11 22:53:53 -04:00
|
|
|
|
[merc2] Support texscroll, use in jak 1 in more places, fix envmap bug (#2303)
Three main changes:
- Adds support for the texture scrolling effect used on conveyor belts,
and turn it on for jak 2.
- Use merc instead of generic in jak 1 for ripple/water/texscroll stuff
(non-ocean water, lava, dark eco, etc). This is a pretty big speedup in
a lot of places.
- Fix a really old bug with blending mode used to draw environment maps.
The effect is that envmaps were half as bright as they should have been.
As usual, there's a flag to go back to the old behavior on jak 1. Set
these to `#t` to use generic like we used to.
```
*texscroll-force-generic*
*ripple-force-generic*
```
The format has changed, and everything must be rebuilt (C++, FR3's, GOAL
code)
2023-03-09 20:01:22 -05:00
|
|
|
if (input_effect.effect_bits & kTextureScrollEffectBit) {
|
|
|
|
can_be_modified = true;
|
|
|
|
}
|
|
|
|
|
2022-05-11 22:53:53 -04:00
|
|
|
handle_frag(debug_name, ctrl_header, frag, frag_ctrl, merc_state, result.vertices,
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
merc_memories[memory_buffer_toggle], can_be_modified, combined_lump4_addr, fi);
|
|
|
|
u32 vert_count = frag.lump4_unpacked.size() / 3;
|
|
|
|
combined_lump4_addr += vert_count;
|
|
|
|
result.verts_per_frag.push_back(vert_count);
|
2022-05-11 22:53:53 -04:00
|
|
|
|
|
|
|
// we'll add draws after this draw, but wait to actually populate the index lists until
|
|
|
|
// we've processed all the vertices.
|
|
|
|
size_t first_draw_to_update = result.draws.size();
|
|
|
|
|
|
|
|
// continuation of a previous shader
|
|
|
|
if (frag.header.strip_len) {
|
|
|
|
// add the continued draw
|
|
|
|
auto& new_draw = result.draws.emplace_back();
|
|
|
|
new_draw.ctrl_idx = ctrl_idx;
|
|
|
|
new_draw.effect_idx = effect_idx;
|
|
|
|
new_draw.frag_idx = fi;
|
|
|
|
new_draw.state = merc_state;
|
|
|
|
new_draw.vtx_offset = 1;
|
|
|
|
// just remember where it started. we might copy some vertices from a later draw in this
|
|
|
|
// fragment back to this draw, and at this point we don't know what the adc flags would be.
|
|
|
|
// (or their index, because we are deduplicated)
|
|
|
|
new_draw.vtx_nloop = frag.header.strip_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
// loop over fresh shaders
|
|
|
|
for (size_t i = 0; i < frag.fp_header.shader_cnt; i++) {
|
|
|
|
const auto& shader = frag.shaders.at(i);
|
|
|
|
// update merc state from shader (will hold over to next fragment, if needed)
|
2023-03-26 12:30:35 -04:00
|
|
|
bool fog = ctrl_header.disable_fog == 0;
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
merc_state.merc_draw_mode.mode =
|
2023-03-26 12:30:35 -04:00
|
|
|
process_draw_mode(shader, result.has_envmap, use_alpha_blend, depth_write, fog);
|
2023-01-22 18:30:31 -05:00
|
|
|
if (!merc_state.merc_draw_mode.mode.get_tcc_enable()) {
|
|
|
|
ASSERT(false);
|
|
|
|
}
|
2022-05-11 22:53:53 -04:00
|
|
|
u32 new_tex = remap_texture(shader.original_tex, map);
|
|
|
|
|
|
|
|
// 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;
|
2022-11-30 22:36:09 -05:00
|
|
|
|
2022-05-11 22:53:53 -04:00
|
|
|
// remember the texture id
|
|
|
|
merc_state.merc_draw_mode.pc_combo_tex_id = tex_combo;
|
|
|
|
|
|
|
|
// add the draw
|
|
|
|
auto& new_draw = result.draws.emplace_back();
|
|
|
|
new_draw.ctrl_idx = ctrl_idx;
|
|
|
|
new_draw.effect_idx = effect_idx;
|
|
|
|
new_draw.frag_idx = fi;
|
|
|
|
new_draw.state = merc_state;
|
|
|
|
// write the shader to memory
|
|
|
|
merc_memories[memory_buffer_toggle].memory.at(shader.output_offset).kind =
|
|
|
|
MercOutputQuadword::Kind::SHADER_START;
|
|
|
|
for (int mi = 1; mi < 6; mi++) {
|
|
|
|
// fill 5qw of adgif data with invalid. make sure we don't read verts from here
|
|
|
|
merc_memories[memory_buffer_toggle].memory.at(shader.output_offset + mi).kind =
|
|
|
|
MercOutputQuadword::Kind::INVALID;
|
|
|
|
}
|
|
|
|
// write the giftag for primitives
|
|
|
|
auto& prim_packet = merc_memories[memory_buffer_toggle].memory.at(shader.output_offset + 6);
|
|
|
|
prim_packet.kind = MercOutputQuadword::Kind::PRIM_START;
|
|
|
|
prim_packet.nloop_count = shader.next_strip_nloop;
|
|
|
|
|
|
|
|
// update draw from hidden fields in adgif.
|
|
|
|
new_draw.vtx_offset = shader.output_offset + 7;
|
|
|
|
new_draw.vtx_nloop = shader.next_strip_nloop;
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy from other places inside this output buffer
|
|
|
|
u32 srcdst_ptr = frag.header.srcdest_off;
|
|
|
|
for (u32 sci = 0; sci < frag.header.samecopy_cnt; sci++) {
|
|
|
|
auto& cpy = frag.unsigned_four_including_header[srcdst_ptr];
|
2022-10-01 11:58:36 -04:00
|
|
|
// lg::print("sci: {}\n", cpy.to_string_hex_byte());
|
2022-05-11 22:53:53 -04:00
|
|
|
u32 src = cpy[0];
|
|
|
|
auto& vert = merc_memories[memory_buffer_toggle].memory.at(src);
|
|
|
|
u32 dst = cpy[1];
|
|
|
|
auto& dvert = merc_memories[memory_buffer_toggle].memory.at(dst);
|
|
|
|
if (vert.kind == MercOutputQuadword::Kind::VTX_START) {
|
|
|
|
dvert = vert;
|
|
|
|
if (cpy[3]) {
|
|
|
|
// dvert.adc = true;
|
|
|
|
dvert.adc = !dvert.adc;
|
|
|
|
}
|
|
|
|
} else {
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::warn("sc missing vert");
|
2022-05-11 22:53:53 -04:00
|
|
|
dvert.kind = MercOutputQuadword::Kind::INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
srcdst_ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// "cross" copy from the other output buffer
|
|
|
|
for (u32 cci = 0; cci < frag.header.crosscopy_cnt; cci++) {
|
|
|
|
auto& cpy = frag.unsigned_four_including_header[srcdst_ptr];
|
2022-10-01 11:58:36 -04:00
|
|
|
// lg::print("cci: {}\n", cpy.to_string_hex_byte());
|
2022-05-11 22:53:53 -04:00
|
|
|
u32 src = cpy[0];
|
|
|
|
auto& vert = merc_memories[memory_buffer_toggle ^ 1].memory.at(src);
|
|
|
|
u32 dst = cpy[1];
|
|
|
|
auto& dvert = merc_memories[memory_buffer_toggle].memory.at(dst);
|
|
|
|
if (vert.kind == MercOutputQuadword::Kind::VTX_START) {
|
|
|
|
dvert = vert;
|
|
|
|
if (cpy[3]) {
|
|
|
|
// dvert.adc = true;
|
|
|
|
dvert.adc = !dvert.adc;
|
|
|
|
}
|
|
|
|
} else {
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::warn("cc missing vert");
|
2022-05-11 22:53:53 -04:00
|
|
|
dvert.kind = MercOutputQuadword::Kind::INVALID;
|
|
|
|
}
|
|
|
|
srcdst_ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now that we've copied all vertices, create index lists.
|
|
|
|
for (size_t i = first_draw_to_update; i < result.draws.size(); i++) {
|
|
|
|
auto& draw = result.draws[i];
|
|
|
|
draw.indices = index_list_from_packet(draw.vtx_offset, draw.vtx_nloop,
|
2022-05-23 18:53:02 -04:00
|
|
|
merc_memories[memory_buffer_toggle]);
|
2022-05-11 22:53:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
memory_buffer_toggle ^= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dump) {
|
2023-01-30 19:20:29 -05:00
|
|
|
auto file_path = file_util::get_file_path(
|
|
|
|
{"debug_out/merc", fmt::format("{}_{}.ply", debug_name, effect_idx)});
|
|
|
|
file_util::create_dir_if_needed_for_file(file_path);
|
|
|
|
file_util::write_text_file(file_path, debug_dump_to_ply(result.draws, result.vertices));
|
2022-05-11 22:53:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-05-28 19:28:19 -04:00
|
|
|
u8 convert_mat(int in) {
|
|
|
|
if (in >= 0) {
|
|
|
|
return in;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-05 12:25:35 -04:00
|
|
|
tfrag3::MercVertex convert_vertex(const MercUnpackedVtx& vtx, float xyz_scale) {
|
2022-05-28 19:28:19 -04:00
|
|
|
tfrag3::MercVertex out;
|
2022-08-05 12:25:35 -04:00
|
|
|
out.pos[0] = vtx.pos[0] * xyz_scale;
|
|
|
|
out.pos[1] = vtx.pos[1] * xyz_scale;
|
|
|
|
out.pos[2] = vtx.pos[2] * xyz_scale;
|
2022-05-28 19:28:19 -04:00
|
|
|
out.pad0 = 0;
|
|
|
|
out.normal[0] = vtx.nrm[0];
|
|
|
|
out.normal[1] = vtx.nrm[1];
|
|
|
|
out.normal[2] = vtx.nrm[2];
|
|
|
|
out.pad1 = 0;
|
|
|
|
out.weights[0] = vtx.mat_weights[0];
|
|
|
|
out.weights[1] = vtx.mat_weights[1];
|
|
|
|
out.weights[2] = vtx.mat_weights[2];
|
|
|
|
out.pad2 = 0;
|
|
|
|
out.st[0] = vtx.st[0];
|
|
|
|
out.st[1] = vtx.st[1];
|
|
|
|
out.rgba[0] = vtx.rgba[0];
|
|
|
|
out.rgba[1] = vtx.rgba[1];
|
|
|
|
out.rgba[2] = vtx.rgba[2];
|
|
|
|
out.rgba[3] = vtx.rgba[3];
|
|
|
|
out.mats[0] = convert_mat(vtx.skel_mats[0]);
|
|
|
|
out.mats[1] = convert_mat(vtx.skel_mats[1]);
|
|
|
|
out.mats[2] = convert_mat(vtx.skel_mats[2]);
|
|
|
|
out.pad3 = 0;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
struct VertexSourceInfo {
|
|
|
|
int combined_lump4;
|
|
|
|
int frag;
|
|
|
|
int flump4;
|
|
|
|
};
|
|
|
|
|
|
|
|
void create_modifiable_vertex_data(
|
|
|
|
const std::vector<bool>& vtx_mod_flag,
|
|
|
|
const std::vector<VertexSourceInfo>& vtx_srcs,
|
|
|
|
tfrag3::MercModelGroup& out,
|
|
|
|
size_t first_out_vertex,
|
|
|
|
size_t first_out_model,
|
|
|
|
const std::vector<std::vector<ConvertedMercEffect>>& all_effects) {
|
|
|
|
ASSERT(vtx_mod_flag.size() + first_out_vertex == out.vertices.size());
|
|
|
|
|
|
|
|
// we need to be able to modify some vertices at runtime.
|
|
|
|
// this can be detected vertex-by-vertex
|
|
|
|
// the plan is to find MercEffects that contain modifiable vertices, and provide an alternate way
|
|
|
|
// to draw them. In the case where no vertices should be modified, we can fall back to the normal
|
|
|
|
// merc drawing path.
|
|
|
|
|
|
|
|
// In this modifiable draw path, there will be a list of "fixed draws", which draw vertices that
|
|
|
|
// cannot be modified. This set is known at build-time.
|
|
|
|
// The "mod draws" will draw the modifiable vertices. These use the normal index buffer, but
|
|
|
|
// index into a per-effect modifiable vertex buffer.
|
|
|
|
|
|
|
|
// std::vector<tfrag3::MercDraw> fixed_draws, mod_draws;
|
|
|
|
|
|
|
|
// some stats
|
|
|
|
int num_tris = 0; // all triangles
|
|
|
|
int mod_tris = 0; // triangles in mod draws
|
|
|
|
|
|
|
|
// loop over models added from this art-group
|
|
|
|
for (size_t mi = first_out_model; mi < out.models.size(); mi++) {
|
|
|
|
auto& model = out.models.at(mi);
|
|
|
|
// loop over "effects" within this model. the pc format merges all fragments in an effect
|
|
|
|
// together.
|
|
|
|
|
|
|
|
for (size_t ei = 0; ei < model.effects.size(); ei++) {
|
|
|
|
auto& effect = model.effects[ei];
|
|
|
|
|
|
|
|
std::vector<std::vector<u32>> inds_per_mod_draw;
|
|
|
|
|
|
|
|
for (const auto& draw : effect.all_draws) {
|
|
|
|
num_tris += draw.num_triangles;
|
|
|
|
|
|
|
|
// first check to see what's in this draw
|
|
|
|
bool found_mod = false;
|
|
|
|
bool found_fixed = false;
|
|
|
|
for (int i = 0; i < (int)draw.index_count; i++) {
|
|
|
|
u32 idx = out.indices.at(draw.first_index + i);
|
|
|
|
if (idx == UINT32_MAX) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ASSERT(idx >= first_out_vertex);
|
|
|
|
if (vtx_mod_flag.at(idx - first_out_vertex)) {
|
|
|
|
found_mod = true;
|
|
|
|
} else {
|
|
|
|
found_fixed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found_fixed && !found_mod) {
|
|
|
|
// nothing found at all, bad
|
|
|
|
ASSERT_NOT_REACHED();
|
|
|
|
} else if (found_fixed && !found_mod) {
|
|
|
|
// only fixed. can just copy the fixed draw
|
|
|
|
effect.mod.fix_draw.push_back(draw);
|
|
|
|
} else if (found_mod && !found_fixed) {
|
|
|
|
// only mod
|
|
|
|
effect.mod.mod_draw.push_back(draw);
|
|
|
|
auto& inds_out = inds_per_mod_draw.emplace_back();
|
|
|
|
for (u32 i = 0; i < draw.index_count; i++) {
|
|
|
|
inds_out.push_back(out.indices.at(draw.first_index + i));
|
|
|
|
}
|
|
|
|
mod_tris += draw.num_triangles;
|
|
|
|
} else {
|
|
|
|
// it's a mix...
|
|
|
|
std::vector<std::vector<u32>> strips;
|
|
|
|
strips.emplace_back();
|
|
|
|
for (u32 i = 0; i < draw.index_count; i++) {
|
|
|
|
u32 val = out.indices.at(draw.first_index + i);
|
|
|
|
if (val == UINT32_MAX) {
|
|
|
|
if (!strips.back().empty()) {
|
|
|
|
strips.emplace_back();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
strips.back().push_back(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tfrag3::MercDraw mod = draw;
|
|
|
|
tfrag3::MercDraw fix = draw;
|
|
|
|
std::vector<u32> mod_ind, fix_ind;
|
|
|
|
for (auto& strip : strips) {
|
|
|
|
bool strip_has_mod = false;
|
|
|
|
for (auto ind : strip) {
|
|
|
|
if (vtx_mod_flag.at(ind - first_out_vertex)) {
|
|
|
|
strip_has_mod = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (strip_has_mod) {
|
|
|
|
mod_ind.insert(mod_ind.end(), strip.begin(), strip.end());
|
|
|
|
mod_ind.push_back(UINT32_MAX);
|
|
|
|
} else {
|
|
|
|
fix_ind.insert(fix_ind.end(), strip.begin(), strip.end());
|
|
|
|
fix_ind.push_back(UINT32_MAX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mod.index_count = mod_ind.size();
|
|
|
|
inds_per_mod_draw.push_back(mod_ind);
|
|
|
|
fix.first_index = out.indices.size();
|
|
|
|
fix.index_count = fix_ind.size();
|
|
|
|
out.indices.insert(out.indices.end(), fix_ind.begin(), fix_ind.end());
|
|
|
|
|
|
|
|
effect.mod.mod_draw.push_back(mod);
|
|
|
|
effect.mod.fix_draw.push_back(fix);
|
|
|
|
}
|
|
|
|
} // for draw
|
|
|
|
|
|
|
|
// if there are no modifiable draws, we can't possible modify anything, so not worth
|
|
|
|
// storing the fixed draws
|
|
|
|
if (effect.mod.mod_draw.empty()) {
|
|
|
|
effect.mod.fix_draw.clear();
|
|
|
|
} else {
|
|
|
|
effect.has_mod_draw = true;
|
|
|
|
// need to set up the vertex buffer for the modifiable draws
|
|
|
|
// map of original vertex indices to mod buffer index
|
|
|
|
std::unordered_map<u32, u32> vtx_to_mod_vtx;
|
|
|
|
for (size_t mdi = 0; mdi < effect.mod.mod_draw.size(); mdi++) {
|
|
|
|
auto& draw = effect.mod.mod_draw[mdi];
|
|
|
|
auto& orig_inds = inds_per_mod_draw.at(mdi);
|
|
|
|
u32 new_first_index = out.indices.size();
|
|
|
|
for (auto vidx : orig_inds) {
|
|
|
|
if (vidx == UINT32_MAX) {
|
|
|
|
out.indices.push_back(UINT32_MAX);
|
|
|
|
continue; // strip restart
|
|
|
|
}
|
|
|
|
const auto& existing = vtx_to_mod_vtx.find(vidx);
|
|
|
|
if (existing == vtx_to_mod_vtx.end()) {
|
|
|
|
// add vertex to mod buffer
|
|
|
|
auto idx = effect.mod.vertices.size();
|
|
|
|
vtx_to_mod_vtx[vidx] = idx;
|
|
|
|
effect.mod.vertices.push_back(out.vertices.at(vidx));
|
|
|
|
auto src = vtx_srcs.at(vidx - first_out_vertex);
|
|
|
|
ASSERT(src.combined_lump4 < UINT16_MAX);
|
|
|
|
effect.mod.vertex_lump4_addr.push_back(src.combined_lump4);
|
|
|
|
u32 frag_idx = src.frag;
|
|
|
|
if (frag_idx >= effect.mod.fragment_mask.size()) {
|
|
|
|
effect.mod.fragment_mask.resize(frag_idx + 1);
|
|
|
|
}
|
|
|
|
effect.mod.fragment_mask[frag_idx] = true;
|
|
|
|
out.indices.push_back(idx);
|
|
|
|
} else {
|
|
|
|
out.indices.push_back(existing->second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
draw.first_index = new_first_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
// splice out masked fragments, the renderer won't index them
|
|
|
|
const auto& frag_counts = all_effects.at(mi - first_out_model).at(ei).verts_per_frag;
|
|
|
|
std::unordered_map<u32, u32> old_to_new;
|
|
|
|
u32 old_idx = 0;
|
|
|
|
u32 new_idx = 0;
|
|
|
|
for (size_t fi = 0; fi < effect.mod.fragment_mask.size(); fi++) {
|
|
|
|
if (effect.mod.fragment_mask[fi]) {
|
|
|
|
for (u32 vi = 0; vi < frag_counts.at(fi); vi++) {
|
|
|
|
old_to_new[old_idx] = new_idx;
|
|
|
|
old_idx++;
|
|
|
|
new_idx++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
old_idx += frag_counts.at(fi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
effect.mod.expect_vidx_end = new_idx;
|
|
|
|
for (auto& v : effect.mod.vertex_lump4_addr) {
|
|
|
|
v = old_to_new.at(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-11 22:53:53 -04:00
|
|
|
/*!
|
|
|
|
* Top-level merc extraction
|
|
|
|
*/
|
|
|
|
void extract_merc(const ObjectFileData& ag_data,
|
|
|
|
const TextureDB& tex_db,
|
|
|
|
const DecompilerTypeSystem& dts,
|
|
|
|
const std::vector<level_tools::TextureRemap>& map,
|
2022-05-28 19:28:19 -04:00
|
|
|
tfrag3::Level& out,
|
2023-01-22 18:30:31 -05:00
|
|
|
bool dump_level,
|
|
|
|
GameVersion version) {
|
2022-05-11 22:53:53 -04:00
|
|
|
if (dump_level) {
|
|
|
|
file_util::create_dir_if_needed(file_util::get_file_path({"debug_out/merc"}));
|
|
|
|
}
|
|
|
|
// find all merc-ctrls in the object file
|
|
|
|
auto ctrl_locations = find_merc_ctrls(ag_data.linked_data);
|
|
|
|
|
|
|
|
// extract them. this does very basic unpacking of data, as done by the VIF/DMA on PS2.
|
|
|
|
std::vector<MercCtrl> ctrls;
|
|
|
|
for (auto location : ctrl_locations) {
|
|
|
|
auto ctrl = extract_merc_ctrl(ag_data.linked_data, dts, location);
|
|
|
|
ctrls.push_back(ctrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
// extract draws. this does no regrouping yet.
|
2022-05-28 19:28:19 -04:00
|
|
|
std::vector<std::vector<ConvertedMercEffect>> all_effects;
|
|
|
|
for (size_t ci = 0; ci < ctrls.size(); ci++) {
|
|
|
|
auto& effects_in_ctrl = all_effects.emplace_back();
|
|
|
|
for (size_t ei = 0; ei < ctrls[ci].effects.size(); ei++) {
|
2022-11-30 22:36:09 -05:00
|
|
|
effects_in_ctrl.push_back(convert_merc_effect(ctrls[ci].effects[ei], ctrls[ci].header, map,
|
2023-01-22 18:30:31 -05:00
|
|
|
ctrls[ci].name, ci, ei, dump_level, tex_db, out,
|
|
|
|
version));
|
2022-05-28 19:28:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
size_t first_out_vertex = out.merc_data.vertices.size();
|
2022-05-28 19:28:19 -04:00
|
|
|
// convert to PC format
|
|
|
|
// first pass, before merging indices
|
|
|
|
u32 first_model = out.merc_data.models.size();
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
std::vector<bool> vertex_modify_flags;
|
|
|
|
std::vector<VertexSourceInfo> vertex_srcs;
|
2022-05-28 19:28:19 -04:00
|
|
|
std::vector<std::vector<std::vector<std::vector<u32>>>> indices_temp; // ctrl, effect, draw, vtx
|
|
|
|
for (size_t ci = 0; ci < ctrls.size(); ci++) {
|
|
|
|
indices_temp.emplace_back();
|
|
|
|
auto& pc_ctrl = out.merc_data.models.emplace_back();
|
|
|
|
auto& ctrl = ctrls[ci];
|
|
|
|
|
|
|
|
pc_ctrl.name = ctrl.name;
|
|
|
|
pc_ctrl.max_draws = 0;
|
|
|
|
pc_ctrl.max_bones = 0;
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
pc_ctrl.st_vif_add = ctrl.header.st_vif_add;
|
[merc2] Support texscroll, use in jak 1 in more places, fix envmap bug (#2303)
Three main changes:
- Adds support for the texture scrolling effect used on conveyor belts,
and turn it on for jak 2.
- Use merc instead of generic in jak 1 for ripple/water/texscroll stuff
(non-ocean water, lava, dark eco, etc). This is a pretty big speedup in
a lot of places.
- Fix a really old bug with blending mode used to draw environment maps.
The effect is that envmaps were half as bright as they should have been.
As usual, there's a flag to go back to the old behavior on jak 1. Set
these to `#t` to use generic like we used to.
```
*texscroll-force-generic*
*ripple-force-generic*
```
The format has changed, and everything must be rebuilt (C++, FR3's, GOAL
code)
2023-03-09 20:01:22 -05:00
|
|
|
pc_ctrl.st_magic = u32_as_float(ctrl.header.st_magic);
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
pc_ctrl.xyz_scale = ctrl.header.xyz_scale;
|
2022-05-28 19:28:19 -04:00
|
|
|
|
|
|
|
for (size_t ei = 0; ei < ctrls[ci].effects.size(); ei++) {
|
|
|
|
indices_temp[ci].emplace_back();
|
|
|
|
auto& pc_effect = pc_ctrl.effects.emplace_back();
|
|
|
|
auto& effect = all_effects[ci][ei];
|
2023-01-22 18:30:31 -05:00
|
|
|
pc_effect.has_envmap = effect.has_envmap;
|
|
|
|
pc_effect.envmap_texture = effect.envmap_texture;
|
|
|
|
pc_effect.envmap_mode = effect.envmap_mode;
|
2022-05-28 19:28:19 -04:00
|
|
|
u32 first_vertex = out.merc_data.vertices.size();
|
|
|
|
for (auto& vtx : effect.vertices) {
|
2022-08-05 12:25:35 -04:00
|
|
|
auto cvtx = convert_vertex(vtx, ctrl.header.xyz_scale);
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
vertex_modify_flags.push_back(vtx.can_be_modified);
|
|
|
|
vertex_srcs.push_back({vtx.idx_in_combined_lump4, vtx.frag, vtx.flump4});
|
2022-05-28 19:28:19 -04:00
|
|
|
out.merc_data.vertices.push_back(cvtx);
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
pc_ctrl.max_bones = std::max(pc_ctrl.max_bones, (u32)cvtx.mats[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// can do two types of de-duplication: toggling back and forth shaders and matrices
|
|
|
|
std::map<u64, u64> draw_mode_dedup;
|
|
|
|
|
|
|
|
for (auto& draw : effect.draws) {
|
|
|
|
indices_temp[ci][ei].emplace_back();
|
|
|
|
// find draw to add to, or create a new one
|
|
|
|
const auto& existing = draw_mode_dedup.find(draw.state.merc_draw_mode.as_u64());
|
|
|
|
tfrag3::MercDraw* pc_draw = nullptr;
|
|
|
|
u64 pc_draw_idx = -1;
|
|
|
|
if (existing == draw_mode_dedup.end()) {
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
pc_draw_idx = pc_effect.all_draws.size();
|
2022-05-28 19:28:19 -04:00
|
|
|
draw_mode_dedup[draw.state.merc_draw_mode.as_u64()] = pc_draw_idx;
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
pc_draw = &pc_effect.all_draws.emplace_back();
|
2022-05-28 19:28:19 -04:00
|
|
|
pc_draw->mode = draw.state.merc_draw_mode.mode;
|
2023-01-22 18:30:31 -05:00
|
|
|
pc_draw->tree_tex_id = find_or_add_texture_to_level(
|
2023-03-08 18:18:35 -05:00
|
|
|
out, tex_db, ctrl.name, draw.state.merc_draw_mode.pc_combo_tex_id, ctrl.header,
|
|
|
|
&pc_draw->eye_id, version);
|
2022-05-28 19:28:19 -04:00
|
|
|
} else {
|
|
|
|
pc_draw_idx = existing->second;
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
pc_draw = &pc_effect.all_draws.at(pc_draw_idx);
|
2022-05-28 19:28:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto idx : draw.indices) {
|
|
|
|
if (idx == UINT32_MAX) {
|
|
|
|
indices_temp[ci][ei][pc_draw_idx].push_back(idx);
|
|
|
|
} else {
|
|
|
|
indices_temp[ci][ei][pc_draw_idx].push_back(idx + first_vertex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// merge indices
|
2022-05-11 22:53:53 -04:00
|
|
|
for (size_t ci = 0; ci < ctrls.size(); ci++) {
|
2022-05-28 19:28:19 -04:00
|
|
|
auto& pc_ctrl = out.merc_data.models.at(ci + first_model);
|
2022-05-11 22:53:53 -04:00
|
|
|
for (size_t ei = 0; ei < ctrls[ci].effects.size(); ei++) {
|
2022-05-28 19:28:19 -04:00
|
|
|
auto& pc_effect = pc_ctrl.effects.at(ei);
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
for (size_t di = 0; di < pc_effect.all_draws.size(); di++) {
|
|
|
|
auto& pc_draw = pc_effect.all_draws.at(di);
|
2022-05-28 19:28:19 -04:00
|
|
|
auto& inds = indices_temp[ci][ei][di];
|
|
|
|
pc_draw.num_triangles = clean_up_vertex_indices(inds);
|
|
|
|
pc_draw.first_index = out.merc_data.indices.size();
|
|
|
|
pc_draw.index_count = inds.size();
|
|
|
|
out.merc_data.indices.insert(out.merc_data.indices.end(), inds.begin(), inds.end());
|
|
|
|
}
|
2022-05-11 22:53:53 -04:00
|
|
|
}
|
|
|
|
}
|
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179)
This PR adds a feature to merc2 to update vertices. This will be needed
to efficient do effects like blerc/ripple/texture scroll. It's enabled
for blerc in jak 1 and jak 2, but with a few disclaimers:
- currently we still use the mips2c blerc implementation, which is slow
and has some "jittering" because of integer precision. When porting to
PC, there was an additional synchronization problem because blerc
overwrites the merc data as its being read by the renderers. I _think_
this wasn't an issue on PS2 because the blerc dma is higher priority
than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex
for this on PC to avoid very slight flickering/gaps. This isn't ideal
for performance, but still beats generic by a significant amount in
every place I tested. If you see merc taking 2ms to draw, it is likely
because it is stuck waiting on blerc to finish. This will go away once
blerc itself is ported to C++.
- in jak 1, we end up using generic in some cases where we could use
merc. In particular maia in village3 hut. This will be fixed later once
we can use merc in more places. I don't want to mess with the
merc/generic selection logic when we're hopefully going to get rid of it
soon.
- There is no support for ripple or texture scroll. These use generic on
jak 1, and remain broken on jak 2.
- Like with `emerc`, jak 1 has a toggle to go back to the old behavior
`*blerc-hack*`.
- In most cases, toggling this causes no visual differences. One
exception is Gol's teeth. I believe this is caused by texture coordinate
rounding issues, where generic has an additional float -> int -> float
compared to PC merc. It is very hard to notice so I'm not going to worry
about it.
2023-01-31 18:23:39 -05:00
|
|
|
|
|
|
|
create_modifiable_vertex_data(vertex_modify_flags, vertex_srcs, out.merc_data, first_out_vertex,
|
|
|
|
first_model, all_effects);
|
|
|
|
|
|
|
|
// compute max draws
|
|
|
|
for (u32 mi = first_model; mi < out.merc_data.models.size(); mi++) {
|
|
|
|
auto& model = out.merc_data.models[mi];
|
|
|
|
model.max_draws = 0;
|
|
|
|
for (auto& e : model.effects) {
|
|
|
|
model.max_draws += e.all_draws.size();
|
|
|
|
if (e.has_mod_draw) {
|
|
|
|
model.max_draws += e.mod.mod_draw.size() + e.mod.fix_draw.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-11 22:53:53 -04:00
|
|
|
}
|
|
|
|
} // namespace decompiler
|