Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 142 additions & 45 deletions common/util/gltf_util.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "gltf_util.h"

#include "algorithm"
#include "image_resize.h"

#include "common/log/log.h"
Expand Down Expand Up @@ -186,6 +187,46 @@ std::vector<JointsAndWeights> extract_and_flatten_joints_and_weights(
return ret;
}

std::vector<math::Vector<u8, 4>> 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<math::Vector<u8, 4>> 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.
*/
Expand All @@ -196,7 +237,7 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model,
bool get_normals,
const std::string& debug_name) {
std::vector<tfrag3::PreloadedVertex> result;
std::vector<math::Vector<u8, 4>> vtx_colors;
std::vector<math::Vector<u8, 32>> vtx_colors;

{
const auto& position_attrib = attributes.find("POSITION");
Expand Down Expand Up @@ -226,54 +267,109 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model,
new_vert.z = v_w.z() * 4096;
}
}

if (get_colors) {
const auto& color_attrib = attributes.find("COLOR_0");
if (color_attrib == attributes.end()) {
lg::error("Mesh {} didn't have any colors, using white", debug_name);
for (size_t i = 0; i < result.size(); i++) {
vtx_colors.emplace_back(0x80, 0x80, 0x80, 0xff);
std::array<std::pair<std::string, std::optional<std::vector<math::Vector<u8, 4>>>>, 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<std::vector<math::Vector<u8, 4>>> color0 = std::nullopt;
vtx_colors.resize(result.size());
bool found_one = false;
bool found_all = true;

for (auto& slot : times_of_day) {
if (const auto attr_val = attributes.find(slot.first); attr_val != attributes.end()) {
slot.second = colors_from_attribute(model, attr_val->second);
found_one = true;
} else {
found_all = false;
}
} else {
const auto attrib_accessor = model.accessors[color_attrib->second];
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const auto data_ptr =
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
const auto count = attrib_accessor.count;
std::vector<math::Vector<u8, 4>> colors;

switch (attrib_accessor.type) {
case TINYGLTF_TYPE_VEC4:
switch (attrib_accessor.componentType) {
case TINYGLTF_COMPONENT_TYPE_FLOAT:
colors = extract_color_from_vec4_float(data_ptr, count, byte_stride);
break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride);
break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
colors = extract_color_from_vec4_u8(data_ptr, count, byte_stride);
break;
default:
lg::die("Unknown type for COLOR_0: {}", attrib_accessor.componentType);
}

if (!found_one) {
if (const auto color0_iter = attributes.find("COLOR_0"); color0_iter != attributes.end()) {
color0 = colors_from_attribute(model, color0_iter->second);
lg::warn("{} had colors but no times of day, using COLOR_0.", debug_name);
} else {
const u32 WHITE_COLOR =
0xFF808080; // Because of little-endianness, FF is at the largest address in memory.
for (auto& vtx_color : vtx_colors) {
// Write white into the color slot for all times of day.
for (u8 byte_offset = 0; byte_offset < 32; byte_offset += 4) {
u8* target_ptr = vtx_color.data() + byte_offset;
std::memcpy(target_ptr, &WHITE_COLOR, sizeof(u32));
}
break;
case TINYGLTF_TYPE_VEC3:
switch (attrib_accessor.componentType) {
case TINYGLTF_COMPONENT_TYPE_FLOAT:
colors = extract_color_from_vec3_float(data_ptr, count, byte_stride);
break;
default:
lg::die("unkonwn component type for vec3 color {}", attrib_accessor.componentType);
}
lg::error("{} didn't have any colors, using white.", debug_name);
}
}

if (found_one || color0.has_value()) {
if (found_all) {
lg::info("{} had all times of day.", debug_name);
} else if (found_one) {
std::string log_string = "";
for (size_t slot_index = 0; slot_index < times_of_day.size(); ++slot_index) {
auto& slot = times_of_day[slot_index];
std::string time_name = slot.first;
std::string value_name;
if (slot.second.has_value()) {
value_name = slot.first;
} else { // If this time_of_day doesn't have a color, use the closest time_of_day with a
// color.
for (int i = 1; !slot.second.has_value();
++i) { // Guaranteed to end in 4 iterations or less
int neg_index = (slot_index - i + 8) % 8;
int pos_index = (slot_index + i + 8) % 8;

if (const auto& neg_slot = times_of_day[neg_index];
attributes.contains(neg_slot.first)) {
slot.second = neg_slot.second.value();
value_name = neg_slot.first;
} else if (const auto& pos_slot = times_of_day[pos_index];
attributes.contains(pos_slot.first)) {
slot.second = pos_slot.second.value();
value_name = pos_slot.first;
}
}
}
break;
default:
lg::die("unknown attribute type for color {}", attrib_accessor.type);
time_name = time_name.substr(1);
std::transform(time_name.begin(), time_name.end(), time_name.begin(),
[](unsigned char c) { return std::tolower(c); });
if (time_name == "greensun")
time_name = "green sun";
std::string mapping = time_name + ":" + value_name;
log_string += log_string.empty() ? mapping : ", " + mapping;
}
lg::warn("{} missing some times of day, using {}", debug_name, log_string);
}

vtx_colors.insert(vtx_colors.end(), colors.begin(), colors.end());
// Create iterators to colors for each time of day.
std::array<std::vector<math::Vector<u8, 4>>::const_iterator, 8> iters;
for (int time = 0; time < 8; ++time) {
const std::vector<math::Vector<u8, 4>>& time_color = times_of_day[time].second.has_value()
? times_of_day[time].second.value()
: color0.value();

iters[time] = time_color.begin();
}

// Write the color for each time of day into vtx_colors.
for (auto& vtx_color : vtx_colors) {
for (int slot_index = 0; slot_index < 8; ++slot_index) {
u8* target_ptr = vtx_color.data() + (4 * slot_index);
auto& color_iter = iters[slot_index];
const u8* source_ptr = color_iter->data();
std::memcpy(target_ptr, source_ptr, sizeof(u32));

++color_iter; // Advance the iterator for this time of day.
}
}
}
}

Expand Down Expand Up @@ -756,14 +852,15 @@ std::size_t TieFullVertex::hash::operator()(const TieFullVertex& x) const {
return tfrag3::PackedTieVertices::Vertex::hash()(x.vertex) ^ std::hash<u16>()(x.color_index);
}

tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>& color_palette) {
tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 32>>& 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];
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions common/util/gltf_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ std::vector<JointsAndWeights> extract_and_flatten_joints_and_weights(

struct ExtractedVertices {
std::vector<tfrag3::PreloadedVertex> vtx;
std::vector<math::Vector<u8, 4>> vtx_colors;
std::vector<math::Vector<u8, 32>> vtx_colors;
std::vector<math::Vector3f> normals;
};

Expand Down Expand Up @@ -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<math::Vector<u8, 4>>& color_palette);
tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 32>>& color_palette);

struct MercExtractData {
TexturePool tex_pool;
std::vector<u32> new_indices;
std::vector<tfrag3::PreloadedVertex> new_vertices;
std::vector<math::Vector<u8, 4>> new_colors;
std::vector<math::Vector<u8, 32>> new_colors;
std::vector<math::Vector3f> normals;
std::vector<JointsAndWeights> joints_and_weights;
tfrag3::MercModel new_model;
Expand Down
3 changes: 3 additions & 0 deletions decompiler/level_extractor/merc_replacement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ void extract(tfrag3::MercModel& mdl,
auto verts =
gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name);
out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end());

out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(),
verts.vtx_colors.end());

out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
ASSERT(out.new_colors.size() == out.new_vertices.size());

Expand Down Expand Up @@ -186,6 +188,7 @@ void extract(const std::string& name,
auto verts =
gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name);
out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end());

out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(),
verts.vtx_colors.end());
out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
Expand Down
3 changes: 3 additions & 0 deletions goalc/build_actor/common/MercExtract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ void extract(const std::string& name,
// extract vertices
auto verts =
gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name);

out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end());

out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(),
verts.vtx_colors.end());

out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
ASSERT(out.new_colors.size() == out.new_vertices.size());

Expand Down
Loading