mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
timesamples pprint w.i.p.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(": ");
|
||||
|
||||
@@ -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
|
||||
///
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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))) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
BIN
tests/usdc/timesamples-array-dedup-001.usdc
Normal file
BIN
tests/usdc/timesamples-array-dedup-001.usdc
Normal file
Binary file not shown.
Reference in New Issue
Block a user