From a25c08d409abd0a944e366c1add40d5cbb412ee6 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 28 Nov 2025 17:52:26 -0500 Subject: [PATCH 01/20] Reworking loop --- common/util/gltf_util.cpp | 75 ++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index 682fe224bf9..2dbb2f3ab8d 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -228,55 +228,40 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, } 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); + const std::array slot_names = { + "_SUNRISE", "_MORNING", "_NOON", "_AFTERNOON", + "_SUNSET", "_TWILIGHT", "_EVENING", "_GREENSUN" + }; + vtx_colors.resize(result.size()); + + //Fall back to all vertex colors being white if: + //at least one time of day is not in attributes, and + //COLOR_0 is not defined. + bool white_fallback = false; + for (const std::string &slot_name : slot_names) { + lg::info("Checking time of day {}", slot_name); + + std::map::const_iterator color_attrib; + if ( color_attrib = attributes.find(slot_name); + color_attrib != attributes.end() ){ + lg::info("Found time of day {}", slot_name); } - } 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); - } - 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); - } - break; - default: - lg::die("unknown attribute type for color {}", attrib_accessor.type); + else if( color_attrib = attributes.find("COLOR_0"); + color_attrib != attributes.end() ) { + lg::info("Mesh {} didn't have time of day {}, using COLOR_0", debug_name, slot_name); + } + else + { + lg::error("Mesh {} didn't have time of day {} or COLOR_0, using white", debug_name, slot_name); + white_fallback = true; } - - vtx_colors.insert(vtx_colors.end(), colors.begin(), colors.end()); + } + if(white_fallback) + { + for(auto& color : vtx_colors) + color = { 0x80, 0x80, 0x80, 0xff }; } } - bool got_texture = false; { const auto& texcoord_attrib = attributes.find("TEXCOORD_0"); From d91a09a38ed59e75b81f0f8e63997f4dd1ecec23 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 30 Nov 2025 12:31:17 -0500 Subject: [PATCH 02/20] Working on updating types so that 4 color channels are used for each of the 8 times of day, for a total of 32 channels (bytes) in each color. --- common/util/gltf_util.cpp | 79 +++++++++++++--- common/util/gltf_util.h | 6 +- .../jak1/levels/test-zone/test-zone2.glb | Bin 8264 -> 13212 bytes .../level_extractor/merc_replacement.cpp | 28 +++++- goalc/build_actor/common/MercExtract.cpp | 8 +- .../build_level/common/color_quantization.cpp | 87 ++++++++++-------- goalc/build_level/common/color_quantization.h | 8 +- .../build_level/common/gltf_mesh_extract.cpp | 32 +++++-- goalc/build_level/common/gltf_mesh_extract.h | 4 +- 9 files changed, 182 insertions(+), 70 deletions(-) diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index 2dbb2f3ab8d..1a8fe63b5c7 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -196,7 +196,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"); @@ -237,10 +237,13 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, //Fall back to all vertex colors being white if: //at least one time of day is not in attributes, and //COLOR_0 is not defined. - bool white_fallback = false; - for (const std::string &slot_name : slot_names) { + for( size_t slot_index = 0; slot_index < slot_names.size(); ++ slot_index ) + { + const auto& slot_name = slot_names[slot_index]; lg::info("Checking time of day {}", slot_name); + size_t byte_offset = slot_index * 4; + std::map::const_iterator color_attrib; if ( color_attrib = attributes.find(slot_name); color_attrib != attributes.end() ){ @@ -253,13 +256,67 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, else { lg::error("Mesh {} didn't have time of day {} or COLOR_0, using white", debug_name, slot_name); - white_fallback = true; + const uint32_t WHITE_COLOR = 0x808080FF; + for(auto& vtx_color : vtx_colors) //Write white into the color slot for this time of day. + { + u8* target_ptr = vtx_color.data() + byte_offset; + std::memcpy(target_ptr, &WHITE_COLOR, sizeof(uint32_t)); + } + continue; + } + + 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); + } + 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); + } + break; + default: + lg::die("unknown attribute type for color {}", attrib_accessor.type); + } + + //Write the colors for the time of day (or color0, if it exists) + //into the right slot for the time of day + auto vtx_color_iter = vtx_colors.begin(); + auto color_iter = colors.begin(); + while( vtx_color_iter != vtx_colors.end() ) + { + auto& vtx_color = *vtx_color_iter; + u8* target_ptr = vtx_color.data() + byte_offset; + u8* source_ptr = color_iter->data(); + std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); + + ++vtx_color_iter; + ++color_iter; } - } - if(white_fallback) - { - for(auto& color : vtx_colors) - color = { 0x80, 0x80, 0x80, 0xff }; } } bool got_texture = false; @@ -741,14 +798,14 @@ 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 015704a009c..dbbf4b2665d 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/custom_assets/jak1/levels/test-zone/test-zone2.glb b/custom_assets/jak1/levels/test-zone/test-zone2.glb index 2df7f4d59537ba09ff5baa8b42fe6e3aefb196d1..d22d5c6eb6950c3cee93f83c4993f236cee617aa 100644 GIT binary patch literal 13212 zcmcIq+j8Sb8P+nhz`}Cag@s#}s<_h_sioE-RKXlJGX!RmB?$vnQ&Wj2f-)>8?Y{y`*t|!4=!4#FljwJ>-JxFhpnBT@3r1X zZQYI%*K^-@hZns;AIhrjyVst3aRLYKmS12O?$(Pdx8FGj&pj|Q&+QLhcPa3_z*Ao6 zMV|KJm)9?+l8MRF-s#&B;tU6)&d3CM;kSc0^AnwBP^XM5`oCbrdFuIU08Q7iZ!(d8>9I9r0W?WbW7=^zSXKhUxAR9opNN-`8ajZosi%i1an5eU_X1eLPfs~Ptw zRZt0WFKLHyrjjs7b)vE?_4SHD!g3I07a9|-w2xU^3_@Qp!d4_+T9urFT0cUKJUKiT%L`d73#?H-K*iV?x=Hi);rlBT%Nw|cQ4?C zYbj?w?wpv-2ph^!#ry^X=W8-6!rAdYOX#or7(63q5!A;PK)1{_fu1uDgZV zKYF&epDSVtj-KpqZ|_3e-HJiwN{Q!wv3Ia@xI>H7b9eXlpFMc$Ze^Z(xc$dRdwctz zANdH1@jcpmy0>o#q>vKEE@{-lNJdv zi*}EM$>LC4_{)Z}3W)t>CRDUU0rm2sB6O3CDnc>sQAJ^8R4+ZZbApz+7!1)icz$?w z`Q}Y`_`KKslUb@KgY$QTez!k5{PG>{t2$suo(wMgBeN*`gW-AStoN7c?lUra?(^+O z5uQdy>qgX6_=-DrMj*p2!_({I!tHl2<7!>XzJGf7MTop=7shdmFE zx9H^a9-fY0+#`9y776hs}5(K zmA>iL=RJ3`8E(4ydGFtBhPCa#&ZN}#{2C7V9JA3O^HFHC4mZ70^4s4A?-6{a+w71x zy;9VsR|+3an}&>d#qM|T=)uzm`<3mJ&!bfb)9sTrl{-WJGCH|4;O4OK*1$*HMedun z=dgBJ%%(TBuihQ-0$me-x=#79+FT$$MK2n`8U^Bm`6Bnz0aovxVQtT^P@vitpS53S zc*awCjnBGo9A0gI&$F+Y|F5^b`2w=e>_uy~H{Vbe#b0Cg_|mh;ebekkD>XM}4-cNx zmnQoq%Dh0m`f}8L+U=i?@VS!9lJwr2H|7&C3OVWwPx&>NUsBcdeQBX7UES6;#`3$Z zZH6|!t!==4`_{(s8r8yQ!P`exyqzqYc7!3?Q>^p~1uGke_=vf5a8s6TUnwyQ<2O@uSij z#_RNU%J03mO*`c>yR~t;Lc#bY+unvUGVI9s5-8v1D)$=2d7ZIdrNt`Nfhq@Yy3v`f z+72FQe}#c3rGevTv~@-vB&%#km7y#AE;d{Dm4>cDK5N<2)?{9du2ZlRT1!sH>fctEwD zN~1K4@vBX%)%x$Jj`MJ5*SWcIoS)sf!7(3R{Uevx!-t6jFE=;!@INNP&CNV`*Uhcx zK}!GjFJ@N{Z*Ic>4;LSl*Wtn=Y{Es}1jj`_ z;)iq@7n-mRA9E#54_V8?5gVZelFwrT7x{s_?AzEEcH+n85$9oYDB|Uu{3eKoS!(~bw0%PL+6L^U}`r8WL|{xaLPqz9!}dur}&^=9WFe=CS2rAa9rdgen^*b zp$Y5oF^Xgz9G`uNjm;xY{tPVJ)zD?%#=g)Ke>Tqqz{TWH#1o#;D|linP;|=i%-q%a zDdk}MVc!~>5U1&51Zcqz`Gh=QHuULfV{H$xNRH2nvD3$e*3 z8kl!Z{xC2Oi(k+}eJf=<|7dsnLpL7}0pV--udZf$HjCq{r+K4kAPtmQzDO+@k z9rfyP;So0BB5#6YE8lrI?I|Oy!y&T|>e`3c*gWFo&%m->4PEwa>L7A~q9^tODQCYKnh>YyKk!?KO+F!yW738EK6$_$K z8DSj`nSD^#KE%f65hs5JmhEcjvTtKw=!rj@X9D12awy^n&*&9Au@xvf<#cv)F)kr^e1*Uq#o&6 F_ixT`cb3+) zf(g%p#ZjvPvsTz{hB7U9W}RHW5i=q!#=(NZroT9;6>mH&i%QzvaJrERUOOYppD zztgtgZQZ}!#h@CFz+$)n(e8esldu_%!);IJ;B|Kfcr5!Ogrg9=j2GdmuYbf<*!H!P zP@x*iz>T;D6XA@w7yhYUS3;T*9tCabBkL4`8rC2_Mtxz~&}iGYdix?-4yTn-n#>TA;b+1p7&Rv?3 z;BEHw@v``bh*K`&1J&O&3~1`k)G^*s$KN4`aP45cj2@mcJjf+!x!Ljj8X^3HgNf$U zNHXG2J+}+}Hot{Z}u &new_color = out.new_colors.emplace_back(); + // const u8* source_ptr = vtx_color.data() + vtx_color_offset; + // u8* target_ptr = new_color.data(); + // std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); + // } + 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,8 +196,18 @@ 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()); + + // const u32 time_of_day = 0; //Defaulting to time of day being zero for now. + // const u32 vtx_color_offset = time_of_day * 4; + // for( const auto &vtx_color : verts.vtx_colors ) + // { + // math::Vector &new_color = out.new_colors.emplace_back(); + // const u8* source_ptr = vtx_color.data() + vtx_color_offset; + // u8* target_ptr = new_color.data(); + // std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); + // } + + 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_actor/common/MercExtract.cpp b/goalc/build_actor/common/MercExtract.cpp index 8945c9a8c74..2082e3cc581 100644 --- a/goalc/build_actor/common/MercExtract.cpp +++ b/goalc/build_actor/common/MercExtract.cpp @@ -55,9 +55,13 @@ 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.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 500c85f253c..4e20fdbf1d2 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -2,18 +2,20 @@ #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 quantize_colors_dumb(const std::vector>& in) { QuantizedColors result; std::unordered_map color_to_slot; for (auto& vtx : in) { @@ -36,7 +38,16 @@ QuantizedColors quantize_colors_dumb(const std::vector>& in) namespace { -using Color = math::Vector; +using Color = math::Vector; + +bool color_less_than(const math::Vector& colorA, const math::Vector& colorB) +{ + for(int channel = 0; channel < 32; ++channel){ + if(colorA[channel] > colorB[channel]) + return false; + } + return colorA[31] < colorB[31]; +} // An octree node. // Represents a color in the output if rgb_sum_count > 0. @@ -173,8 +184,15 @@ 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 +210,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; @@ -370,27 +388,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; } @@ -435,12 +437,12 @@ void get_splittable(KdNode* node, std::vector* out) { } } -QuantizedColors quantize_colors_kd_tree(const std::vector>& in, +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 +474,7 @@ QuantizedColors quantize_colors_kd_tree(const std::vector>& } // Get final colors: - std::unordered_map color_value_to_color_idx; + std::map, u32, bool(*)(const math::Vector&, const math::Vector&)> color_value_to_color_idx(&color_less_than); QuantizedColors result; for_each_child(&root, [&](KdNode* node) { if (node->colors.empty()) { @@ -480,21 +482,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]; + for(int channel = 0; channel < 32; ++channel) + { + color_value_to_color_idx[color] = slot; + color_totals[channel] += color[channel]; } } - 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))); + 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; + + std::array time_of_day_color = {saturate_to_u8(color_totals[color_offset + 0] / 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[0]; + u8* target_ptr = final_color.data() + color_offset; + std::memcpy(target_ptr, source_ptr, sizeof(u32)); + } }); 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(), diff --git a/goalc/build_level/common/color_quantization.h b/goalc/build_level/common/color_quantization.h index bd302181f0f..ab75811de35 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 2e384cbd9f6..a77b8f2023d 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,8 +128,18 @@ 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()); + + // const u32 time_of_day = 0; //Defaulting to time of day being zero for now. + // const u32 vtx_color_offset = time_of_day * 4; + // for( const auto &vtx_color : verts.vtx_colors ) + // { + // math::Vector &new_color = all_vtx_colors.emplace_back(); + // const u8* source_ptr = vtx_color.data() + vtx_color_offset; + // u8* target_ptr = new_color.data(); + // std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); + // } + + 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()); auto& info = info_by_material[prim.material]; @@ -248,7 +258,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,8 +292,18 @@ 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()); + + + // const u32 time_of_day = 0; //Defaulting to time of day being zero for now. + // const u32 vtx_color_offset = time_of_day * 4; + // for( const auto &vtx_color : verts.vtx_colors ) + // { + // math::Vector &new_color = all_vtx_colors.emplace_back(); + // const u8* source_ptr = vtx_color.data() + vtx_color_offset; + // u8* target_ptr = new_color.data(); + // std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); + // } + all_vtx_colors.insert(all_vtx_colors.end(), verts.vtx_colors.begin(), verts.vtx_colors.end()); ASSERT(all_vtx_colors.size() == out.vertices.size()); auto& info = info_by_material[prim.material]; diff --git a/goalc/build_level/common/gltf_mesh_extract.h b/goalc/build_level/common/gltf_mesh_extract.h index fbba828a5a3..344bb5bfe9d 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 { From e1c55e5a8e8d75eb076f3b96c3f3d40390cee92a Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 30 Nov 2025 14:02:49 -0500 Subject: [PATCH 03/20] Cleaning up. --- .../level_extractor/merc_replacement.cpp | 19 ------------------- goalc/build_actor/common/MercExtract.cpp | 2 -- .../build_level/common/color_quantization.cpp | 4 +--- .../build_level/common/gltf_mesh_extract.cpp | 12 +----------- 4 files changed, 2 insertions(+), 35 deletions(-) diff --git a/decompiler/level_extractor/merc_replacement.cpp b/decompiler/level_extractor/merc_replacement.cpp index 3195097db70..724d7724cb1 100644 --- a/decompiler/level_extractor/merc_replacement.cpp +++ b/decompiler/level_extractor/merc_replacement.cpp @@ -50,15 +50,6 @@ void extract(tfrag3::MercModel& mdl, 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()); - // const u32 time_of_day = 0; //Defaulting to time of day being zero for now. - // const u32 vtx_color_offset = time_of_day * 4; - // for( const auto &vtx_color : verts.vtx_colors ) - // { - // math::Vector &new_color = out.new_colors.emplace_back(); - // const u8* source_ptr = vtx_color.data() + vtx_color_offset; - // u8* target_ptr = new_color.data(); - // std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); - // } 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()); @@ -197,16 +188,6 @@ void extract(const std::string& name, 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()); - // const u32 time_of_day = 0; //Defaulting to time of day being zero for now. - // const u32 vtx_color_offset = time_of_day * 4; - // for( const auto &vtx_color : verts.vtx_colors ) - // { - // math::Vector &new_color = out.new_colors.emplace_back(); - // const u8* source_ptr = vtx_color.data() + vtx_color_offset; - // u8* target_ptr = new_color.data(); - // std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); - // } - 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_actor/common/MercExtract.cpp b/goalc/build_actor/common/MercExtract.cpp index 2082e3cc581..4520235e28a 100644 --- a/goalc/build_actor/common/MercExtract.cpp +++ b/goalc/build_actor/common/MercExtract.cpp @@ -58,8 +58,6 @@ void extract(const std::string& 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_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index 4e20fdbf1d2..b3fe29efe6c 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -485,11 +485,9 @@ QuantizedColors quantize_colors_kd_tree(const std::vector>& math::Vector color_totals = math::Vector::zero(); const u32 n = node->colors.size(); for (auto& color : node->colors) { + color_value_to_color_idx[color] = slot; for(int channel = 0; channel < 32; ++channel) - { - color_value_to_color_idx[color] = slot; 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){ diff --git a/goalc/build_level/common/gltf_mesh_extract.cpp b/goalc/build_level/common/gltf_mesh_extract.cpp index a77b8f2023d..a65fd32e6a8 100644 --- a/goalc/build_level/common/gltf_mesh_extract.cpp +++ b/goalc/build_level/common/gltf_mesh_extract.cpp @@ -292,17 +292,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); - - - // const u32 time_of_day = 0; //Defaulting to time of day being zero for now. - // const u32 vtx_color_offset = time_of_day * 4; - // for( const auto &vtx_color : verts.vtx_colors ) - // { - // math::Vector &new_color = all_vtx_colors.emplace_back(); - // const u8* source_ptr = vtx_color.data() + vtx_color_offset; - // u8* target_ptr = new_color.data(); - // std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); - // } + all_vtx_colors.insert(all_vtx_colors.end(), verts.vtx_colors.begin(), verts.vtx_colors.end()); ASSERT(all_vtx_colors.size() == out.vertices.size()); From 98da716221a0e4832a860ee7b352deac6c2b8e35 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 18 Dec 2025 19:34:07 -0500 Subject: [PATCH 04/20] Making log messages less verbose. --- common/util/gltf_util.cpp | 59 ++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index 1a8fe63b5c7..805a70aad95 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -237,34 +237,35 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, //Fall back to all vertex colors being white if: //at least one time of day is not in attributes, and //COLOR_0 is not defined. + std::string times_found = ""; + std::string times_missing = ""; + bool hadColor0 = false; for( size_t slot_index = 0; slot_index < slot_names.size(); ++ slot_index ) { const auto& slot_name = slot_names[slot_index]; - lg::info("Checking time of day {}", slot_name); - + size_t byte_offset = slot_index * 4; - std::map::const_iterator color_attrib; - if ( color_attrib = attributes.find(slot_name); - color_attrib != attributes.end() ){ - lg::info("Found time of day {}", slot_name); - } - else if( color_attrib = attributes.find("COLOR_0"); - color_attrib != attributes.end() ) { - lg::info("Mesh {} didn't have time of day {}, using COLOR_0", debug_name, slot_name); + if (color_attrib = attributes.find(slot_name); color_attrib != attributes.end()){ + times_found += times_found.empty() ? slot_name : ", " + slot_name; } - else - { - lg::error("Mesh {} didn't have time of day {} or COLOR_0, using white", debug_name, slot_name); - const uint32_t WHITE_COLOR = 0x808080FF; - for(auto& vtx_color : vtx_colors) //Write white into the color slot for this time of day. + else{ + times_missing += times_missing.empty() ? slot_name : ", " + slot_name; + if(color_attrib = attributes.find("COLOR_0"); color_attrib != attributes.end()) + { + hadColor0 = true; + } + else { - u8* target_ptr = vtx_color.data() + byte_offset; - std::memcpy(target_ptr, &WHITE_COLOR, sizeof(uint32_t)); + const uint32_t WHITE_COLOR = 0x808080FF; + for(auto& vtx_color : vtx_colors) //Write white into the color slot for this time of day. + { + u8* target_ptr = vtx_color.data() + byte_offset; + std::memcpy(target_ptr, &WHITE_COLOR, sizeof(uint32_t)); + } + continue; } - continue; } - 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]; @@ -287,7 +288,7 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, colors = extract_color_from_vec4_u8(data_ptr, count, byte_stride); break; default: - lg::die("Unknown type for COLOR_0: {}", attrib_accessor.componentType); + lg::die("Unknown type for {}", attrib_accessor.componentType); } break; case TINYGLTF_TYPE_VEC3: @@ -296,11 +297,11 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, 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::die("Unknown component type for vec3 color {}", attrib_accessor.componentType); } break; default: - lg::die("unknown attribute type for color {}", attrib_accessor.type); + lg::die("Unknown attribute type for color {}", attrib_accessor.type); } //Write the colors for the time of day (or color0, if it exists) @@ -318,7 +319,21 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, ++color_iter; } } + if(times_missing.empty()){ + lg::info("{} had all times of day.", debug_name); + } + else{ + std::string defaulting_string = hadColor0 ? "COLOR_0" : "white"; + if(times_found.empty()){ + lg::info("{} missing all times of day, defaulting to {}.", debug_name, defaulting_string); + } + else{ + lg::info("{} had times of day: {} but was missing: {}.", debug_name, times_found, times_missing); + lg::info( "The missing times of day default to {}", defaulting_string); + } + } } + bool got_texture = false; { const auto& texcoord_attrib = attributes.find("TEXCOORD_0"); From b398f2f4cc19a8189bbf018ddd529758d975c109 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 24 Dec 2025 08:53:26 -0500 Subject: [PATCH 05/20] Storing modified test-zone. --- .../jak1/levels/test-zone/test-zone3.glb | Bin 0 -> 8264 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 custom_assets/jak1/levels/test-zone/test-zone3.glb diff --git a/custom_assets/jak1/levels/test-zone/test-zone3.glb b/custom_assets/jak1/levels/test-zone/test-zone3.glb new file mode 100644 index 0000000000000000000000000000000000000000..2df7f4d59537ba09ff5baa8b42fe6e3aefb196d1 GIT binary patch literal 8264 zcmcIoTaO#J6`s^do1|&eq)qxN%=1_!Im5Z^L%WWfqHbMpU>iXI!-(XyycV!48ItTa zSS+A_ru>Nfpnf04v!dpvb=-16p8JJ|XE>uhJAeGQUqn&#_dyhW_q!xew(ZhVG^Eip$Ocu-O zdAkXbPhXoff4|ZC+|^ zp=S%|7uFPIX|uFI%++E%Tb_&eY^aLdWHwbrWlWltevMj5jP*xRXasy5yLp#(qD{ZCn zT&c<$Yzz5hMOviF<{47VQj_R>h@?@HvdHo@Evg_xjY4lvrrP7TMw~Jw#SEfjHiBqhqQrWi* zlGcNmu+TVYV--%>Pe)v zB+z^n{GnF1%F#GmP2VgX2?UO1*+IA2kOescaQY-gDbuNYB9Z-uBLCibi7(Erq5olNM6R@ zoIJYs_}<9__s~2zdHAn8_v0gU=i{%xyL)o-@UP#i_{dx(@pSfldPxOVm}A{D`&P{_SKRrNhRP2%w>T4On1Y+p6cUcY!TS$sR4{M$9v>HOl=d^VY_ z9{=zPSFqJ4PvX=0>lt2l*wV%LKfIR{youoHVu}~pliMV3yW7Iq#NU2>H^r;%G7f#C z@&|mcdaQ9)H?}s7*tq+e){g1+g&q3XkM7>Nf9GMt9vg4k@9JWL!fdb2>%yQm2P=c_ zIOM&rG%kP9lon>Zr`j9FN{O> z@=W}UqvsuT$bIkjT048c_&fWS?fri{n-||ZZSNg>8y^M-s^kq)%SFaKBUV7M1Jxpl(+7DC0|c&vAu!S*K^V zcbJ7XeXdPeOIl}rX*blfUhnv*+)t*^eW@2UZTt-B*=Qpde4xLLI^MEblYb*0lbWnYzv<40JJ z|7JdAu69qae{#de6+gZ32|f7f(%Zbkgh2Xk=~{(EuCMW+kj1U|ZO@j-bTE`SH)*h7gl9$H3=A$T1@A<;Ubv50Lt#2bduoQOC>0E`-!4U5E51b|Iu5={md> zeFVWr(J!M9qmQF6uznH!KKeuS$LKSxpGCioeiMBfy^r;MJTJeBK94@Z`bqR&^kwwx z=mV@DMEJ*H|Fg4!ocRhogj4U(6d%-U!-YrKhl{)qZi3vqaN1Kw*oH&q#@YkY9w$d^ zh}Zd!1)tY77x;}>0z~@BBF(U2d$K(Nz0I5%UfEmIOb-Y~cLP&kmbx40=7eeZhu0yH&n*KI^ zw&COnzYE_4KDu!6L3tZ4Ji$uQ_ZTJRt<5;_O+s7U!M{Jz5#uqtl zrH4BGAWmJ!+57m6(`gHtlRE=0+aWx$6}r<8b6^~fwOidHdA0drzd1f3rt3dg4SY_7 z93#?ReoP+l2$1@u2bduoQOC>0E`-!4U5E51b|Iu5={oG~`OS83PKWV0h1Z5tc4&$n z_1bXZ5%%FC?}M8l-!7c?lo7V!kh!t;fV9WS5gX!lzGJ~B`HbNPa1KYW9qJaT+m_hp zlVTk4->`+u$(W3f<`kIo5UPNpf%V!+vvoLQL0xuo?KA2suWiz5JLw;1MA8 zNe?hXIHHc1i(Lq*Pr452PwYZSJ<@e3bzjrp#?LmKJmGiYo4`jGEJCM+c>G$Ax>Y{a1Hv9AIR%E&feQOfADk7^SGlCOX5kM z!oP;luj{yY;LC954_|JqJp_=vB!|!s`_0jWn6Cd|Gw?YPa*RlO`7wFGBS7kt9$(^|yAV>JbRE*4*oBaKr1#-}0kv~_egFUf literal 0 HcmV?d00001 From d03ee41c37b7fe278276c178ef3cac2bc13e9d49 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 24 Dec 2025 11:11:05 -0500 Subject: [PATCH 06/20] Fixing formatting issues, fixed endianness bug. --- common/util/gltf_util.cpp | 28 ++++----- .../{test-zone3.glb => test-zone2.old.glb} | Bin goalc/build_actor/common/MercExtract.cpp | 4 +- .../build_level/common/color_quantization.cpp | 59 +++++++++--------- 4 files changed, 43 insertions(+), 48 deletions(-) rename custom_assets/jak1/levels/test-zone/{test-zone3.glb => test-zone2.old.glb} (100%) diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index 805a70aad95..a8a59e025bb 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -233,17 +233,14 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, "_SUNSET", "_TWILIGHT", "_EVENING", "_GREENSUN" }; vtx_colors.resize(result.size()); - - //Fall back to all vertex colors being white if: - //at least one time of day is not in attributes, and - //COLOR_0 is not defined. + std::string times_found = ""; std::string times_missing = ""; bool hadColor0 = false; - for( size_t slot_index = 0; slot_index < slot_names.size(); ++ slot_index ) + for( size_t slot_index = 0; slot_index < slot_names.size(); ++slot_index ) { const auto& slot_name = slot_names[slot_index]; - + size_t byte_offset = slot_index * 4; std::map::const_iterator color_attrib; if (color_attrib = attributes.find(slot_name); color_attrib != attributes.end()){ @@ -251,13 +248,15 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, } else{ times_missing += times_missing.empty() ? slot_name : ", " + slot_name; - if(color_attrib = attributes.find("COLOR_0"); color_attrib != attributes.end()) + if(color_attrib = attributes.find("COLOR_0"); color_attrib != attributes.end()) { hadColor0 = true; } else { - const uint32_t WHITE_COLOR = 0x808080FF; + //On little endian systems, the most significant byte is stored last. + //Thus why byte for transparency is first in the constant here. + const uint32_t WHITE_COLOR = 0xFF808080; for(auto& vtx_color : vtx_colors) //Write white into the color slot for this time of day. { u8* target_ptr = vtx_color.data() + byte_offset; @@ -303,7 +302,7 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, default: lg::die("Unknown attribute type for color {}", attrib_accessor.type); } - + assert(vtx_colors.size() == colors.size()); //Write the colors for the time of day (or color0, if it exists) //into the right slot for the time of day auto vtx_color_iter = vtx_colors.begin(); @@ -324,13 +323,10 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, } else{ std::string defaulting_string = hadColor0 ? "COLOR_0" : "white"; - if(times_found.empty()){ - lg::info("{} missing all times of day, defaulting to {}.", debug_name, defaulting_string); - } - else{ - lg::info("{} had times of day: {} but was missing: {}.", debug_name, times_found, times_missing); - lg::info( "The missing times of day default to {}", defaulting_string); - } + if(times_found.empty()) + lg::info("{} missing all times of day, defaulted to {}.", debug_name, defaulting_string); + else + lg::info("{} had times of day: {} but was missing: {} which defaulted to {}.", debug_name, times_found, times_missing, defaulting_string); } } diff --git a/custom_assets/jak1/levels/test-zone/test-zone3.glb b/custom_assets/jak1/levels/test-zone/test-zone2.old.glb similarity index 100% rename from custom_assets/jak1/levels/test-zone/test-zone3.glb rename to custom_assets/jak1/levels/test-zone/test-zone2.old.glb diff --git a/goalc/build_actor/common/MercExtract.cpp b/goalc/build_actor/common/MercExtract.cpp index 4520235e28a..83fa764dc22 100644 --- a/goalc/build_actor/common/MercExtract.cpp +++ b/goalc/build_actor/common/MercExtract.cpp @@ -55,11 +55,11 @@ 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 b3fe29efe6c..7cf29f94257 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include "common/log/log.h" @@ -12,35 +11,11 @@ #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 math::Vector& colorA, const math::Vector& colorB) +bool color_less_than(const Color& colorA, const Color& colorB) { for(int channel = 0; channel < 32; ++channel){ if(colorA[channel] > colorB[channel]) @@ -406,7 +381,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; } @@ -437,7 +412,31 @@ void get_splittable(KdNode* node, std::vector* out) { } } -QuantizedColors quantize_colors_kd_tree(const std::vector>& in, +/*! +* 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; +} + +QuantizedColors quantize_colors_kd_tree(const std::vector& in, u32 target_depth) { Timer timer; // Build root node: From e59a46d8eaf4a6e056cd5d1a0cc10115126af421 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 26 Dec 2025 14:24:48 -0500 Subject: [PATCH 07/20] Trying to work on using 32 channel colors for color_quantization instead of 4. --- .../build_level/common/color_quantization.cpp | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/goalc/build_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index 7cf29f94257..646cf739061 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "common/log/log.h" @@ -17,8 +18,11 @@ namespace { bool color_less_than(const Color& colorA, const Color& colorB) { - for(int channel = 0; channel < 32; ++channel){ - if(colorA[channel] > colorB[channel]) + for(int channel = 0; channel < 31; ++channel){ + const s32 sum = colorA[channel] - colorB[channel]; + if(sum < 0) + return true; + else if(sum > 0) return false; } return colorA[31] < colorB[31]; @@ -42,24 +46,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,u32>(rgb); + root.g_sum += std::get<1,u32>(rgb); + root.b_sum += std::get<2,u32>(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); @@ -256,19 +273,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; From ee6c0ec5a46c0439144543f2f1468174e4821ae8 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 27 Dec 2025 18:49:47 -0500 Subject: [PATCH 08/20] Reworked reading color attributes. Will to default to color for closest time of day if possible. --- common/util/gltf_util.cpp | 219 +++++++++++------- .../levels/test-zone/test-zone2.morphed.glb | Bin 0 -> 13460 bytes 2 files changed, 133 insertions(+), 86 deletions(-) create mode 100644 custom_assets/jak1/levels/test-zone/test-zone2.morphed.glb diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index a8a59e025bb..75f140a650f 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -1,7 +1,7 @@ #include "gltf_util.h" #include "image_resize.h" - +#include "algorithm" #include "common/log/log.h" namespace gltf_util { @@ -186,6 +186,47 @@ 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. */ @@ -226,108 +267,114 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, new_vert.z = v_w.z() * 4096; } } - - if (get_colors) { - const std::array slot_names = { - "_SUNRISE", "_MORNING", "_NOON", "_AFTERNOON", - "_SUNSET", "_TWILIGHT", "_EVENING", "_GREENSUN" - }; + if (get_colors) + { + 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()); - - std::string times_found = ""; - std::string times_missing = ""; - bool hadColor0 = false; - for( size_t slot_index = 0; slot_index < slot_names.size(); ++slot_index ) + bool found_one = false; + bool found_all = true; + + for(size_t slot_index = 0; slot_index < times_of_day.size(); ++slot_index) { - const auto& slot_name = slot_names[slot_index]; + auto& slot = times_of_day[slot_index]; + 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; + } + } - size_t byte_offset = slot_index * 4; - std::map::const_iterator color_attrib; - if (color_attrib = attributes.find(slot_name); color_attrib != attributes.end()){ - times_found += times_found.empty() ? slot_name : ", " + slot_name; + if(!found_one){ + std::string defaulting_string; + if(const auto color0_iter = attributes.find("COLOR_0"); color0_iter != attributes.end()) + { + color0 = colors_from_attribute(model, color0_iter->second); + defaulting_string = "COLOR_0"; } - else{ - times_missing += times_missing.empty() ? slot_name : ", " + slot_name; - if(color_attrib = attributes.find("COLOR_0"); color_attrib != attributes.end()) - { - hadColor0 = true; - } - else + else + { + const uint32_t WHITE_COLOR = 0xFF808080; + for(auto& vtx_color : vtx_colors) { - //On little endian systems, the most significant byte is stored last. - //Thus why byte for transparency is first in the constant here. - const uint32_t WHITE_COLOR = 0xFF808080; - for(auto& vtx_color : vtx_colors) //Write white into the color slot for this time of day. + //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(uint32_t)); } - continue; } + defaulting_string = "white"; } - 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 {}", attrib_accessor.componentType); + lg::info("{} missing all times of day, defaulted to {}.", debug_name, defaulting_string); + } + + 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, value_name; + if(slot.second.has_value()) + { + value_name = slot.first; } - 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); + else + { + for(int i = 1; i <= 4;++i){ + int neg_index = (slot_index - i + 8) % 8; + int pos_index = (slot_index + i + 8) % 8; + if(const auto& near_slot = times_of_day[neg_index]; near_slot.second.has_value()) + { + slot.second = near_slot.second.value(); + value_name = near_slot.first; + break; + } + + if(const auto& near_slot = times_of_day[pos_index]; near_slot.second.has_value()) + { + slot.second = near_slot.second.value(); + value_name = near_slot.first; + break; + } + } } - 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); }); + std::string mapping = time_name + ":" + value_name; + log_string += log_string.empty() ? mapping : ", " + mapping; + } + lg::info("{} missing some times of day, using {}", debug_name, log_string); } - assert(vtx_colors.size() == colors.size()); - //Write the colors for the time of day (or color0, if it exists) - //into the right slot for the time of day - auto vtx_color_iter = vtx_colors.begin(); - auto color_iter = colors.begin(); - while( vtx_color_iter != vtx_colors.end() ) + + for(size_t slot_index = 0; slot_index < times_of_day.size(); ++slot_index) { - auto& vtx_color = *vtx_color_iter; - u8* target_ptr = vtx_color.data() + byte_offset; - u8* source_ptr = color_iter->data(); - std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); - - ++vtx_color_iter; - ++color_iter; + const auto &colors = times_of_day[slot_index].second.has_value() ? times_of_day[slot_index].second.value() : color0.value(); + assert(vtx_colors.size() == colors.size()); + //Write the color for this time of day into the channels for the time of day. + auto vtx_color_iter = vtx_colors.begin(); + auto color_iter = colors.begin(); + for( ;vtx_color_iter != vtx_colors.end(); ++vtx_color_iter, ++color_iter) + { + u8* target_ptr = vtx_color_iter->data() + (4 * slot_index); + const u8* source_ptr = color_iter->data(); + std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); + } } } - if(times_missing.empty()){ - lg::info("{} had all times of day.", debug_name); - } - else{ - std::string defaulting_string = hadColor0 ? "COLOR_0" : "white"; - if(times_found.empty()) - lg::info("{} missing all times of day, defaulted to {}.", debug_name, defaulting_string); - else - lg::info("{} had times of day: {} but was missing: {} which defaulted to {}.", debug_name, times_found, times_missing, defaulting_string); - } } bool got_texture = false; diff --git a/custom_assets/jak1/levels/test-zone/test-zone2.morphed.glb b/custom_assets/jak1/levels/test-zone/test-zone2.morphed.glb new file mode 100644 index 0000000000000000000000000000000000000000..95a77bf6a4b1055024ff38083bb7afa9a3ac698f GIT binary patch literal 13460 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 dbOV Date: Sun, 28 Dec 2025 01:01:06 -0500 Subject: [PATCH 09/20] Fixed error with defaulting implementation. --- common/util/gltf_util.cpp | 4 ++-- .../jak1/levels/test-zone/test-zone2.glb | Bin 13212 -> 13460 bytes .../levels/test-zone/test-zone2.morphed.glb | Bin 13460 -> 0 bytes .../jak1/levels/test-zone/test-zone2.new.glb | Bin 0 -> 13212 bytes 4 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 custom_assets/jak1/levels/test-zone/test-zone2.morphed.glb create mode 100644 custom_assets/jak1/levels/test-zone/test-zone2.new.glb diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index 75f140a650f..d393a1f129f 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -337,14 +337,14 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, for(int i = 1; i <= 4;++i){ int neg_index = (slot_index - i + 8) % 8; int pos_index = (slot_index + i + 8) % 8; - if(const auto& near_slot = times_of_day[neg_index]; near_slot.second.has_value()) + if(const auto& near_slot = times_of_day[neg_index]; attributes.contains(near_slot.first) ) { slot.second = near_slot.second.value(); value_name = near_slot.first; break; } - if(const auto& near_slot = times_of_day[pos_index]; near_slot.second.has_value()) + if(const auto& near_slot = times_of_day[pos_index]; attributes.contains(near_slot.first) ) { slot.second = near_slot.second.value(); value_name = near_slot.first; diff --git a/custom_assets/jak1/levels/test-zone/test-zone2.glb b/custom_assets/jak1/levels/test-zone/test-zone2.glb index d22d5c6eb6950c3cee93f83c4993f236cee617aa..95a77bf6a4b1055024ff38083bb7afa9a3ac698f 100644 GIT binary patch delta 2146 zcmc&zOH9*X9PipOCg`?y4u~0JE5iqj(0*;#ZY-G~1((38+XOLDjE@i!kB|yS3e3$>@`@Pn7&t})=T(fs_ zqclZPYcfTB2|RIaw#ZS9Xo4Ceq~NmsVQyqEr8B9l&c}raKQorm^)znyxQLTJsi#xv zF+NUkm@qP>LBb(z7>JRv%T1-mQ)B0Id|bh4Xf&s1N|#X_Q7NnE;BFJRmLvS!{H?j0 zw--=52KOBkeQ20AG804NXn=M({qi}($c)SgIFnjDk>Hmj86)UdC7|0s1hhM6j2jt? zt=6$;nw9Id*@zb5FBsWWE@l1<65H05FjTFsgu$x15f42Ka_hD+s+1U1TMM>OtU`l9BV00>ufhX=Mu2R_QQi#4pgqBrFlcJ$ZaD< z_=-0bo(LV@u*IA9cEfM36V|=`(0r7GO>ZqqJ^rci)A!mAi+&FiRig07KS)QTz_$0n zMkmX}a20Cng@FKT7l|xe!vbE&l7(eNMW}%7q8h89IY!V*;DG?g5Vg9e<%&3G`n(UA zKAbHEtUqG8NCcJ3mb4^;r`_7qxP2Fhn4#>FCK9l94KlJQph5z}XjTYJ$;gUUR%Pw7 zs+NF?U|J>YiX>~W6zp>=iYzQ&U4H4KsNqzaf?%ivgpd37@bJs}u$E-F{f@ zK6wrQrFe?PooaE9vlFkhhqs|sSUKZ>$! QH#I5hkZQ6)QlgPwYRBYDz@cHL6DP4$B|ToxPMyCCAQWNmLTa)Z_(YGLeOjI#&!~COMfP zQ5DyRMze{Gkxm;VN|BDIGe*)FBT)^>SSFD$P)(v?WTpsa>tInNBk5E+Go_QL+*cue zB&uLeX-Afj$yFvJQ>sishRJ26iVTCxj3UG2GSiTS7eq2Mdt>JM&3R-Ik=zEsb~dDo z#7Jkxhf=tR9kPkbBk6SJ^b`iGQmsXm;ejnKs+eCfsF=RPKzA7mHVxj|8blSVR89B< zJ4}&Xrqv^Zkg7kyVqjB!T%>sYikD(|t(U4hz4^QK4jVjcl40H641+>L5!)Qwc(ewu zI0D7}_cd$Bo!i>!8ocfdz>1x~FQ*4KcstzTV{ne|f)9Kfyx@D_bE5#?_>%XzgFv^? zT-No&f?#?=uqkwcU1)<|S10=WVb;|HZA}8aay93KP|m#xPhAcRh3}1i@VnzIRlwpV z7}1K0%T1n~;LC5iUs_?#!^1 zn%TP4frcrCH|?SGR9C|bR~G_-z*m7`hLZ+UC@@TrE8y?oc`sku-#ek#PhhJ(&~7CR z9#tspKfyqm(;t92oIm{c7avVri80Jl9REO=f5C^ftF+(SuD11Xq*SmtA@1k@w|2&V p>e~Ld+rG6~^Y9u6KXQ;OJ|@0WeyQW44PFO>`QKfi*xleG`xlZI)++!2 diff --git a/custom_assets/jak1/levels/test-zone/test-zone2.morphed.glb b/custom_assets/jak1/levels/test-zone/test-zone2.morphed.glb deleted file mode 100644 index 95a77bf6a4b1055024ff38083bb7afa9a3ac698f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13460 zcmdT~+ioLC8SZ6vfraI;z`zYcR$upcyQ{kTkPDc@W`;l}UL|2b8jTVs@nkF|_Q-Jt zmQkd+=L(5OK;i|sHxIxS;*KZbDtupcmtF2|w~s3^CAI(aq5k^+cDs}Fi^IoXa~$U{ zq2v7fXO8o$gVx?#w|#Zh8M<3<-SbYbGiVR{19!{)^{YX@*S~6qSHI;3>rJ1 zwHj~2rfP<<>$z__gR5@82W8Rp-5bxnI)wvw%g?bZckB6Ex7WS|&ppsG&+YZkIu!U` z;0aH9p{Km)#m$R}WNfnAJ%2SsoI!us9_m2P{bmrQeyrjo_MHgJ-;bp5yV00$Ei$w$U^9;*iXYaj1rN6F9d=P2kqX~g>fG?{Wub#l3FYy>8WPw z%OncYG*tl{!gtX0eFdE~422&F87D7pytnRU=jxT-d%oc>F4`ytOVPeS0iFkO(@*^* zNzyp>l^-YG0-REYsu`#-QK=tAzMm=)C=dCBv5cj!q7W&DQg}hsMAE29g563Pr&fjm zDxDq4qw5nUI9-CI=_fJ>RS*V|AE-!pqA64u#wjYFgs5@grA?7a1VZ^CVIe045L50^ zs-P6&Ufh&XDq`X+^yl@x-(Ai^Ullm^~LaMu8u5UpA4RMhV6@s?&*I2`utU|a|I`y zrHuKweX8$9xT6e=e9UXA8{RfJclwSpzHgYxdp+o0c8A?JxwJhT4!S4TLy~XZql4e< z?e83H>ybTrvcJ8(2adai@i^Lkw!OEr_r%>oGao%|?Pmm3!K_G{WP#};&MnoWxLPo?Ok{i$M_RhMe ztO4$2usIKhjC!q&&3u=A-<Exz#F_9@!#sy{&M;j!T4`sK^c;90lxdp&`t{ma+=UZ*!a z{PH!vEma`U?5F+f9v)1v!(M-I*}mxhadJ-?YCZSa_M;Gw9@G9%`;Gd;@om(f-r5HD zivn#lKeW+C{hJRs{jrv0?m;LFaP5)iC|G-B$4^OS=X@%hvp6SlC>Yf(Mn8FtxMV=$meQeuI^_v(BV%y7l=@y4egj-TeGU-)x4J z?Z3{URQCMDAu5u0-NB;=yASqDZOdng@)jp;D{$&&BC|*P@kC-M=Z+*FPv*I=8w*i6 z7SriX?8{S`eYMTL|MP2mPJt@hemaA73RF1+)9xo5EZ?<+RxNIDmVHHm=CnA^f4L_D zKDd>SeA1FDc&u#l={>G-1bm(>Cp_)G?g;q&xww7#2>8fawqK`UcvG`!k6-N+@M*eS zf+dbXtFAr;a^q7VE2m(3N9*+L0wYn^v*A)bkDkS&*yLw~{j);qMksdvMOzo_uA9->2pm#9ULlTGci}$F6Fd;+$5s4S4@s**IFGT6q1n zdSt=d@}g;n*rI*JLM>6SqOruwx`iVbn@g%C_FRgbtPz>-epgN#FCo`3UZ*|PI_;^} zX-~ZGTz${@OTpsCe3NIlXH;xYycU{y4-!eCxua-_fi796#n^TCKRv;A=79*8*mqpm zcYrtH(^Xq)goxLQj=x+jo_y)l1^#5Tj(N&k)uMOf z(%z*gp8Hajm*Fz^h;sCZzbO|@zEnDyaC}!b=bw)jH!me0N{;`c(aYv4St5FA?_tal zUNm~iT=~m%T`74b%Uw5q?8_hdtmi!Zsg8fh`0HKAdAPIZ{KvVyb#Tpsx3}`Yl+T6_ z<4j%+Df{z3vl!LzUje;4&Mb&O#_JrbA#Ljxt?KL@=iMmNdG`z8xVSWK_<&=+;pKWp zR~zMavvAwLZD;t4!CB{I__NQ+oMZJl-QH&Wull^Q>hQd|s^ACC9Z2pt{4WfijlNLt zTAXsDGYcPCK4#&@2jx|`;Stv1MqUR;c|OJu=^}1u!YX{kDo&Q^Wy3KxhBlCVt}&eF z2lAqCZJ*m2KQ@mzm(C%NmvORBV^f4irx;J4f0ds?4#pq-{Nv~O9tm-g=4!wX^$59+ zN$2wW<*b-wF-$N8S~AwECEynMs?f%6GIKXE>Ae(ZeP`3RpMIp2o|UAqw=^CFyu zQ*Lx-;k2E186VWE!VQnG4ma{TILh-een=N_LlaivBNWM6+@HOSjm;xY{uC_QRnSG> z+CJAa{%oEOfDfHR9?$T!Ud}VN1{$4WJbiXmehN9*e%QB~Cd8%t7y%maLp~wbG3i`> zpFH3WAoWQ%aM|#fI=S4~*^v6Ai;(_|oeil+x(LCo{H}RF__w!z{}c0nUm?zLlwUm0 zI-GK&GYdENbXDv?@9W%7@~-=Z_5Ux!8IJOc=UInS zZgghh#=Z_3AJnPB4Ue!6H}X0-%J*dakS^keCal6o=v!-*W;VC6R5VIoTw^%T59CGP z+CH~4erz6bE}eHCFXLpN#-<33PBET7|0+L)9E?Bu;k;{_5SN~R@Eh<$J|WjJ>0ExF zJm3x>^+`8y+3=V;x!l; z%I00hj(SzN;Stv1MqUR;R=%@v+EYeYg+pd9>e|cL*gWFoPr;&H1zq&5?Q=cj&*td> z_|Q4z@eEJv1C5@sH;{79i>3*2>G=V_f!O2|avhV-<@d=0?f_Ds dbOVf-)>8?Y{y`*t|!4=!4#FljwJ>-JxFhpnBT@3r1X zZQYI%*K^-@hZns;AIhrjyVst3aRLYKmS12O?$(Pdx8FGj&pj|Q&+QLhcPa3_z*Ao6 zMV|KJm)9?+l8MRF-s#&B;tU6)&d3CM;kSc0^AnwBP^XM5`oCbrdFuIU08Q7iZ!(d8>9I9r0W?WbW7=^zSXKhUxAR9opNN-`8ajZosi%i1an5eU_X1eLPfs~Ptw zRZt0WFKLHyrjjs7b)vE?_4SHD!g3I07a9|-w2xU^3_@Qp!d4_+T9urFT0cUKJUKiT%L`d73#?H-K*iV?x=Hi);rlBT%Nw|cQ4?C zYbj?w?wpv-2ph^!#ry^X=W8-6!rAdYOX#or7(63q5!A;PK)1{_fu1uDgZV zKYF&epDSVtj-KpqZ|_3e-HJiwN{Q!wv3Ia@xI>H7b9eXlpFMc$Ze^Z(xc$dRdwctz zANdH1@jcpmy0>o#q>vKEE@{-lNJdv zi*}EM$>LC4_{)Z}3W)t>CRDUU0rm2sB6O3CDnc>sQAJ^8R4+ZZbApz+7!1)icz$?w z`Q}Y`_`KKslUb@KgY$QTez!k5{PG>{t2$suo(wMgBeN*`gW-AStoN7c?lUra?(^+O z5uQdy>qgX6_=-DrMj*p2!_({I!tHl2<7!>XzJGf7MTop=7shdmFE zx9H^a9-fY0+#`9y776hs}5(K zmA>iL=RJ3`8E(4ydGFtBhPCa#&ZN}#{2C7V9JA3O^HFHC4mZ70^4s4A?-6{a+w71x zy;9VsR|+3an}&>d#qM|T=)uzm`<3mJ&!bfb)9sTrl{-WJGCH|4;O4OK*1$*HMedun z=dgBJ%%(TBuihQ-0$me-x=#79+FT$$MK2n`8U^Bm`6Bnz0aovxVQtT^P@vitpS53S zc*awCjnBGo9A0gI&$F+Y|F5^b`2w=e>_uy~H{Vbe#b0Cg_|mh;ebekkD>XM}4-cNx zmnQoq%Dh0m`f}8L+U=i?@VS!9lJwr2H|7&C3OVWwPx&>NUsBcdeQBX7UES6;#`3$Z zZH6|!t!==4`_{(s8r8yQ!P`exyqzqYc7!3?Q>^p~1uGke_=vf5a8s6TUnwyQ<2O@uSij z#_RNU%J03mO*`c>yR~t;Lc#bY+unvUGVI9s5-8v1D)$=2d7ZIdrNt`Nfhq@Yy3v`f z+72FQe}#c3rGevTv~@-vB&%#km7y#AE;d{Dm4>cDK5N<2)?{9du2ZlRT1!sH>fctEwD zN~1K4@vBX%)%x$Jj`MJ5*SWcIoS)sf!7(3R{Uevx!-t6jFE=;!@INNP&CNV`*Uhcx zK}!GjFJ@N{Z*Ic>4;LSl*Wtn=Y{Es}1jj`_ z;)iq@7n-mRA9E#54_V8?5gVZelFwrT7x{s_?AzEEcH+n85$9oYDB|Uu{3eKoS!(~bw0%PL+6L^U}`r8WL|{xaLPqz9!}dur}&^=9WFe=CS2rAa9rdgen^*b zp$Y5oF^Xgz9G`uNjm;xY{tPVJ)zD?%#=g)Ke>Tqqz{TWH#1o#;D|linP;|=i%-q%a zDdk}MVc!~>5U1&51Zcqz`Gh=QHuULfV{H$xNRH2nvD3$e*3 z8kl!Z{xC2Oi(k+}eJf=<|7dsnLpL7}0pV--udZf$HjCq{r+K4kAPtmQzDO+@k z9rfyP;So0BB5#6YE8lrI?I|Oy!y&T|>e`3c*gWFo&%m->4PEwa>L7A~q9^tODQCYKnh>YyKk!?KO+F!yW738EK6$_$K z8DSj`nSD^#KE%f65hs5JmhEcjvTtKw=!rj@X9D12awy^n&*&9Au@xvf<#cv)F)kr^e1*Uq#o&6 F_ Date: Sun, 28 Dec 2025 14:30:38 -0500 Subject: [PATCH 10/20] Reworking implementation. --- common/util/gltf_util.cpp | 41 +++++++++++------- .../jak1/levels/test-zone/test-zone2.glb | Bin 13460 -> 12528 bytes .../levels/test-zone/test-zone2.morphed.glb | Bin 0 -> 13460 bytes 3 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 custom_assets/jak1/levels/test-zone/test-zone2.morphed.glb diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index d393a1f129f..d890688c906 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -293,15 +293,14 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, } if(!found_one){ - std::string defaulting_string; if(const auto color0_iter = attributes.find("COLOR_0"); color0_iter != attributes.end()) { color0 = colors_from_attribute(model, color0_iter->second); - defaulting_string = "COLOR_0"; + lg::info("{} had colors but no times of day, using COLOR_0.", debug_name); } else { - const uint32_t WHITE_COLOR = 0xFF808080; + const uint32_t 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. @@ -311,9 +310,8 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, std::memcpy(target_ptr, &WHITE_COLOR, sizeof(uint32_t)); } } - defaulting_string = "white"; + lg::info("{} didn't have any colors, using white.", debug_name); } - lg::info("{} missing all times of day, defaulted to {}.", debug_name, defaulting_string); } if(found_one || color0.has_value()) @@ -332,7 +330,7 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, { value_name = slot.first; } - else + else //If this time_of_day doesn't have a color, use the closest time_of_day with a color. { for(int i = 1; i <= 4;++i){ int neg_index = (slot_index - i + 8) % 8; @@ -354,24 +352,35 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, } 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::info("{} missing some times of day, using {}", debug_name, log_string); } - for(size_t slot_index = 0; slot_index < times_of_day.size(); ++slot_index) + //Create iterators to colors for each time of day. + std::array>::iterator,8> iters; + for(int time = 0; time < 8; ++time){ + std::vector> &time_color = times_of_day[time].second.has_value() ? + times_of_day[time].second.value() : color0.value(); + + assert(time_color.size() == vtx_colors.size()); + iters[time] = time_color.begin(); + } + + //Write the color for each time of day into vtx_colors. + for(auto& vtx_color : vtx_colors) { - const auto &colors = times_of_day[slot_index].second.has_value() ? times_of_day[slot_index].second.value() : color0.value(); - assert(vtx_colors.size() == colors.size()); - //Write the color for this time of day into the channels for the time of day. - auto vtx_color_iter = vtx_colors.begin(); - auto color_iter = colors.begin(); - for( ;vtx_color_iter != vtx_colors.end(); ++vtx_color_iter, ++color_iter) + for(int slot_index = 0; slot_index < 8; ++slot_index) { - u8* target_ptr = vtx_color_iter->data() + (4 * slot_index); - const u8* source_ptr = color_iter->data(); - std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); + 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(uint32_t)); + + ++color_iter; //Advance the iterator for this time of day. } } } diff --git a/custom_assets/jak1/levels/test-zone/test-zone2.glb b/custom_assets/jak1/levels/test-zone/test-zone2.glb index 95a77bf6a4b1055024ff38083bb7afa9a3ac698f..22db4e5ddcf56b29bfe03c8fd83a97e2b387dd48 100644 GIT binary patch literal 12528 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 dbOV Date: Mon, 29 Dec 2025 02:40:32 -0500 Subject: [PATCH 11/20] Slight code quality improvement and improving logs. --- common/util/gltf_util.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index d890688c906..8859ed6cad3 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -278,9 +278,8 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, bool found_one = false; bool found_all = true; - for(size_t slot_index = 0; slot_index < times_of_day.size(); ++slot_index) + for(auto& slot : times_of_day) { - auto& slot = times_of_day[slot_index]; if (const auto attr_val = attributes.find(slot.first); attr_val != attributes.end()) { slot.second = colors_from_attribute(model, attr_val->second); @@ -296,7 +295,7 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, if(const auto color0_iter = attributes.find("COLOR_0"); color0_iter != attributes.end()) { color0 = colors_from_attribute(model, color0_iter->second); - lg::info("{} had colors but no times of day, using COLOR_0.", debug_name); + lg::warn("{} had colors but no times of day, using COLOR_0.", debug_name); } else { @@ -310,7 +309,7 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, std::memcpy(target_ptr, &WHITE_COLOR, sizeof(uint32_t)); } } - lg::info("{} didn't have any colors, using white.", debug_name); + lg::error("{} didn't have any colors, using white.", debug_name); } } @@ -325,28 +324,27 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, 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, value_name; + 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; i <= 4;++i){ + 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& near_slot = times_of_day[neg_index]; attributes.contains(near_slot.first) ) + + if(const auto& neg_slot = times_of_day[neg_index]; attributes.contains(neg_slot.first) ) { - slot.second = near_slot.second.value(); - value_name = near_slot.first; - break; + slot.second = neg_slot.second.value(); + value_name = neg_slot.first; } - - if(const auto& near_slot = times_of_day[pos_index]; attributes.contains(near_slot.first) ) + else if(const auto& pos_slot = times_of_day[pos_index]; attributes.contains(pos_slot.first) ) { - slot.second = near_slot.second.value(); - value_name = near_slot.first; - break; + slot.second = pos_slot.second.value(); + value_name = pos_slot.first; } } } @@ -357,11 +355,11 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, std::string mapping = time_name + ":" + value_name; log_string += log_string.empty() ? mapping : ", " + mapping; } - lg::info("{} missing some times of day, using {}", debug_name, log_string); + lg::warn("{} missing some times of day, using {}", debug_name, log_string); } //Create iterators to colors for each time of day. - std::array>::iterator,8> iters; + std::array>::const_iterator,8> iters; for(int time = 0; time < 8; ++time){ std::vector> &time_color = times_of_day[time].second.has_value() ? times_of_day[time].second.value() : color0.value(); From fd5e8f5a6a034fa14459af64947f299d5bd1e4f2 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 30 Dec 2025 01:20:34 -0500 Subject: [PATCH 12/20] Updating code formatting. --- common/util/gltf_util.cpp | 72 ++++++++----------- .../build_level/common/color_quantization.cpp | 22 +++--- 2 files changed, 38 insertions(+), 56 deletions(-) diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index 8859ed6cad3..44d117d86b6 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -186,7 +186,7 @@ std::vector extract_and_flatten_joints_and_weights( return ret; } -std::vector> colors_from_attribute(const tinygltf::Model& model, int attrib){ +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]; @@ -277,79 +277,65 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, 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()) - { + + 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 - { + else { found_all = false; } } - if(!found_one){ - if(const auto color0_iter = attributes.find("COLOR_0"); color0_iter != attributes.end()) - { + 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 uint32_t WHITE_COLOR = 0xFF808080; //Because of little-endianness, FF is at the largest address in memory. - for(auto& vtx_color : vtx_colors) - { + 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) - { + 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(uint32_t)); + std::memcpy(target_ptr, &WHITE_COLOR, sizeof(u32)); } } lg::error("{} didn't have any colors, using white.", debug_name); } } - if(found_one || color0.has_value()) - { - if(found_all){ + if(found_one || color0.has_value()) { + if(found_all) { lg::info("{} had all times of day.", debug_name); } - else if(found_one) - { + else if(found_one) { std::string log_string = ""; - for(size_t slot_index = 0; slot_index < times_of_day.size(); ++slot_index) - { + 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()) - { + 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 + 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) ) - { + + 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) ) - { + 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; } } } time_name = time_name.substr(1); - std::transform(time_name.begin(), time_name.end(), time_name.begin(),[](unsigned char c){ return std::tolower(c); }); + 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; @@ -360,8 +346,8 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, //Create iterators to colors for each time of day. std::array>::const_iterator,8> iters; - for(int time = 0; time < 8; ++time){ - std::vector> &time_color = times_of_day[time].second.has_value() ? + 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(); assert(time_color.size() == vtx_colors.size()); @@ -369,14 +355,12 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, } //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) - { + 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(uint32_t)); + std::memcpy(target_ptr, source_ptr, sizeof(u32)); ++color_iter; //Advance the iterator for this time of day. } diff --git a/goalc/build_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index 646cf739061..f08aab4a30f 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -13,14 +13,13 @@ #include "common/util/Timer.h" 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){ - const s32 sum = colorA[channel] - colorB[channel]; - if(sum < 0) + if(const s32 sum = colorA[channel] - colorB[channel];sum < 0) return true; else if(sum > 0) return false; @@ -177,14 +176,13 @@ void assign_colors(Node& root, std::vector& palette_out) { if (n.rgb_sum_count) { n.final_idx = idx++; 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)); - // } - + + 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)); + } } }); } From 9af38d618b1fcbd3b429c3032691c2da5e105cd4 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 30 Dec 2025 01:43:11 -0500 Subject: [PATCH 13/20] Removing comments. --- goalc/build_level/common/gltf_mesh_extract.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/goalc/build_level/common/gltf_mesh_extract.cpp b/goalc/build_level/common/gltf_mesh_extract.cpp index a65fd32e6a8..86023cddf0e 100644 --- a/goalc/build_level/common/gltf_mesh_extract.cpp +++ b/goalc/build_level/common/gltf_mesh_extract.cpp @@ -128,17 +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()); - - // const u32 time_of_day = 0; //Defaulting to time of day being zero for now. - // const u32 vtx_color_offset = time_of_day * 4; - // for( const auto &vtx_color : verts.vtx_colors ) - // { - // math::Vector &new_color = all_vtx_colors.emplace_back(); - // const u8* source_ptr = vtx_color.data() + vtx_color_offset; - // u8* target_ptr = new_color.data(); - // std::memcpy(target_ptr, source_ptr, sizeof(uint32_t)); - // } - + 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()); From 7685324f8ccd5b0e341d40b2c41715ac22b9e6a3 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 30 Dec 2025 02:12:54 -0500 Subject: [PATCH 14/20] Fixing quantize_colors_dumb. --- .../build_level/common/color_quantization.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/goalc/build_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index f08aab4a30f..05a647af5e0 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -432,18 +432,19 @@ void get_splittable(KdNode* node, std::vector* out) { */ 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 less_than = [](const Color& lhs, const Color& rhs) { + return color_less_than(lhs, rhs); + }; + std::map color_to_slot(less_than); + for (const auto& vtx : in) { + if (const auto iter = color_to_slot.find(vtx); iter != color_to_slot.end()) { + result.vtx_to_color.push_back(iter->second); + } + else { auto cidx = result.final_colors.size(); result.vtx_to_color.push_back(cidx); - color_to_slot[key] = cidx; + color_to_slot[vtx] = 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()); From 404936ae9c23ec6c24f8a02f73ad365d871d358f Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 30 Dec 2025 02:49:45 -0500 Subject: [PATCH 15/20] Further improved quantize_colors_dumb. --- .../build_level/common/color_quantization.cpp | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/goalc/build_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index 05a647af5e0..ef1e72c1102 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -432,21 +432,14 @@ void get_splittable(KdNode* node, std::vector* out) { */ QuantizedColors quantize_colors_dumb(const std::vector& in) { QuantizedColors result; - auto less_than = [](const Color& lhs, const Color& rhs) { - return color_less_than(lhs, rhs); - }; - std::map color_to_slot(less_than); - for (const auto& vtx : in) { - if (const auto iter = color_to_slot.find(vtx); iter != color_to_slot.end()) { - result.vtx_to_color.push_back(iter->second); - } - else { - auto cidx = result.final_colors.size(); - result.vtx_to_color.push_back(cidx); - color_to_slot[vtx] = cidx; - result.final_colors.push_back(vtx); - } + + 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; From 2e513d2cb10704c8ad20ef7dedff2af78fb50300 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 30 Dec 2025 14:49:01 -0500 Subject: [PATCH 16/20] Fixing formatting, and some minor issues in color_quantization code. --- goalc/build_level/common/color_quantization.cpp | 17 ++++++++++------- goalc/build_level/common/gltf_mesh_extract.cpp | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/goalc/build_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index ef1e72c1102..fc0aec8aaea 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "common/log/log.h" #include "common/math/Vector.h" @@ -309,7 +308,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; } @@ -364,8 +363,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 @@ -482,7 +481,8 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, } // Get final colors: - std::map, u32, bool(*)(const math::Vector&, const math::Vector&)> color_value_to_color_idx(&color_less_than); + 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()) { @@ -501,7 +501,8 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, for(int time_of_day = 0; time_of_day < 8; ++time_of_day){ int color_offset = time_of_day * 4; - std::array time_of_day_color = {saturate_to_u8(color_totals[color_offset + 0] / n), saturate_to_u8(color_totals[color_offset + 1] / n), + std::array time_of_day_color = {saturate_to_u8(color_totals[color_offset + 0] / 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[0]; @@ -509,6 +510,7 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, std::memcpy(target_ptr, source_ptr, sizeof(u32)); } }); + for (auto& color : in) { result.vtx_to_color.push_back(color_value_to_color_idx.at(color)); @@ -525,7 +527,8 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, 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) { diff --git a/goalc/build_level/common/gltf_mesh_extract.cpp b/goalc/build_level/common/gltf_mesh_extract.cpp index 86023cddf0e..2ca24aed507 100644 --- a/goalc/build_level/common/gltf_mesh_extract.cpp +++ b/goalc/build_level/common/gltf_mesh_extract.cpp @@ -128,7 +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()); @@ -282,7 +282,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()); From 2fb7b933e92bdd6899850b1ef1962981952c79da Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 30 Dec 2025 18:15:54 -0500 Subject: [PATCH 17/20] Cycling through other times of day. --- goalc/build_level/common/color_quantization.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goalc/build_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index fc0aec8aaea..f91c6b49f3c 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -298,7 +298,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) { From 248227ca0dec9e390997a51c91620409ef81998f Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 30 Dec 2025 20:13:41 -0500 Subject: [PATCH 18/20] Minor formatting changes. --- goalc/build_level/common/color_quantization.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/goalc/build_level/common/color_quantization.cpp b/goalc/build_level/common/color_quantization.cpp index f91c6b49f3c..a21b057fd68 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -501,11 +501,11 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, for(int time_of_day = 0; time_of_day < 8; ++time_of_day){ int color_offset = time_of_day * 4; - std::array time_of_day_color = {saturate_to_u8(color_totals[color_offset + 0] / n), + 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[0]; + 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)); } @@ -529,6 +529,7 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, Color input = in.at(i); 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) { @@ -541,6 +542,5 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, lg::error("Worst diff {} between {} {}", std::sqrt((float)worst_diff), worst_in.to_string_hex_byte(), worst_out.to_string_hex_byte()); } - return result; } From a9e9bab8646b1cd35ecda00294bb324564fbd5d8 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 31 Dec 2025 22:34:40 -0500 Subject: [PATCH 19/20] Cleaning up development .glb files. --- .../jak1/levels/test-zone/test-zone2.glb | Bin 12528 -> 8264 bytes .../levels/test-zone/test-zone2.morphed.glb | Bin 13460 -> 0 bytes .../jak1/levels/test-zone/test-zone2.new.glb | Bin 13212 -> 0 bytes .../jak1/levels/test-zone/test-zone2.old.glb | Bin 8264 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 custom_assets/jak1/levels/test-zone/test-zone2.morphed.glb delete mode 100644 custom_assets/jak1/levels/test-zone/test-zone2.new.glb delete mode 100644 custom_assets/jak1/levels/test-zone/test-zone2.old.glb diff --git a/custom_assets/jak1/levels/test-zone/test-zone2.glb b/custom_assets/jak1/levels/test-zone/test-zone2.glb index 22db4e5ddcf56b29bfe03c8fd83a97e2b387dd48..2df7f4d59537ba09ff5baa8b42fe6e3aefb196d1 100644 GIT binary patch delta 1654 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 F_iXI!-(XyycV!48ItTa zSS+A_ru>Nfpnf04v!dpvb=-16p8JJ|XE>uhJAeGQUqn&#_dyhW_q!xew(ZhVG^Eip$Ocu-O zdAkXbPhXoff4|ZC+|^ zp=S%|7uFPIX|uFI%++E%Tb_&eY^aLdWHwbrWlWltevMj5jP*xRXasy5yLp#(qD{ZCn zT&c<$Yzz5hMOviF<{47VQj_R>h@?@HvdHo@Evg_xjY4lvrrP7TMw~Jw#SEfjHiBqhqQrWi* zlGcNmu+TVYV--%>Pe)v zB+z^n{GnF1%F#GmP2VgX2?UO1*+IA2kOescaQY-gDbuNYB9Z-uBLCibi7(Erq5olNM6R@ zoIJYs_}<9__s~2zdHAn8_v0gU=i{%xyL)o-@UP#i_{dx(@pSfldPxOVm}A{D`&P{_SKRrNhRP2%w>T4On1Y+p6cUcY!TS$sR4{M$9v>HOl=d^VY_ z9{=zPSFqJ4PvX=0>lt2l*wV%LKfIR{youoHVu}~pliMV3yW7Iq#NU2>H^r;%G7f#C z@&|mcdaQ9)H?}s7*tq+e){g1+g&q3XkM7>Nf9GMt9vg4k@9JWL!fdb2>%yQm2P=c_ zIOM&rG%kP9lon>Zr`j9FN{O> z@=W}UqvsuT$bIkjT048c_&fWS?fri{n-||ZZSNg>8y^M-s^kq)%SFaKBUV7M1Jxpl(+7DC0|c&vAu!S*K^V zcbJ7XeXdPeOIl}rX*blfUhnv*+)t*^eW@2UZTt-B*=Qpde4xLLI^MEblYb*0lbWnYzv<40JJ z|7JdAu69qae{#de6+gZ32|f7f(%Zbkgh2Xk=~{(EuCMW+kj1U|ZO@j-bTE`SH)*h7gl9$H3=A$T1@A<;Ubv50Lt#2bduoQOC>0E`-!4U5E51b|Iu5={md> zeFVWr(J!M9qmQF6uznH!KKeuS$LKSxpGCioeiMBfy^r;MJTJeBK94@Z`bqR&^kwwx z=mV@DMEJ*H|Fg4!ocRhogj4U(6d%-U!-YrKhl{)qZi3vqaN1Kw*oH&q#@YkY9w$d^ zh}Zd!1)tY77x;}>0z~@BBF(U2d$K(Nz0I5%UfEmIOb-Y~cLP&kmbx40=7eeZhu0yH&n*KI^ zw&COnzYE_4KDu!6L3tZ4Ji$uQ_ZTJRt<5;_O+s7U!M{Jz5#uqtl zrH4BGAWmJ!+57m6(`gHtlRE=0+aWx$6}r<8b6^~fwOidHdA0drzd1f3rt3dg4SY_7 z93#?ReoP+l2$1@u2bduoQOC>0E`-!4U5E51b|Iu5={oG~`OS83PKWV0h1Z5tc4&$n z_1bXZ5%%FC?}M8l-!7c?lo7V!kh!t;fV9WS5gX!lzGJ~B`HbNPa1KYW9qJaT+m_hp zlVTk4->`+u$(W3f<`kIo5UPNpf%V!+vvoLQL0xuo?KA2suWiz5JLw;1MA8 zNe?hXIHHc1i(Lq*Pr452PwYZSJ<@e3bzjrp#?LmKJmGiYo4`jGEJCM+c>G$Ax>Y{a1Hv9AIR%E&feQOfADk7^SGlCOX5kM z!oP;luj{yY;LC954_|JqJp_=vB!|!s`_0jWn6Cd|Gw?YPa*RlO`7wFGBS7kt9$(^|yAV>JbRE*4*oBaKr1#-}0kv~_egFUf From d1abc2bf9de1962f244cbff991ed6879af6d1166 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 8 Jan 2026 13:49:11 -0500 Subject: [PATCH 20/20] Fixed compiler error, using clang formatting, removed assert. --- common/util/gltf_util.cpp | 98 ++++++++++--------- .../level_extractor/merc_replacement.cpp | 6 +- goalc/build_actor/common/MercExtract.cpp | 3 +- .../build_level/common/color_quantization.cpp | 70 ++++++------- .../build_level/common/gltf_mesh_extract.cpp | 6 +- 5 files changed, 98 insertions(+), 85 deletions(-) diff --git a/common/util/gltf_util.cpp b/common/util/gltf_util.cpp index 44d117d86b6..d8ef6d73d3f 100644 --- a/common/util/gltf_util.cpp +++ b/common/util/gltf_util.cpp @@ -1,7 +1,8 @@ #include "gltf_util.h" -#include "image_resize.h" #include "algorithm" +#include "image_resize.h" + #include "common/log/log.h" namespace gltf_util { @@ -190,8 +191,7 @@ std::vector> colors_from_attribute(const tinygltf::Model& mo 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 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; @@ -267,37 +267,40 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, new_vert.z = v_w.z() * 4096; } } - if (get_colors) - { - 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} - }}; + if (get_colors) { + 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) { + 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 { + } else { found_all = false; } } - if(!found_one) { - if(const auto color0_iter = attributes.find("COLOR_0"); color0_iter != attributes.end()) { + 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) { + } 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)); } @@ -306,37 +309,39 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, } } - if(found_one || color0.has_value()) { - if(found_all) { + if (found_one || color0.has_value()) { + if (found_all) { lg::info("{} had all times of day.", debug_name); - } - else if(found_one) { + } else if (found_one) { std::string log_string = ""; - for(size_t slot_index = 0; slot_index < times_of_day.size(); ++slot_index) { + 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()) { + 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 + } 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) ) { + 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) ) { + } 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; } } } 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") + 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; @@ -344,25 +349,25 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model, lg::warn("{} missing some times of day, using {}", debug_name, log_string); } - //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(); + // 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(); - assert(time_color.size() == vtx_colors.size()); 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) { + // 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. + ++color_iter; // Advance the iterator for this time of day. } } } @@ -847,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][4*palette + channel]; + colors.read(color_index, palette, channel) = + color_palette[color_index][4 * palette + channel]; } } } diff --git a/decompiler/level_extractor/merc_replacement.cpp b/decompiler/level_extractor/merc_replacement.cpp index 724d7724cb1..5cb02e0b196 100644 --- a/decompiler/level_extractor/merc_replacement.cpp +++ b/decompiler/level_extractor/merc_replacement.cpp @@ -50,7 +50,8 @@ void extract(tfrag3::MercModel& mdl, 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.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()); @@ -188,7 +189,8 @@ void extract(const std::string& name, 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.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_actor/common/MercExtract.cpp b/goalc/build_actor/common/MercExtract.cpp index 83fa764dc22..13af4bb435f 100644 --- a/goalc/build_actor/common/MercExtract.cpp +++ b/goalc/build_actor/common/MercExtract.cpp @@ -58,7 +58,8 @@ void extract(const std::string& 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.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 a21b057fd68..1f7c56c5354 100644 --- a/goalc/build_level/common/color_quantization.cpp +++ b/goalc/build_level/common/color_quantization.cpp @@ -3,9 +3,10 @@ #include #include #include +#include #include #include -#include + #include "common/log/log.h" #include "common/math/Vector.h" #include "common/util/Assert.h" @@ -15,12 +16,11 @@ namespace { 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) +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) + else if (sum > 0) return false; } return colorA[31] < colorB[31]; @@ -44,31 +44,31 @@ 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){ +std::tuple color_rgb(Color& color) { u32 r = 0; u32 g = 0; u32 b = 0; - for(int channel = 0;channel < 32;channel += 4){ + 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); + return std::make_tuple(r, g, b); } void insert(Node& root, Color color, u8 current_depth) { if (current_depth == 7) { const auto rgb = color_rgb(color); - root.r_sum += std::get<0,u32>(rgb); - root.g_sum += std::get<1,u32>(rgb); - root.b_sum += std::get<2,u32>(rgb); + 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++; @@ -176,8 +176,10 @@ void assign_colors(Node& root, std::vector& palette_out) { n.final_idx = idx++; 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}; + 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)); @@ -270,8 +272,8 @@ size_t pick_split_point(const std::vector& colors, int dim) { } int pick_split_dim_final_splits(const std::vector& colors) { - std::vector mins(32,255); - std::vector maxes(32,0); + std::vector mins(32, 255); + std::vector maxes(32, 0); for (const auto& color : colors) { for (int i = 0; i < 32; i++) { mins[i] = std::min(mins[i], (int)color[i]); @@ -381,7 +383,7 @@ 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() ); + out.erase(end_unique, out.end()); return out; } @@ -427,14 +429,15 @@ void get_splittable(KdNode* node, std::vector* out) { } /*! -* Just removes duplicate colors, which can work if there are only a few unique colors. -*/ + * 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); + 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); } @@ -444,8 +447,7 @@ QuantizedColors quantize_colors_dumb(const std::vector& in) { return result; } -QuantizedColors quantize_colors_kd_tree(const std::vector& in, - u32 target_depth) { +QuantizedColors quantize_colors_kd_tree(const std::vector& in, u32 target_depth) { Timer timer; // Build root node: KdNode root; @@ -482,7 +484,7 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, // Get final colors: auto cmp = &color_less_than; - std::map, u32, decltype(cmp)> color_value_to_color_idx(cmp); + std::map, u32, decltype(cmp)> color_value_to_color_idx(cmp); QuantizedColors result; for_each_child(&root, [&](KdNode* node) { if (node->colors.empty()) { @@ -490,27 +492,27 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, } const u32 slot = result.final_colors.size(); - math::Vector color_totals = math::Vector::zero(); + math::Vector color_totals = math::Vector::zero(); const u32 n = node->colors.size(); for (auto& color : node->colors) { color_value_to_color_idx[color] = slot; - for(int channel = 0; channel < 32; ++channel) + 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){ + 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))}; + 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)); } }); - for (auto& color : in) { result.vtx_to_color.push_back(color_value_to_color_idx.at(color)); @@ -527,7 +529,7 @@ QuantizedColors quantize_colors_kd_tree(const std::vector& in, for (size_t i = 0; i < result.vtx_to_color.size(); i++) { Color input = in.at(i); - for(int alpha_channel = 3; alpha_channel < 32; alpha_channel +=4) + 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)); diff --git a/goalc/build_level/common/gltf_mesh_extract.cpp b/goalc/build_level/common/gltf_mesh_extract.cpp index 2ca24aed507..e7b1892e54b 100644 --- a/goalc/build_level/common/gltf_mesh_extract.cpp +++ b/goalc/build_level/common/gltf_mesh_extract.cpp @@ -129,7 +129,8 @@ void extract(const Input& in, 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()); + 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()); auto& info = info_by_material[prim.material]; @@ -283,7 +284,8 @@ void extract(const Input& in, 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()); + all_vtx_colors.insert(all_vtx_colors.end(), verts.vtx_colors.begin(), + verts.vtx_colors.end()); ASSERT(all_vtx_colors.size() == out.vertices.size()); auto& info = info_by_material[prim.material];