[tie] add wind effect (#1046)

* wip tie wind stuff

* wind

* clang
This commit is contained in:
water111
2022-01-02 19:02:28 -05:00
committed by GitHub
parent c9204f2a9b
commit b999422305
10 changed files with 648 additions and 60 deletions
+185 -56
View File
@@ -165,6 +165,8 @@ struct TieInstanceFragInfo {
// this contains indices into the shared palette.
std::vector<u8> color_indices;
// in the PC port format, we upload a single giant time of day color. this points to the offset
// of the colors from this frag instance.
u16 color_index_offset_in_big_palette = -1;
math::Vector<u32, 4> lq_colors_ui(u32 qw) const {
@@ -336,6 +338,25 @@ std::array<math::Vector4f, 4> extract_tie_matrix(const u16* data) {
constexpr int GEOM_IDX = 1; // todo 0 or 1??
/*!
* Confirm that the initial value of all wind vectors is 0.
*/
void check_wind_vectors_zero(const std::vector<TieProtoInfo>& protos, Ref wind_ref) {
u16 max_wind = 0;
for (auto& proto : protos) {
for (auto& inst : proto.instances) {
max_wind = std::max(inst.wind_index, max_wind);
}
}
u32 wind_words = max_wind;
wind_words *= 4;
for (size_t i = 0; i < wind_words; i++) {
auto& word = wind_ref.data->words_by_seg.at(wind_ref.seg).at(wind_ref.byte_offset / 4 + i);
assert(word.kind() == LinkedWord::PLAIN_DATA);
assert(word.data == 0);
}
}
std::vector<TieProtoInfo> collect_instance_info(
const level_tools::DrawableInlineArrayInstanceTie* instances,
const std::vector<level_tools::PrototypeBucketTie>* protos) {
@@ -416,6 +437,9 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
info.uses_generic = (proto.flags == 2);
info.name = proto.name;
info.stiffness = proto.stiffness;
if (info.stiffness != 0) {
fmt::print("--------------------proto {} wind {}\n", info.name, info.stiffness);
}
info.generic_flag = proto.flags & 2;
info.time_of_day_colors.resize(proto.time_of_day.height);
@@ -1674,13 +1698,6 @@ std::string debug_dump_proto_to_obj(const TieProtoInfo& proto) {
math::Vector<float, 3> transform_tie(const std::array<math::Vector4f, 4> mat,
const math::Vector3f& pt) {
auto temp = mat[0] * pt.x() + mat[1] * pt.y() + mat[2] * pt.z() + mat[3];
// math::Vector4f temp;
// temp.x() = pt.x();
// temp.y() = pt.y();
// temp.z() = pt.z();
// temp += mat[3];
math::Vector3f result;
result.x() = temp.x();
result.y() = temp.y();
@@ -1872,17 +1889,33 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
tfrag3::Level& lev,
const TextureDB& tdb,
const std::vector<TieProtoInfo>& protos) {
// our current approach for static draws is just to flatten to giant mesh.
// our current approach for static draws is just to flatten to giant mesh, except for wind stuff.
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
std::unordered_map<u32, std::vector<u32>> wind_draws_by_tex;
std::unordered_map<u32, std::vector<u32>> draws_by_tex;
std::unordered_map<u32, u32> interp_hack_colors;
// renumbering instances.
// loop over all prototypes
for (auto& proto : protos) {
// bool using_wind = true; // hack, for testing
bool using_wind = proto.stiffness != 0.f;
// loop over instances of the prototypes
for (auto& inst : proto.instances) {
u32 wind_instance_idx = tree.instance_info.size();
if (using_wind) {
tfrag3::TieWindInstance wind_instance_info;
wind_instance_info.wind_idx = inst.wind_index;
wind_instance_info.stiffness = proto.stiffness;
wind_instance_info.matrix = inst.mat;
tree.instance_info.push_back(wind_instance_info);
}
// loop over fragments of the prototype
for (size_t frag_idx = 0; frag_idx < proto.frags.size(); frag_idx++) {
auto& frag = proto.frags[frag_idx];
auto& ifrag = inst.frags.at(frag_idx);
// loop over triangle strips within the fragment
for (auto& strip : frag.strips) {
// what texture are we using?
u32 combo_tex = strip.adgif.combo_tex;
@@ -1930,57 +1963,111 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
DrawMode mode =
process_draw_mode(strip.adgif, frag.prog_info.misc_x == 0, frag.has_magic_tex0_bit);
// okay, we now have a texture and draw mode, let's see if we can add to an existing...
auto existing_draws_in_tex = draws_by_tex.find(idx_in_lev_data);
tfrag3::StripDraw* draw_to_add_to = nullptr;
if (existing_draws_in_tex != draws_by_tex.end()) {
for (auto idx : existing_draws_in_tex->second) {
if (tree.static_draws.at(idx).mode == mode) {
draw_to_add_to = &tree.static_draws[idx];
if (using_wind) {
// okay, we now have a texture and draw mode, let's see if we can add to an existing...
auto existing_draws_in_tex = wind_draws_by_tex.find(idx_in_lev_data);
tfrag3::InstancedStripDraw* draw_to_add_to = nullptr;
if (existing_draws_in_tex != wind_draws_by_tex.end()) {
for (auto idx : existing_draws_in_tex->second) {
if (tree.instanced_wind_draws.at(idx).mode == mode) {
draw_to_add_to = &tree.instanced_wind_draws[idx];
}
}
}
}
if (!draw_to_add_to) {
// nope, need to create a new draw
tree.static_draws.emplace_back();
draws_by_tex[idx_in_lev_data].push_back(tree.static_draws.size() - 1);
draw_to_add_to = &tree.static_draws.back();
draw_to_add_to->mode = mode;
draw_to_add_to->tree_tex_id = idx_in_lev_data;
}
// now we have a draw, time to add vertices
tfrag3::StripDraw::VisGroup vgroup;
vgroup.vis_idx = inst.vis_id; // associate with the tfrag for culling
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
draw_to_add_to->num_triangles += strip.verts.size() - 2;
for (auto& vert : strip.verts) {
tfrag3::PreloadedVertex vtx;
// todo fields
auto tf = transform_tie(inst.mat, vert.pos);
vtx.x = tf.x();
vtx.y = tf.y();
vtx.z = tf.z();
vtx.s = vert.tex.x();
vtx.t = vert.tex.y();
vtx.q = vert.tex.z();
// if this is true, we can remove a divide in the shader
assert(vtx.q == 1.f);
if (vert.color_index_index == UINT32_MAX) {
vtx.color_index = 0;
} else {
vtx.color_index = ifrag.color_indices.at(vert.color_index_index);
assert(vert.color_index_index < ifrag.color_indices.size());
vtx.color_index += ifrag.color_index_offset_in_big_palette;
if (!draw_to_add_to) {
// nope, need to create a new draw
tree.instanced_wind_draws.emplace_back();
wind_draws_by_tex[idx_in_lev_data].push_back(tree.instanced_wind_draws.size() - 1);
draw_to_add_to = &tree.instanced_wind_draws.back();
draw_to_add_to->mode = mode;
draw_to_add_to->tree_tex_id = idx_in_lev_data;
}
size_t vert_idx = tree.vertices.size();
tree.vertices.push_back(vtx);
draw_to_add_to->vertex_index_stream.push_back(vert_idx);
// now we have a draw, time to add vertices
tfrag3::InstancedStripDraw::InstanceGroup igroup;
igroup.vis_idx = inst.vis_id; // associate with the tfrag for culling
igroup.num = strip.verts.size() + 1; // one for the primitive restart!
igroup.instance_idx = wind_instance_idx;
draw_to_add_to->num_triangles += strip.verts.size() - 2;
// note: this is a bit wasteful to duplicate the xyz/stq.
for (auto& vert : strip.verts) {
tfrag3::PreloadedVertex vtx;
vtx.x = vert.pos.x();
vtx.y = vert.pos.y();
vtx.z = vert.pos.z();
vtx.s = vert.tex.x();
vtx.t = vert.tex.y();
vtx.q = vert.tex.z();
// if this is true, we can remove a divide in the shader
assert(vtx.q == 1.f);
if (vert.color_index_index == UINT32_MAX) {
vtx.color_index = 0;
} else {
vtx.color_index = ifrag.color_indices.at(vert.color_index_index);
assert(vert.color_index_index < ifrag.color_indices.size());
vtx.color_index += ifrag.color_index_offset_in_big_palette;
}
size_t vert_idx = tree.vertices.size();
tree.vertices.push_back(vtx);
draw_to_add_to->vertex_index_stream.push_back(vert_idx);
}
draw_to_add_to->vertex_index_stream.push_back(UINT32_MAX);
draw_to_add_to->instance_groups.push_back(igroup);
} else {
// okay, we now have a texture and draw mode, let's see if we can add to an existing...
auto existing_draws_in_tex = static_draws_by_tex.find(idx_in_lev_data);
tfrag3::StripDraw* draw_to_add_to = nullptr;
if (existing_draws_in_tex != static_draws_by_tex.end()) {
for (auto idx : existing_draws_in_tex->second) {
if (tree.static_draws.at(idx).mode == mode) {
draw_to_add_to = &tree.static_draws[idx];
}
}
}
if (!draw_to_add_to) {
// nope, need to create a new draw
tree.static_draws.emplace_back();
static_draws_by_tex[idx_in_lev_data].push_back(tree.static_draws.size() - 1);
draw_to_add_to = &tree.static_draws.back();
draw_to_add_to->mode = mode;
draw_to_add_to->tree_tex_id = idx_in_lev_data;
}
// now we have a draw, time to add vertices
tfrag3::StripDraw::VisGroup vgroup;
vgroup.vis_idx = inst.vis_id; // associate with the tfrag for culling
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
draw_to_add_to->num_triangles += strip.verts.size() - 2;
for (auto& vert : strip.verts) {
tfrag3::PreloadedVertex vtx;
// todo fields
auto tf = transform_tie(inst.mat, vert.pos);
vtx.x = tf.x();
vtx.y = tf.y();
vtx.z = tf.z();
vtx.s = vert.tex.x();
vtx.t = vert.tex.y();
vtx.q = vert.tex.z();
// if this is true, we can remove a divide in the shader
assert(vtx.q == 1.f);
if (vert.color_index_index == UINT32_MAX) {
vtx.color_index = 0;
} else {
vtx.color_index = ifrag.color_indices.at(vert.color_index_index);
assert(vert.color_index_index < ifrag.color_indices.size());
vtx.color_index += ifrag.color_index_offset_in_big_palette;
}
size_t vert_idx = tree.vertices.size();
tree.vertices.push_back(vtx);
draw_to_add_to->vertex_index_stream.push_back(vert_idx);
}
draw_to_add_to->vertex_index_stream.push_back(UINT32_MAX);
draw_to_add_to->vis_groups.push_back(vgroup);
}
draw_to_add_to->vertex_index_stream.push_back(UINT32_MAX);
draw_to_add_to->vis_groups.push_back(vgroup);
}
}
}
@@ -1992,6 +2079,33 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
});
}
void merge_groups(std::vector<tfrag3::InstancedStripDraw::InstanceGroup>& grps) {
std::vector<tfrag3::InstancedStripDraw::InstanceGroup> result;
result.push_back(grps.at(0));
for (size_t i = 1; i < grps.size(); i++) {
if (grps[i].vis_idx == result.back().vis_idx &&
grps[i].instance_idx == result.back().instance_idx) {
result.back().num += grps[i].num;
} else {
result.push_back(grps[i]);
}
}
std::swap(result, grps);
}
void merge_groups(std::vector<tfrag3::StripDraw::VisGroup>& grps) {
std::vector<tfrag3::StripDraw::VisGroup> result;
result.push_back(grps.at(0));
for (size_t i = 1; i < grps.size(); i++) {
if (grps[i].vis_idx == result.back().vis_idx) {
result.back().num += grps[i].num;
} else {
result.push_back(grps[i]);
}
}
std::swap(result, grps);
}
void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
const std::string& debug_name,
const std::vector<level_tools::TextureRemap>& tex_map,
@@ -2034,6 +2148,7 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
auto info = collect_instance_info(as_instance_array, &tree->prototypes.prototype_array_tie.data);
update_proto_info(&info, tex_map, tex_db, tree->prototypes.prototype_array_tie.data);
check_wind_vectors_zero(info, tree->prototypes.wind_vectors);
// debug_print_info(info);
emulate_tie_prototype_program(info);
emulate_tie_instance_program(info);
@@ -2064,6 +2179,20 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
str.vis_idx = it->second;
}
}
merge_groups(draw.vis_groups);
}
for (auto& draw : this_tree.instanced_wind_draws) {
for (auto& str : draw.instance_groups) {
auto it = instance_parents.find(str.vis_idx);
if (it == instance_parents.end()) {
str.vis_idx = UINT32_MAX;
} else {
str.vis_idx = it->second;
}
}
merge_groups(draw.instance_groups);
}
this_tree.colors = full_palette.colors;