diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index 682fe224bf..d8ef6d73d3 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -1,5 +1,6 @@ #include "gltf_util.h" +#include "algorithm" #include "image_resize.h" #include "common/log/log.h" @@ -186,6 +187,46 @@ std::vector extract_and_flatten_joints_and_weights( return ret; } +std::vector> colors_from_attribute(const tinygltf::Model& model, int attrib) { + const auto attrib_accessor = model.accessors[attrib]; + const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView]; + const auto& buffer = model.buffers[buffer_view.buffer]; + const auto data_ptr = buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset; + const auto byte_stride = attrib_accessor.ByteStride(buffer_view); + const auto count = attrib_accessor.count; + std::vector> colors; + + switch (attrib_accessor.type) { + case TINYGLTF_TYPE_VEC4: + switch (attrib_accessor.componentType) { + case TINYGLTF_COMPONENT_TYPE_FLOAT: + colors = extract_color_from_vec4_float(data_ptr, count, byte_stride); + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride); + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: + colors = extract_color_from_vec4_u8(data_ptr, count, byte_stride); + break; + default: + lg::die("Unknown type for {}", attrib_accessor.componentType); + } + break; + case TINYGLTF_TYPE_VEC3: + switch (attrib_accessor.componentType) { + case TINYGLTF_COMPONENT_TYPE_FLOAT: + colors = extract_color_from_vec3_float(data_ptr, count, byte_stride); + break; + default: + lg::die("Unknown component type for vec3 color {}", attrib_accessor.componentType); + } + break; + default: + lg::die("Unknown attribute type for color {}", attrib_accessor.type); + } + return colors; +} + /*! * Extract positions, colors, and normals from a mesh. */ @@ -196,7 +237,7 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, bool get_normals, const std::string& debug_name) { std::vector result; - std::vector> vtx_colors; + std::vector> vtx_colors; { const auto& position_attrib = attributes.find("POSITION"); @@ -226,54 +267,109 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, new_vert.z = v_w.z() * 4096; } } - if (get_colors) { - const auto& color_attrib = attributes.find("COLOR_0"); - if (color_attrib == attributes.end()) { - lg::error("Mesh {} didn't have any colors, using white", debug_name); - for (size_t i = 0; i < result.size(); i++) { - vtx_colors.emplace_back(0x80, 0x80, 0x80, 0xff); + std::array>>>, 8> + times_of_day = {{{"_SUNRISE", std::nullopt}, + {"_MORNING", std::nullopt}, + {"_NOON", std::nullopt}, + {"_AFTERNOON", std::nullopt}, + {"_SUNSET", std::nullopt}, + {"_TWILIGHT", std::nullopt}, + {"_EVENING", std::nullopt}, + {"_GREENSUN", std::nullopt}}}; + std::optional>> color0 = std::nullopt; + vtx_colors.resize(result.size()); + bool found_one = false; + bool found_all = true; + + for (auto& slot : times_of_day) { + if (const auto attr_val = attributes.find(slot.first); attr_val != attributes.end()) { + slot.second = colors_from_attribute(model, attr_val->second); + found_one = true; + } else { + found_all = false; } - } else { - const auto attrib_accessor = model.accessors[color_attrib->second]; - const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView]; - const auto& buffer = model.buffers[buffer_view.buffer]; - const auto data_ptr = - buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset; - const auto byte_stride = attrib_accessor.ByteStride(buffer_view); - const auto count = attrib_accessor.count; - std::vector> colors; - - switch (attrib_accessor.type) { - case TINYGLTF_TYPE_VEC4: - switch (attrib_accessor.componentType) { - case TINYGLTF_COMPONENT_TYPE_FLOAT: - colors = extract_color_from_vec4_float(data_ptr, count, byte_stride); - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: - colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride); - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: - colors = extract_color_from_vec4_u8(data_ptr, count, byte_stride); - break; - default: - lg::die("Unknown type for COLOR_0: {}", attrib_accessor.componentType); + } + + if (!found_one) { + if (const auto color0_iter = attributes.find("COLOR_0"); color0_iter != attributes.end()) { + color0 = colors_from_attribute(model, color0_iter->second); + lg::warn("{} had colors but no times of day, using COLOR_0.", debug_name); + } else { + const u32 WHITE_COLOR = + 0xFF808080; // Because of little-endianness, FF is at the largest address in memory. + for (auto& vtx_color : vtx_colors) { + // Write white into the color slot for all times of day. + for (u8 byte_offset = 0; byte_offset < 32; byte_offset += 4) { + u8* target_ptr = vtx_color.data() + byte_offset; + std::memcpy(target_ptr, &WHITE_COLOR, sizeof(u32)); } - break; - case TINYGLTF_TYPE_VEC3: - switch (attrib_accessor.componentType) { - case TINYGLTF_COMPONENT_TYPE_FLOAT: - colors = extract_color_from_vec3_float(data_ptr, count, byte_stride); - break; - default: - lg::die("unkonwn component type for vec3 color {}", attrib_accessor.componentType); + } + lg::error("{} didn't have any colors, using white.", debug_name); + } + } + + if (found_one || color0.has_value()) { + if (found_all) { + lg::info("{} had all times of day.", debug_name); + } else if (found_one) { + std::string log_string = ""; + for (size_t slot_index = 0; slot_index < times_of_day.size(); ++slot_index) { + auto& slot = times_of_day[slot_index]; + std::string time_name = slot.first; + std::string value_name; + if (slot.second.has_value()) { + value_name = slot.first; + } else { // If this time_of_day doesn't have a color, use the closest time_of_day with a + // color. + for (int i = 1; !slot.second.has_value(); + ++i) { // Guaranteed to end in 4 iterations or less + int neg_index = (slot_index - i + 8) % 8; + int pos_index = (slot_index + i + 8) % 8; + + if (const auto& neg_slot = times_of_day[neg_index]; + attributes.contains(neg_slot.first)) { + slot.second = neg_slot.second.value(); + value_name = neg_slot.first; + } else if (const auto& pos_slot = times_of_day[pos_index]; + attributes.contains(pos_slot.first)) { + slot.second = pos_slot.second.value(); + value_name = pos_slot.first; + } + } } - break; - default: - lg::die("unknown attribute type for color {}", attrib_accessor.type); + time_name = time_name.substr(1); + std::transform(time_name.begin(), time_name.end(), time_name.begin(), + [](unsigned char c) { return std::tolower(c); }); + if (time_name == "greensun") + time_name = "green sun"; + std::string mapping = time_name + ":" + value_name; + log_string += log_string.empty() ? mapping : ", " + mapping; + } + lg::warn("{} missing some times of day, using {}", debug_name, log_string); } - vtx_colors.insert(vtx_colors.end(), colors.begin(), colors.end()); + // Create iterators to colors for each time of day. + std::array>::const_iterator, 8> iters; + for (int time = 0; time < 8; ++time) { + const std::vector>& time_color = times_of_day[time].second.has_value() + ? times_of_day[time].second.value() + : color0.value(); + + iters[time] = time_color.begin(); + } + + // Write the color for each time of day into vtx_colors. + for (auto& vtx_color : vtx_colors) { + for (int slot_index = 0; slot_index < 8; ++slot_index) { + u8* target_ptr = vtx_color.data() + (4 * slot_index); + auto& color_iter = iters[slot_index]; + const u8* source_ptr = color_iter->data(); + std::memcpy(target_ptr, source_ptr, sizeof(u32)); + + ++color_iter; // Advance the iterator for this time of day. + } + } } } @@ -756,14 +852,15 @@ std::size_t TieFullVertex::hash::operator()(const TieFullVertex& x) const { return tfrag3::PackedTieVertices::Vertex::hash()(x.vertex) ^ std::hash()(x.color_index); } -tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector>& color_palette) { +tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector>& color_palette) { tfrag3::PackedTimeOfDay colors; colors.color_count = (color_palette.size() + 3) & (~3); colors.data.resize(colors.color_count * 8 * 4); for (u32 color_index = 0; color_index < color_palette.size(); color_index++) { for (u32 palette = 0; palette < 8; palette++) { for (u32 channel = 0; channel < 4; channel++) { - colors.read(color_index, palette, channel) = color_palette[color_index][channel]; + colors.read(color_index, palette, channel) = + color_palette[color_index][4 * palette + channel]; } } } diff --git a/common/util/gltf_util.h b/common/util/gltf_util.h index 015704a009..dbbf4b2665 100644 --- a/common/util/gltf_util.h +++ b/common/util/gltf_util.h @@ -46,7 +46,7 @@ std::vector extract_and_flatten_joints_and_weights( struct ExtractedVertices { std::vector vtx; - std::vector> vtx_colors; + std::vector> vtx_colors; std::vector normals; }; @@ -178,13 +178,13 @@ math::Matrix4f matrix_from_trs(const math::Vector3f& trans, const math::Vector4f& quat, const math::Vector3f& scale); -tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector>& color_palette); +tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector>& color_palette); struct MercExtractData { TexturePool tex_pool; std::vector new_indices; std::vector new_vertices; - std::vector> new_colors; + std::vector> new_colors; std::vector normals; std::vector joints_and_weights; tfrag3::MercModel new_model; diff --git a/decompiler/level_extractor/merc_replacement.cpp b/decompiler/level_extractor/merc_replacement.cpp index 467048bd0d..5cb02e0b19 100644 --- a/decompiler/level_extractor/merc_replacement.cpp +++ b/decompiler/level_extractor/merc_replacement.cpp @@ -49,8 +49,10 @@ void extract(tfrag3::MercModel& mdl, auto verts = gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name); out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end()); + out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(), verts.vtx_colors.end()); + out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end()); ASSERT(out.new_colors.size() == out.new_vertices.size()); @@ -186,6 +188,7 @@ void extract(const std::string& name, auto verts = gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name); out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end()); + out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(), verts.vtx_colors.end()); out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end()); diff --git a/goalc/build_actor/common/MercExtract.cpp b/goalc/build_actor/common/MercExtract.cpp index 8945c9a8c7..13af4bb435 100644 --- a/goalc/build_actor/common/MercExtract.cpp +++ b/goalc/build_actor/common/MercExtract.cpp @@ -55,9 +55,12 @@ void extract(const std::string& name, // extract vertices auto verts = gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name); + out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end()); + out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(), verts.vtx_colors.end()); + out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end()); ASSERT(out.new_colors.size() == out.new_vertices.size()); diff --git a/goalc/build_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index 500c85f253..1f7c56c535 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -2,41 +2,29 @@ #include #include +#include +#include #include -#include -#include +#include #include "common/log/log.h" +#include "common/math/Vector.h" #include "common/util/Assert.h" #include "common/util/Timer.h" -/*! - * Just removes duplicate colors, which can work if there are only a few unique colors. - */ -QuantizedColors quantize_colors_dumb(const std::vector>& in) { - QuantizedColors result; - std::unordered_map color_to_slot; - for (auto& vtx : in) { - u64 key; - memcpy(&key, vtx.data(), sizeof(u64)); - const auto& existing = color_to_slot.find(key); - if (existing == color_to_slot.end()) { - auto cidx = result.final_colors.size(); - result.vtx_to_color.push_back(cidx); - color_to_slot[key] = cidx; - result.final_colors.push_back(vtx); - } else { - result.vtx_to_color.push_back(existing->second); - } - } - lg::print("quantize_colors_dumb: {} -> {}\n", in.size(), result.final_colors.size()); - ASSERT(result.final_colors.size() < 8192); - return result; -} - namespace { -using Color = math::Vector; +using Color = math::Vector; + +bool color_less_than(const Color& colorA, const Color& colorB) { + for (int channel = 0; channel < 31; ++channel) { + if (const s32 sum = colorA[channel] - colorB[channel]; sum < 0) + return true; + else if (sum > 0) + return false; + } + return colorA[31] < colorB[31]; +} // An octree node. // Represents a color in the output if rgb_sum_count > 0. @@ -56,24 +44,37 @@ struct Node { u32 final_idx = UINT32_MAX; }; -u8 child_index(Color color, u8 depth) { +u8 child_index(Color& color, u8 depth) { u8 r_bit = (color.x() >> (7 - depth)) & 1; u8 g_bit = (color.y() >> (7 - depth)) & 1; u8 b_bit = (color.z() >> (7 - depth)) & 1; return (r_bit) + (g_bit * 2) + (b_bit * 4); } +std::tuple color_rgb(Color& color) { + u32 r = 0; + u32 g = 0; + u32 b = 0; + for (int channel = 0; channel < 32; channel += 4) { + r += color[channel]; + g += color[channel + 1]; + b += color[channel + 2]; + } + return std::make_tuple(r, g, b); +} + void insert(Node& root, Color color, u8 current_depth) { if (current_depth == 7) { - root.r_sum += color.x(); - root.g_sum += color.y(); - root.b_sum += color.z(); + const auto rgb = color_rgb(color); + root.r_sum += std::get<0>(rgb); + root.g_sum += std::get<1>(rgb); + root.b_sum += std::get<2>(rgb); if (root.rgb_sum_count == 0) { for (auto* up = root.parent; up; up = up->parent) { up->leaves_under_me++; } } - root.rgb_sum_count++; + root.rgb_sum_count += 8; } else { if (root.children.empty()) { root.children.resize(8); @@ -173,8 +174,16 @@ void assign_colors(Node& root, std::vector& palette_out) { for_each_node(root, [&](Node& n) { if (n.rgb_sum_count) { n.final_idx = idx++; - palette_out.emplace_back(n.r_sum / n.rgb_sum_count, n.g_sum / n.rgb_sum_count, - n.b_sum / n.rgb_sum_count, 0); + Color& color = palette_out.emplace_back(); + + for (int time_of_day = 0; time_of_day < 8; ++time_of_day) { + const std::array raw_color = {(u8)(n.r_sum / n.rgb_sum_count), + (u8)(n.g_sum / n.rgb_sum_count), + (u8)(n.b_sum / n.rgb_sum_count), (u8)0}; + const auto source_ptr = &raw_color[0]; + const auto target_ptr = color.data() + 4 * time_of_day; + std::memcpy(target_ptr, source_ptr, sizeof(u32)); + } } }); } @@ -192,7 +201,7 @@ u32 lookup_node_for_color(Node& root, Color c, u8 depth) { /*! * Quantize colors using an octree for clustering. */ -QuantizedColors quantize_colors_octree(const std::vector>& in, +QuantizedColors quantize_colors_octree(const std::vector>& in, u32 target_count) { Node root; root.depth = 0; @@ -263,19 +272,19 @@ size_t pick_split_point(const std::vector& colors, int dim) { } int pick_split_dim_final_splits(const std::vector& colors) { - int mins[4] = {255, 255, 255, 255}; - int maxs[4] = {0, 0, 0, 0}; + std::vector mins(32, 255); + std::vector maxes(32, 0); for (const auto& color : colors) { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 32; i++) { mins[i] = std::min(mins[i], (int)color[i]); - maxs[i] = std::max(maxs[i], (int)color[i]); + maxes[i] = std::max(maxes[i], (int)color[i]); } } int best_dim = 0; int best_diff = 0; - for (int i = 0; i < 4; i++) { - const int diff = maxs[i] - mins[i]; + for (int i = 0; i < 32; i++) { + const int diff = maxes[i] - mins[i]; if (diff > best_diff) { best_diff = diff; best_dim = i; @@ -291,7 +300,7 @@ void split_kd(KdNode* in, u32 depth, int next_split_dim) { } if (!in->colors.empty()) { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 32; i++) { bool all_same = true; u8 same = in->colors[0][next_split_dim]; for (auto& color : in->colors) { @@ -301,7 +310,7 @@ void split_kd(KdNode* in, u32 depth, int next_split_dim) { } } if (all_same) { - next_split_dim = (next_split_dim + 1) % 4; + next_split_dim = (next_split_dim + 1) % 32; } else { break; } @@ -356,8 +365,8 @@ void split_kd(KdNode* in, u32 depth, int next_split_dim) { } */ - split_kd(in->left.get(), depth - 1, (next_split_dim + 1) % 4); - split_kd(in->right.get(), depth - 1, (next_split_dim + 1) % 4); + split_kd(in->left.get(), depth - 1, (next_split_dim + 1) % 32); + split_kd(in->right.get(), depth - 1, (next_split_dim + 1) % 32); } template @@ -370,27 +379,11 @@ void for_each_child(KdNode* node, Func&& f) { } } -u32 color_as_u32(const Color& color) { - u32 ret = 0; - memcpy(&ret, color.data(), 4); - return ret; -} - -Color u32_as_color(u32 in) { - Color ret; - memcpy(ret.data(), &in, 4); - return ret; -} - -std::vector deduplicated_colors(const std::vector& in) { - std::set unique; - for (auto& x : in) { - unique.insert(color_as_u32(x)); - } - std::vector out; - for (auto& x : unique) { - out.push_back(u32_as_color(x)); - } +std::vector remove_duplicates(const std::vector& in) { + std::vector out = in; + std::sort(out.begin(), out.end(), color_less_than); + const auto& end_unique = std::unique(out.begin(), out.end()); + out.erase(end_unique, out.end()); return out; } @@ -404,7 +397,7 @@ u8 saturate_to_u8(u32 in) { s32 color_difference(const Color& c1, const Color& c2) { s32 ret = 0; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 32; i++) { const int diff = (int)c1[i] - (int)c2[i]; ret += diff * diff; } @@ -435,12 +428,30 @@ void get_splittable(KdNode* node, std::vector* out) { } } -QuantizedColors quantize_colors_kd_tree(const std::vector>& in, - u32 target_depth) { +/*! + * Just removes duplicate colors, which can work if there are only a few unique colors. + */ +QuantizedColors quantize_colors_dumb(const std::vector& in) { + QuantizedColors result; + + result.final_colors = remove_duplicates(in); + for (const auto& vtx : in) { + const auto iter = std::lower_bound(result.final_colors.begin(), result.final_colors.end(), vtx, + color_less_than); + const int index = std::distance(result.final_colors.begin(), iter); + result.vtx_to_color.push_back(index); + } + + lg::print("quantize_colors_dumb: {} -> {}\n", in.size(), result.final_colors.size()); + ASSERT(result.final_colors.size() < 8192); + return result; +} + +QuantizedColors quantize_colors_kd_tree(const std::vector& in, u32 target_depth) { Timer timer; // Build root node: KdNode root; - root.colors = deduplicated_colors(in); + root.colors = remove_duplicates(in); const int num_unique_colors = root.colors.size(); // Split tree: @@ -472,7 +483,8 @@ QuantizedColors quantize_colors_kd_tree(const std::vector>& } // Get final colors: - std::unordered_map color_value_to_color_idx; + auto cmp = &color_less_than; + std::map, u32, decltype(cmp)> color_value_to_color_idx(cmp); QuantizedColors result; for_each_child(&root, [&](KdNode* node) { if (node->colors.empty()) { @@ -480,21 +492,30 @@ QuantizedColors quantize_colors_kd_tree(const std::vector>& } const u32 slot = result.final_colors.size(); - u32 totals[4] = {0, 0, 0, 0}; + math::Vector color_totals = math::Vector::zero(); const u32 n = node->colors.size(); for (auto& color : node->colors) { - color_value_to_color_idx[color_as_u32(color)] = slot; - for (int i = 0; i < 4; i++) { - totals[i] += color[i]; - } + color_value_to_color_idx[color] = slot; + for (int channel = 0; channel < 32; ++channel) + color_totals[channel] += color[channel]; + } + auto& final_color = result.final_colors.emplace_back(); + for (int time_of_day = 0; time_of_day < 8; ++time_of_day) { + int color_offset = time_of_day * 4; + + math::Vector time_of_day_color = { + saturate_to_u8(color_totals[color_offset] / n), + saturate_to_u8(color_totals[color_offset + 1] / n), + saturate_to_u8(color_totals[color_offset + 2] / n), + saturate_to_u8(color_totals[color_offset + 3] / (2 * n))}; + const u8* source_ptr = time_of_day_color.data(); + u8* target_ptr = final_color.data() + color_offset; + std::memcpy(target_ptr, source_ptr, sizeof(u32)); } - result.final_colors.emplace_back(saturate_to_u8(totals[0] / n), saturate_to_u8(totals[1] / n), - saturate_to_u8(totals[2] / n), - saturate_to_u8(totals[3] / (2 * n))); }); for (auto& color : in) { - result.vtx_to_color.push_back(color_value_to_color_idx.at(color_as_u32(color))); + result.vtx_to_color.push_back(color_value_to_color_idx.at(color)); } lg::warn("Quantize colors: {} input colors ({} unique) -> {} output in {:.3f} ms\n", in.size(), @@ -508,7 +529,9 @@ QuantizedColors quantize_colors_kd_tree(const std::vector>& for (size_t i = 0; i < result.vtx_to_color.size(); i++) { Color input = in.at(i); - input.w() /= 2; + for (int alpha_channel = 3; alpha_channel < 32; alpha_channel += 4) + input[alpha_channel] /= 2; + const Color output = result.final_colors.at(result.vtx_to_color.at(i)); const s32 diff = color_difference(input, output); if (diff > worst_diff) { @@ -521,6 +544,5 @@ QuantizedColors quantize_colors_kd_tree(const std::vector>& lg::error("Worst diff {} between {} {}", std::sqrt((float)worst_diff), worst_in.to_string_hex_byte(), worst_out.to_string_hex_byte()); } - return result; } diff --git a/goalc/build_level/common/color_quantization.h b/goalc/build_level/common/color_quantization.h index bd302181f0..ab75811de3 100644 --- a/goalc/build_level/common/color_quantization.h +++ b/goalc/build_level/common/color_quantization.h @@ -11,14 +11,14 @@ // but a k-d tree seems like the right approach. struct QuantizedColors { - std::vector> final_colors; + std::vector> final_colors; std::vector vtx_to_color; }; -QuantizedColors quantize_colors_dumb(const std::vector>& in); +QuantizedColors quantize_colors_dumb(const std::vector>& in); -QuantizedColors quantize_colors_octree(const std::vector>& in, +QuantizedColors quantize_colors_octree(const std::vector>& in, u32 target_count); -QuantizedColors quantize_colors_kd_tree(const std::vector>& in, +QuantizedColors quantize_colors_kd_tree(const std::vector>& in, u32 target_depth); \ No newline at end of file diff --git a/goalc/build_level/common/gltf_mesh_extract.cpp b/goalc/build_level/common/gltf_mesh_extract.cpp index 2e384cbd9f..e7b1892e54 100644 --- a/goalc/build_level/common/gltf_mesh_extract.cpp +++ b/goalc/build_level/common/gltf_mesh_extract.cpp @@ -92,7 +92,7 @@ void extract(const Input& in, TfragOutput& out, const tinygltf::Model& model, const std::vector& all_nodes) { - std::vector> all_vtx_colors; + std::vector> all_vtx_colors; ASSERT(out.tfrag_vertices.empty()); struct MaterialInfo { @@ -128,6 +128,7 @@ void extract(const Input& in, // extract vertices auto verts = gltf_vertices(model, prim.attributes, n.w_T_node, true, false, mesh.name); out.tfrag_vertices.insert(out.tfrag_vertices.end(), verts.vtx.begin(), verts.vtx.end()); + all_vtx_colors.insert(all_vtx_colors.end(), verts.vtx_colors.begin(), verts.vtx_colors.end()); ASSERT(all_vtx_colors.size() == out.tfrag_vertices.size()); @@ -248,7 +249,7 @@ void extract(const Input& in, TieOutput& out, const tinygltf::Model& model, const std::vector& all_nodes) { - std::vector> all_vtx_colors; + std::vector> all_vtx_colors; struct MaterialInfo { tfrag3::StripDraw draw; @@ -282,6 +283,7 @@ void extract(const Input& in, // extract vertices auto verts = gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name); add_to_packed_verts(&out.vertices, verts.vtx, verts.normals); + all_vtx_colors.insert(all_vtx_colors.end(), verts.vtx_colors.begin(), verts.vtx_colors.end()); ASSERT(all_vtx_colors.size() == out.vertices.size()); diff --git a/goalc/build_level/common/gltf_mesh_extract.h b/goalc/build_level/common/gltf_mesh_extract.h index fbba828a5a..344bb5bfe9 100644 --- a/goalc/build_level/common/gltf_mesh_extract.h +++ b/goalc/build_level/common/gltf_mesh_extract.h @@ -26,7 +26,7 @@ struct TfragOutput { std::vector normal_strip_draws; std::vector trans_strip_draws; std::vector tfrag_vertices; - std::vector> color_palette; + std::vector> color_palette; }; struct CollideOutput { @@ -38,7 +38,7 @@ struct TieOutput { std::vector envmap_draws; std::vector vertices; std::vector color_indices; - std::vector> color_palette; + std::vector> color_palette; }; struct Output {