timesamples pprint w.i.p.

This commit is contained in:
Syoyo Fujita
2025-10-15 12:14:10 +09:00
parent 9069b7014f
commit bbc01dfa50
13 changed files with 405 additions and 90 deletions

View File

@@ -183,9 +183,9 @@ class Buffer {
capacity_ = new_capacity;
}
uint8_t* data_;
size_t size_;
size_t capacity_;
uint8_t* data_{nullptr};
size_t size_{0};
size_t capacity_{0};
};
} // namespace tinyusdz

View File

@@ -546,20 +546,35 @@ add_array_sample_to_timesamples(value::TimeSamples *d, double time,
}
}
// TypedArray overload for POD types
template <typename T>
typename std::enable_if<is_pod_type<T>::value, bool>::type
//typename std::enable_if<is_pod_type<T>::value, bool>::type
bool
add_array_sample_to_timesamples(value::TimeSamples *d, double time,
const TypedArray<T> &arrval, std::string *err,
size_t expected_total_samples = 0) {
#if 0
if (d->is_using_pod()) {
TUSDZ_LOG_I("TypedArray: use pod");
return d->add_array_sample_pod<T>(time, arrval, err,
expected_total_samples);
} else {
TUSDZ_LOG_I("TypedArray: non-pod");
// Convert TypedArray to std::vector for non-POD path
std::vector<T> vec(arrval.data(), arrval.data() + arrval.size());
return d->add_sample(time, value::Value(vec), err);
}
#else
(void)expected_total_samples;
//TUSDZ_LOG_I("TypedArray: non-pod");
// TypedArray manages its own memory internally using a 64-bit packed pointer,
// which means memory is handled within the TypedArray implementation and users
// should not manually manage or free the underlying array.
// This is important here because passing the TypedArray directly avoids unnecessary
// copies and ensures that memory ownership and lifetime are correctly handled,
// preventing double-free or memory leaks. Maintainers should avoid adding manual
// memory management for TypedArray instances at this call site.
return d->add_typed_array_sample(time, arrval, err);
#endif
}
// Specialization for matrix(treat it as pod)
@@ -1405,12 +1420,14 @@ bool CrateReader::UnpackTimeSampleValue_FLOAT2(double t,
// Check deduplication cache for array
auto it = _dedup_float2_array.find(rep);
if (it != _dedup_float2_array.end()) {
TUSDZ_LOG_I("dedup float2 array\n");
//TUSDZ_LOG_I("dedup float2 array\n");
// Reuse cached array - shallow copy shares the underlying data
v = it->second;
v = MakeDedupTypedArray(it->second.get());
v.set_dedup(true);
// HACK
DCOUT("Reusing cached FLOAT2 array for ValueRep, size=" << v.size());
} else {
TUSDZ_LOG_I("read float2 array\n");
//TUSDZ_LOG_I("read float2 array\n");
// Read and cache array
if (!ReadFloat2ArrayTyped(&v)) {
PUSH_ERROR_AND_RETURN_TAG(kTag, "Failed to read vec2 array.");
@@ -1425,9 +1442,11 @@ bool CrateReader::UnpackTimeSampleValue_FLOAT2(double t,
}
if (it == _dedup_float2_array.end()) {
// Mark as dedup before caching so the original won't delete when it goes out of scope
// content of 'v' is stored as the first timesample value.
// We store v with duplicated flag on to prevent double-free.
// Also use move assignment to avoid calling copy assignemnt operator.
v.set_dedup(true);
_dedup_float2_array[rep] = v;
_dedup_float2_array.emplace(rep, std::move(v));
}
} else {

View File

@@ -153,9 +153,11 @@ CrateReader::~CrateReader() {
// Clean up float2_array cache
for (auto& pair : _dedup_float2_array) {
if (pair.second.get() != nullptr) {
delete pair.second.get();
}
// HACK
pair.second.clear();
//if (pair.second.get() != nullptr) {
// delete pair.second.get();
//}
}
// Clean up double_array cache

View File

@@ -4416,7 +4416,7 @@ bool ReconstructPrim<GeomMesh>(
}
}
TUSDZ_LOG_I("add prop: " << prop.first);
//TUSDZ_LOG_I("add prop: " << prop.first);
// generic
ADD_PROPERTY(table, prop, GeomMesh, mesh->props)
PARSE_PROPERTY_END_MAKE_WARN(table, prop)

View File

@@ -9,8 +9,10 @@
#include "value-types.hh"
#include "value-pprint.hh"
#include "pprinter.hh"
#include "logger.hh"
#include "timesamples.hh"
#include "stream-writer.hh"
#include "typed-array.hh"
namespace tinyusdz {
@@ -377,6 +379,60 @@ std::string print_texcoord3d(const uint8_t* data) {
return ss.str();
}
// TypedArray - stored as packed pointer (uint64_t)
// Attempt to reconstruct TypedArray and print its contents
template<typename T>
std::string try_print_typed_array(const uint8_t* packed_ptr_data) {
uint64_t packed_value;
std::memcpy(&packed_value, packed_ptr_data, sizeof(uint64_t));
// Extract pointer from packed value (lower 48 bits)
uint64_t ptr_bits = packed_value & 0x0000FFFFFFFFFFFFULL;
// Sign-extend from 48 bits to 64 bits for canonical address
if (ptr_bits & (1ULL << 47)) {
ptr_bits |= 0xFFFF000000000000ULL;
}
if (ptr_bits == 0) {
return ""; // Return empty to indicate failure
}
// Cast to TypedArrayImpl<T>*
auto* impl = reinterpret_cast<TypedArrayImpl<T>*>(ptr_bits);
// Create TypedArray with dedup flag to prevent deletion
TypedArray<T> typed_array(impl, true);
// Create a view to access the data
TypedArrayView<const T> view(typed_array);
if (view.size() == 0) {
return "[]";
}
std::stringstream ss;
ss << "[";
// Limit output to first 10 elements for readability
size_t max_elements = std::min(view.size(), size_t(10));
for (size_t i = 0; i < max_elements; ++i) {
if (i > 0) ss << ", ";
// In C++14, we can't use if constexpr, so just output directly
// The operator<< should work for all types we're likely to encounter
ss << view[i];
}
if (view.size() > max_elements) {
ss << ", ... (" << view.size() << " total)";
}
ss << "]";
return ss.str();
}
// Geometry types
std::string print_point3h(const uint8_t* data) {
value::point3h p;
@@ -461,6 +517,7 @@ std::string print_frame4d(const uint8_t* data) {
// StreamWriter versions of print functions
template<typename T>
void print_pod_value(StreamWriter& writer, const uint8_t* data) {
TUSDZ_LOG_I("pod_value\n");
T value;
std::memcpy(&value, data, sizeof(T));
writer << value;
@@ -510,8 +567,171 @@ void print_value_type(StreamWriter& writer, const uint8_t* data) {
writer.write(ss.str());
}
// TypedArray - stored as packed pointer (uint64_t)
// Attempt to reconstruct TypedArray and print its contents to StreamWriter
template<typename T>
bool try_print_typed_array_value(StreamWriter& writer, const uint8_t* packed_ptr_data) {
uint64_t packed_value;
std::memcpy(&packed_value, packed_ptr_data, sizeof(uint64_t));
// Extract pointer from packed value (lower 48 bits)
uint64_t ptr_bits = packed_value & 0x0000FFFFFFFFFFFFULL;
// Sign-extend from 48 bits to 64 bits for canonical address
if (ptr_bits & (1ULL << 47)) {
ptr_bits |= 0xFFFF000000000000ULL;
}
if (ptr_bits == 0) {
return false; // Return false to indicate failure
}
// Cast to TypedArrayImpl<T>*
auto* impl = reinterpret_cast<TypedArrayImpl<T>*>(ptr_bits);
// Create TypedArray with dedup flag to prevent deletion
TypedArray<T> typed_array(impl, true);
// Create a view to access the data
TypedArrayView<const T> view(typed_array);
if (view.size() == 0) {
writer.write("[]");
return true;
}
writer.write("[");
// Limit output to first 10 elements for readability
size_t max_elements = std::min(view.size(), size_t(10));
for (size_t i = 0; i < max_elements; ++i) {
if (i > 0) writer.write(", ");
// Write the value using operator<< via stringstream
std::stringstream ss;
ss << view[i];
writer.write(ss.str());
}
if (view.size() > max_elements) {
writer.write(", ... (");
writer.write(static_cast<int>(view.size()));
writer.write(" total)");
}
writer.write("]");
return true;
}
void print_typed_array_value(StreamWriter& writer, const uint8_t* data) {
// Try common types in order of likelihood
bool success = false;
// Try float array
success = try_print_typed_array_value<float>(writer, data);
if (success) return;
// Try double array
success = try_print_typed_array_value<double>(writer, data);
if (success) return;
// Try int array
success = try_print_typed_array_value<int>(writer, data);
if (success) return;
// Try float3 array
success = try_print_typed_array_value<value::float3>(writer, data);
if (success) return;
// Try float2 array
success = try_print_typed_array_value<value::float2>(writer, data);
if (success) return;
// Try double3 array
success = try_print_typed_array_value<value::double3>(writer, data);
if (success) return;
// If we can't determine the type, print a generic representation
uint64_t packed_value;
std::memcpy(&packed_value, data, sizeof(uint64_t));
uint64_t ptr_bits = packed_value & 0x0000FFFFFFFFFFFFULL;
if (ptr_bits & (1ULL << 47)) {
ptr_bits |= 0xFFFF000000000000ULL;
}
bool is_dedup = (packed_value & (1ULL << 63)) != 0;
if (ptr_bits == 0) {
writer.write("[]");
} else {
writer.write("[TypedArray@0x");
std::stringstream ss;
ss << std::hex << ptr_bits;
writer.write(ss.str());
if (is_dedup) {
writer.write(" (dedup)");
}
writer.write("]");
}
}
} // namespace
// TypedArray printing function - moved outside anonymous namespace to be accessible
std::string print_typed_array(const uint8_t* data) {
// Try common types in order of likelihood
std::string result;
// Try float array
result = try_print_typed_array<float>(data);
if (!result.empty()) return result;
// Try double array
result = try_print_typed_array<double>(data);
if (!result.empty()) return result;
// Try int array
result = try_print_typed_array<int>(data);
if (!result.empty()) return result;
// Try float3 array
result = try_print_typed_array<value::float3>(data);
if (!result.empty()) return result;
// Try float2 array
result = try_print_typed_array<value::float2>(data);
if (!result.empty()) return result;
// Try double3 array
result = try_print_typed_array<value::double3>(data);
if (!result.empty()) return result;
// If we can't determine the type, print a generic representation
uint64_t packed_value;
std::memcpy(&packed_value, data, sizeof(uint64_t));
uint64_t ptr_bits = packed_value & 0x0000FFFFFFFFFFFFULL;
if (ptr_bits & (1ULL << 47)) {
ptr_bits |= 0xFFFF000000000000ULL;
}
bool is_dedup = (packed_value & (1ULL << 63)) != 0;
std::stringstream ss;
if (ptr_bits == 0) {
ss << "[]";
} else {
ss << "[TypedArray@0x" << std::hex << ptr_bits;
if (is_dedup) {
ss << " (dedup)";
}
ss << "]";
}
return ss.str();
}
std::string pprint_pod_value_by_type(const uint8_t* data, uint32_t type_id) {
using namespace value;
@@ -656,6 +876,8 @@ std::string pprint_pod_value_by_type(const uint8_t* data, uint32_t type_id) {
return print_texcoord3f(data);
case TYPE_ID_TEXCOORD3D:
return print_texcoord3d(data);
case TYPE_ID_TYPED_ARRAY_TIMESAMPLE_VALUE:
return print_typed_array(data);
default:
return "[Unknown POD type: " + std::to_string(type_id) + "]";
}
@@ -875,6 +1097,9 @@ void pprint_pod_value_by_type(StreamWriter& writer, const uint8_t* data, uint32_
case TYPE_ID_TEXCOORD3D:
print_value_type<value::texcoord3d>(writer, data);
break;
case TYPE_ID_TYPED_ARRAY_TIMESAMPLE_VALUE:
print_typed_array_value(writer, data);
break;
default:
writer << "[Unknown POD type: " << type_id << "]";
break;
@@ -1025,6 +1250,10 @@ size_t get_pod_type_size(uint32_t type_id) {
return sizeof(value::texcoord3f);
case TYPE_ID_TEXCOORD3D:
return sizeof(value::texcoord3d);
case TYPE_ID_TYPED_TIMESAMPLE_VALUE:
return sizeof(uint64_t);
case TYPE_ID_TYPED_ARRAY_TIMESAMPLE_VALUE:
return sizeof(uint64_t);
default:
return 0; // Unknown type
}
@@ -1160,6 +1389,10 @@ void pprint_timesamples(StreamWriter& writer, const value::TimeSamples& samples,
const auto& blocked = pod_samples.get_blocked();
const auto& values = pod_samples.get_values();
TUSDZ_LOG_I("times.size " << times.size());
TUSDZ_LOG_I("blocked.size " << blocked.size());
TUSDZ_LOG_I("values.size " << values.size());
// Write samples - handle offset table if present
if (!pod_samples._offsets.empty()) {
// Using offset table - blocked values don't consume space
@@ -1185,6 +1418,7 @@ void pprint_timesamples(StreamWriter& writer, const value::TimeSamples& samples,
// Legacy: blocked values still counted in offset calculation
size_t value_offset = 0;
for (size_t i = 0; i < times.size(); ++i) {
TUSDZ_LOG_I("times[" << i << "] = " << times[i]);
writer.write(pprint::Indent(indent + 1));
writer.write(times[i]);
writer.write(": ");

View File

@@ -72,6 +72,14 @@ void pprint_pod_value_by_type(StreamWriter& writer,
///
size_t get_pod_type_size(uint32_t type_id);
///
/// Pretty print a TypedArray stored as a packed pointer
///
/// @param data Pointer to the packed TypedArray pointer (uint64_t)
/// @return String representation of the TypedArray
///
std::string print_typed_array(const uint8_t* data);
///
/// Pretty print non-POD TimeSamples with indentation support
///

View File

@@ -27,14 +27,14 @@ std::vector<std::pair<double, std::pair<value::Value, bool>>> PODTimeSamples::ge
// Get element size for the type
size_t element_size = 0;
if (!_is_array) {
if (!_is_stl_array && !_is_typed_array) {
element_size = get_element_size();
}
// Macro to handle each POD type
#define HANDLE_POD_TYPE(__type_id, __type) \
if (_type_id == __type_id) { \
if (_is_array) { \
if (_is_stl_array || _is_typed_array) { \
/* Array handling with offset table */ \
element_size = sizeof(__type) * _array_size; \
if (!_offsets.empty()) { \
@@ -120,7 +120,7 @@ std::vector<std::pair<double, std::pair<value::Value, bool>>> PODTimeSamples::ge
// Handle bool separately due to std::vector<bool> specialization
if (_type_id == value::TypeTraits<bool>::type_id()) {
if (_is_array) {
if (_is_stl_array || _is_typed_array) {
/* Bool array handling - special case due to vector<bool> */
element_size = _array_size; // 1 byte per bool
if (!_offsets.empty()) {
@@ -312,6 +312,14 @@ size_t PODTimeSamples::get_element_size() const {
#undef TYPE_SIZE_CASE
if (_type_id == value::TYPE_ID_TYPED_TIMESAMPLE_VALUE) {
return sizeof(uint64_t);
}
if (_type_id == value::TYPE_ID_TYPED_ARRAY_TIMESAMPLE_VALUE) {
return sizeof(uint64_t);
}
return 0; // Unknown type
}

View File

@@ -79,7 +79,8 @@ inline bool is_pod_type_id(uint32_t type_id) {
struct PODTimeSamples {
// Hot data (frequently accessed, cache-friendly layout)
uint32_t _type_id{0}; // TypeId from value-types.hh
bool _is_array{false}; // Whether the stored type is an array
bool _is_stl_array{false}; // Whether the stored type is a std::vector<T> array
bool _is_typed_array{false}; // Whether the stored type is TypedArray<T>
uint16_t _element_size{0}; // Cached element size (0 = not cached)
size_t _array_size{0}; // Number of elements per array (fixed for all samples)
mutable bool _dirty{false};
@@ -110,7 +111,8 @@ struct PODTimeSamples {
_values.clear();
_offsets.clear();
_type_id = 0;
_is_array = false;
_is_stl_array = false;
_is_typed_array = false;
_array_size = 0;
_element_size = 0;
_blocked_count = 0;
@@ -122,7 +124,8 @@ struct PODTimeSamples {
/// Move constructor
PODTimeSamples(PODTimeSamples&& other) noexcept
: _type_id(other._type_id),
_is_array(other._is_array),
_is_stl_array(other._is_stl_array),
_is_typed_array(other._is_typed_array),
_element_size(other._element_size),
_array_size(other._array_size),
_dirty(other._dirty),
@@ -135,7 +138,8 @@ struct PODTimeSamples {
_blocked_count(other._blocked_count) {
// Reset moved-from object to valid empty state
other._type_id = 0;
other._is_array = false;
other._is_stl_array = false;
other._is_typed_array = false;
other._element_size = 0;
other._array_size = 0;
other._dirty = false;
@@ -149,7 +153,8 @@ struct PODTimeSamples {
if (this != &other) {
// Move data from other
_type_id = other._type_id;
_is_array = other._is_array;
_is_stl_array = other._is_stl_array;
_is_typed_array = other._is_typed_array;
_element_size = other._element_size;
_array_size = other._array_size;
_dirty = other._dirty;
@@ -163,7 +168,8 @@ struct PODTimeSamples {
// Reset moved-from object to valid empty state
other._type_id = 0;
other._is_array = false;
other._is_stl_array = false;
other._is_typed_array = false;
other._element_size = 0;
other._array_size = 0;
other._dirty = false;
@@ -183,7 +189,7 @@ struct PODTimeSamples {
/// Initialize PODTimeSamples with type information and optional pre-allocation
/// @param type_id The TypeId from value-types.hh
/// @param is_array Whether storing array data
/// @param is_array Whether storing array data (std::vector-based)
/// @param element_size Size of each element in bytes
/// @param array_size Number of elements per array (for array data)
/// @param expected_samples Optional: expected number of samples to pre-allocate
@@ -195,7 +201,8 @@ struct PODTimeSamples {
}
_type_id = tid;
_is_array = is_array_type;
_is_stl_array = is_array_type;
_is_typed_array = false; // STL array init doesn't use TypedArray
_array_size = arr_size;
// Calculate element size if not provided
@@ -220,7 +227,7 @@ struct PODTimeSamples {
if (_element_size > 0) {
// Calculate total size based on whether it's array data or not
size_t value_reserve_size = 0;
if (_is_array && _array_size > 0) {
if ((_is_stl_array || _is_typed_array) && _array_size > 0) {
// For array data: sizeof(element) * n_samples * array_size
value_reserve_size = n * _element_size * _array_size;
} else {
@@ -230,7 +237,7 @@ struct PODTimeSamples {
}
_values.reserve(value_reserve_size);
}
if (_is_array || !_offsets.empty()) {
if (_is_stl_array || _is_typed_array || !_offsets.empty()) {
_offsets.reserve(n);
}
}
@@ -250,7 +257,7 @@ struct PODTimeSamples {
if (_element_size > 0) {
size_t value_bytes = 0;
if (_is_array && _array_size > 0) {
if ((_is_stl_array || _is_typed_array) && _array_size > 0) {
// Array data: sizeof(T) * expected_samples * array_size
value_bytes = expected_samples * _element_size * _array_size;
} else {
@@ -262,7 +269,7 @@ struct PODTimeSamples {
}
// Always reserve offsets for array data
if (_is_array || !_offsets.empty()) {
if (_is_stl_array || _is_typed_array || !_offsets.empty()) {
_offsets.reserve(expected_samples);
}
}
@@ -291,6 +298,12 @@ struct PODTimeSamples {
std::sort(indices.begin(), indices.end(),
[this](size_t a, size_t b) { return _times[a] < _times[b]; });
// HACK
for (size_t i = 0; i < indices.size(); ++i) {
TUSDZ_LOG_I("indices[" << i << "] = " << indices[i]);
TUSDZ_LOG_I("times[" << i << "] = " << _times[i]);
}
// Reorder arrays based on sorted indices
std::vector<double> sorted_times(_times.size());
Buffer<16> sorted_blocked;
@@ -303,6 +316,7 @@ struct PODTimeSamples {
sorted_times[i] = _times[indices[i]];
sorted_blocked[i] = _blocked[indices[i]];
sorted_offsets[i] = _offsets[indices[i]];
}
_times = std::move(sorted_times);
_blocked = std::move(sorted_blocked);
@@ -320,6 +334,8 @@ struct PODTimeSamples {
for (size_t i = 0; i < indices.size(); ++i) {
sorted_times[i] = _times[indices[i]];
sorted_blocked[i] = _blocked[indices[i]];
TUSDZ_LOG_I("sorted.times[" << i << "] = " << sorted_times[i]);
TUSDZ_LOG_I("sorted.blocked[" << i << "] = " << sorted_blocked[i]);
// Only copy value if not blocked
if (!_blocked[indices[i]]) {
@@ -387,7 +403,8 @@ public:
// This allows storing role types (normal3f) as their underlying type (float3)
if (_times.empty()) {
_type_id = value::TypeTraits<T>::underlying_type_id();
_is_array = false; // Single values are not arrays
_is_stl_array = false; // Single values are not arrays
_is_typed_array = false;
_element_size = sizeof(T); // Cache element size
// Pre-allocate if requested
@@ -413,7 +430,7 @@ public:
// For non-blocked values, append to values array
// If we're using offsets (arrays or when we have any blocked values), update offset table
if (_is_array || !_offsets.empty()) {
if (_is_stl_array || _is_typed_array || !_offsets.empty()) {
// Using offset table - need to maintain consistency
// If offsets table exists but is smaller than times, we need to populate missing offsets
if (_offsets.size() < _times.size() - 1) {
@@ -448,11 +465,12 @@ public:
// TypedArray internally stores a uint64_t packed pointer, so we can treat it as POD
uint64_t packed_value = typed_array.get_packed_value();
// Set type_id on first sample - use TYPE_ID_UINT64 for TypedArray storage
// Set type_id on first sample
// We store the packed pointer as a uint64_t
if (_times.empty()) {
_type_id = value::TYPE_ID_UINT64; // TypedArray stored as uint64_t packed pointer
_is_array = false;
_type_id = value::TypeTraits<T>::type_id();
_is_stl_array = false; // Not using std::vector
_is_typed_array = true; // Using TypedArray
_element_size = sizeof(uint64_t); // Always 8 bytes for packed pointer
// Pre-allocate if requested
@@ -461,7 +479,7 @@ public:
}
} else {
// Verify we're storing TypedArray data
if (_type_id != value::TYPE_ID_UINT64 || _element_size != sizeof(uint64_t)) {
if (_type_id != value::TypeTraits<T>::type_id() || _element_size != sizeof(uint64_t)) {
if (err) {
(*err) += "Type mismatch: PODTimeSamples is not configured for TypedArray storage.\n";
}
@@ -474,7 +492,7 @@ public:
_blocked.push_back(0); // false = 0
// Store the packed pointer value
if (_is_array || !_offsets.empty()) {
if (_is_stl_array || _is_typed_array || !_offsets.empty()) {
// Using offset table
if (_offsets.size() < _times.size() - 1) {
_offsets.resize(_times.size() - 1, SIZE_MAX);
@@ -512,7 +530,8 @@ public:
// Set type_id and array info on first sample - use underlying_type_id
if (_times.empty()) {
_type_id = value::TypeTraits<T>::underlying_type_id();
_is_array = true;
_is_stl_array = true; // Using std::vector-based array
_is_typed_array = false; // Not using TypedArray
_array_size = count;
_element_size = sizeof(T); // Cache element size
@@ -573,7 +592,8 @@ public:
// Set type_id and array info on first sample - use underlying_type_id
if (_times.empty()) {
_type_id = value::TypeTraits<T>::underlying_type_id();
_is_array = true;
_is_stl_array = true; // Using std::vector-based array
_is_typed_array = false; // Not using TypedArray
_array_size = count;
_element_size = sizeof(T); // Cache element size
@@ -640,7 +660,8 @@ public:
// Set type_id on first sample - use underlying_type_id
if (_times.empty()) {
_type_id = value::TypeTraits<T>::underlying_type_id();
_is_array = false; // Will be set properly if array samples are added
_is_stl_array = false; // Will be set properly if array samples are added
_is_typed_array = false;
_element_size = sizeof(T); // Cache element size
// Pre-allocate if requested (note: blocked samples don't use value storage)
@@ -668,7 +689,7 @@ public:
// For blocked values, we DON'T allocate any space in _values
// If this is the first blocked sample and we don't have offsets yet,
// we need to create the offset table and populate it with existing samples
if (_offsets.empty() && !_is_array && !_times.empty()) {
if (_offsets.empty() && !_is_stl_array && !_is_typed_array && !_times.empty()) {
// Transition to offset-based storage
// Build offset table for existing samples
size_t offset = 0;
@@ -684,7 +705,7 @@ public:
}
// Add offset marker for this blocked sample
if (_is_array || !_offsets.empty()) {
if (_is_stl_array || _is_typed_array || !_offsets.empty()) {
// Use SIZE_MAX as a marker for blocked values in offset table
_offsets.push_back(SIZE_MAX);
}
@@ -704,7 +725,8 @@ public:
size_t expected_total_samples = 0) {
// Initialize array info on first sample
if (_times.empty()) {
_is_array = true;
_is_stl_array = true; // Assume STL array for blocked array samples
_is_typed_array = false;
_array_size = count;
// type_id will be set when first non-blocked sample is added
@@ -715,7 +737,7 @@ public:
_blocked.reserve(expected_total_samples);
_offsets.reserve(expected_total_samples);
}
} else if (_is_array) {
} else if (_is_stl_array || _is_typed_array) {
// Verify array size consistency
if (_array_size != count) {
if (err) {
@@ -869,7 +891,7 @@ public:
}
// Check if this PODTimeSamples is storing TypedArray data
if (_type_id != value::TYPE_ID_UINT64 || _element_size != sizeof(uint64_t)) {
if (_type_id != value::TypeTraits<T>::type_id() || _element_size != sizeof(uint64_t)) {
return false; // Not TypedArray storage
}
@@ -979,7 +1001,7 @@ public:
}
// For TypedArray storage
if (_type_id == value::TYPE_ID_UINT64 && _element_size == sizeof(uint64_t)) {
if (_type_id == value::TypeTraits<T>::type_id() && _element_size == sizeof(uint64_t)) {
// Retrieve the TypedArray and create a view from it
TypedArray<T> typed_array;
bool blocked_value = false;
@@ -992,7 +1014,7 @@ public:
}
// For array data stored directly
if (_is_array && _array_size > 0) {
if ((_is_stl_array || _is_typed_array) && _array_size > 0) {
// Find the actual data offset
if (!_offsets.empty()) {
if (_offsets[idx] == SIZE_MAX) {
@@ -1153,6 +1175,18 @@ struct TimeSamples {
bool is_using_pod() const { return _use_pod; }
/// Check if storing std::vector-based array data
/// @return true if using POD storage with STL arrays, false otherwise
bool is_stl_array() const {
return _use_pod ? _pod_samples._is_stl_array : false;
}
/// Check if storing TypedArray data
/// @return true if using POD storage with TypedArray, false otherwise
bool is_typed_array() const {
return _use_pod ? _pod_samples._is_typed_array : false;
}
/// Get POD storage for direct manipulation (only valid when using POD storage)
PODTimeSamples* get_pod_storage() {
return _use_pod ? &_pod_samples : nullptr;
@@ -1395,6 +1429,9 @@ struct TimeSamples {
init(value::TypeTraits<T>::type_id());
}
TUSDZ_LOG_I("is dedup? " << value.is_dedup());
TUSDZ_LOG_I("_use_pod? " << _use_pod);
if (_use_pod) {
bool result = _pod_samples.add_array_sample<T>(t, value.data(), value.size(), err, expected_total_samples);
_dirty = true;
@@ -1478,10 +1515,10 @@ struct TimeSamples {
size_t expected_total_samples = 0) {
// Initialize for TypedArray storage
if (empty()) {
_type_id = value::TYPE_ID_UINT64; // TypedArray stored as uint64_t
_type_id = value::TypeTraits<T>::type_id();
_use_pod = true; // Always use POD storage for TypedArray
_pod_samples._type_id = value::TYPE_ID_UINT64;
} else if (_type_id != value::TYPE_ID_UINT64) {
_pod_samples._type_id = value::TypeTraits<T>::type_id();
} else if (_type_id != value::TypeTraits<T>::type_id()) {
if (err) {
(*err) += "Type mismatch: TimeSamples already initialized with different type.\n";
}
@@ -1509,7 +1546,7 @@ struct TimeSamples {
}
// Check if storing TypedArray data
if (_type_id != value::TYPE_ID_UINT64) {
if (_type_id != value::TypeTraits<T>::type_id()) {
return false;
}
@@ -1529,7 +1566,7 @@ struct TimeSamples {
}
// Check if storing TypedArray data
if (_type_id != value::TYPE_ID_UINT64) {
if (_type_id != value::TypeTraits<T>::type_id()) {
return false;
}

View File

@@ -146,7 +146,13 @@ class TypedArrayImpl {
}
// Destructor
~TypedArrayImpl() = default;
~TypedArrayImpl() {
if (_is_view) {
// no free
} else {
_storage.clear();
}
}
// Check if this is a view (non-owning)
bool is_view() const noexcept { return _is_view; }

View File

@@ -568,10 +568,6 @@ bool USDCReader::Impl::ReconstructGeomSubset(
return false;
}
#ifdef TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "add [" << prop_name << "] to generic attrs\n";
#endif
geom_subset->attribs[prop_name] = std::move(attr);
}
}
@@ -2367,17 +2363,17 @@ bool USDCReader::Impl::ReconstructPrimNode(int parent, int current, int level,
DCOUT(fmt::format("parent = {}, curent = {}, is_parent_variant = {}", parent, current, is_parent_variant));
#ifdef TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << pprint::Indent(uint32_t(level)) << "lv[" << level
<< "] node_index[" << current << "] " << node.GetLocalPath()
<< " ==\n";
std::cout << pprint::Indent(uint32_t(level)) << " childs = [";
for (size_t i = 0; i < node.GetChildren().size(); i++) {
std::cout << node.GetChildren()[i];
if (i != (node.GetChildren().size() - 1)) {
std::cout << ", ";
}
}
std::cout << "] (is_parent_variant = " << is_parent_variant << ")\n";
//std::cout << pprint::Indent(uint32_t(level)) << "lv[" << level
// << "] node_index[" << current << "] " << node.GetLocalPath()
// << " ==\n";
//std::cout << pprint::Indent(uint32_t(level)) << " childs = [";
//for (size_t i = 0; i < node.GetChildren().size(); i++) {
// std::cout << node.GetChildren()[i];
// if (i != (node.GetChildren().size() - 1)) {
// std::cout << ", ";
// }
//}
//std::cout << "] (is_parent_variant = " << is_parent_variant << ")\n";
#endif
if (!psmap.count(uint32_t(current))) {
@@ -2828,17 +2824,17 @@ bool USDCReader::Impl::ReconstructPrimSpecNode(int parent, int current, int leve
const crate::CrateReader::Node &node = (*_nodes)[size_t(current)];
#ifdef TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << pprint::Indent(uint32_t(level)) << "lv[" << level
<< "] node_index[" << current << "] " << node.GetLocalPath()
<< " ==\n";
std::cout << pprint::Indent(uint32_t(level)) << " childs = [";
for (size_t i = 0; i < node.GetChildren().size(); i++) {
std::cout << node.GetChildren()[i];
if (i != (node.GetChildren().size() - 1)) {
std::cout << ", ";
}
}
std::cout << "] (is_parent_variant = " << is_parent_variant << ")\n";
//std::cout << pprint::Indent(uint32_t(level)) << "lv[" << level
// << "] node_index[" << current << "] " << node.GetLocalPath()
// << " ==\n";
//std::cout << pprint::Indent(uint32_t(level)) << " childs = [";
//for (size_t i = 0; i < node.GetChildren().size(); i++) {
// std::cout << node.GetChildren()[i];
// if (i != (node.GetChildren().size() - 1)) {
// std::cout << ", ";
// }
//}
//std::cout << "] (is_parent_variant = " << is_parent_variant << ")\n";
#endif
if (!psmap.count(uint32_t(current))) {

View File

@@ -428,6 +428,10 @@ enum TypeId {
TYPE_ID_TIMESAMPLES,
TYPE_ID_VARIANT_SELECION_MAP,
// tinyusdz specific.
TYPE_ID_TYPED_TIMESAMPLE_VALUE,
TYPE_ID_TYPED_ARRAY_TIMESAMPLE_VALUE,
// Types in crate-format.hh
TYPE_ID_CRATE_BEGIN = 256,
TYPE_ID_CRATE_VALUE,
@@ -527,6 +531,7 @@ enum TypeId {
TYPE_ID_ALL = (TYPE_ID_TERMINATOR_BIT - 1) // terminator.
};
static_assert(TYPE_ID_TYPED_ARRAY_TIMESAMPLE_VALUE < 256, "internal error.");
static_assert(TYPE_ID_API_END <= 65535, "Non user-defined TYPE_ID must be less than 16bit");

View File

@@ -10,18 +10,18 @@ def Xform "muda"
192: 1440,
}
color3f[] value.timeSamples = {
0: [(1.0, 2.0, 4.0)],
1: [(1.0, 2.0, 4.0)],
2: [(1.0, 2.0, 4.0)],
3: [(1.0, 2.0, 4.0)],
4: [(1.0, 2.0, 4.0)],
5: [(1.0, 2.0, 4.0)],
6: [(1.0, 2.0, 4.0)],
7: [(1.0, 2.0, 4.0)],
8: [(1.0, 2.0, 4.0)],
9: [(1.0, 2.0, 4.0)],
10: [(1.0, 2.0, 4.0)],
texCoord2f[] primvars:uv.timeSamples = {
0: [(1.0, 2.0)],
1: [(1.0, 2.0)],
2: [(1.0, 2.0)],
3: [(1.0, 2.0)],
4: [(1.0, 2.0)],
5: [(1.0, 2.0)],
6: [(1.0, 2.0)],
7: [(1.0, 2.0)],
8: [(1.0, 2.0)],
9: [(1.0, 2.0)],
10: [(1.0, 2.0)],
}
uniform token[] xformOpOrder = ["xformOp:rotateZ:tilt", "xformOp:rotateZ:spin"]

Binary file not shown.