cocos-engine-external/sources/acl/compression/impl/track_stream.h

361 lines
13 KiB
C++

#pragma once
////////////////////////////////////////////////////////////////////////////////
// The MIT License (MIT)
//
// Copyright (c) 2017 Nicholas Frechette & Animation Compression Library contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#include "acl/core/iallocator.h"
#include "acl/core/impl/compiler_utils.h"
#include "acl/core/error.h"
#include "acl/core/track_formats.h"
#include "acl/core/track_types.h"
#include "acl/core/utils.h"
#include "acl/core/variable_bit_rates.h"
#include "acl/math/quat_packing.h"
#include "acl/math/vector4_packing.h"
#include <rtm/quatf.h>
#include <rtm/vector4f.h>
#include <cstdint>
ACL_IMPL_FILE_PRAGMA_PUSH
namespace acl
{
namespace acl_impl
{
class TrackStream
{
public:
uint8_t* get_raw_sample_ptr(uint32_t sample_index)
{
ACL_ASSERT(sample_index < m_num_samples, "Invalid sample index. %u >= %u", sample_index, m_num_samples);
uint32_t offset = sample_index * m_sample_size;
return m_samples + offset;
}
const uint8_t* get_raw_sample_ptr(uint32_t sample_index) const
{
ACL_ASSERT(sample_index < m_num_samples, "Invalid sample index. %u >= %u", sample_index, m_num_samples);
uint32_t offset = sample_index * m_sample_size;
return m_samples + offset;
}
template<typename SampleType>
SampleType RTM_SIMD_CALL get_raw_sample(uint32_t sample_index) const
{
const uint8_t* ptr = get_raw_sample_ptr(sample_index);
return *safe_ptr_cast<const SampleType>(ptr);
}
#if defined(RTM_NO_INTRINSICS)
template<typename SampleType>
void RTM_SIMD_CALL set_raw_sample(uint32_t sample_index, const SampleType& sample)
#else
template<typename SampleType>
void RTM_SIMD_CALL set_raw_sample(uint32_t sample_index, SampleType sample)
#endif
{
ACL_ASSERT(m_sample_size == sizeof(SampleType), "Unexpected sample size. %u != %zu", m_sample_size, sizeof(SampleType));
uint8_t* ptr = get_raw_sample_ptr(sample_index);
*safe_ptr_cast<SampleType>(ptr) = sample;
}
uint32_t get_num_samples() const { return m_num_samples; }
uint32_t get_sample_size() const { return m_sample_size; }
float get_sample_rate() const { return m_sample_rate; }
animation_track_type8 get_track_type() const { return m_type; }
uint8_t get_bit_rate() const { return m_bit_rate; }
bool is_bit_rate_variable() const { return m_bit_rate != k_invalid_bit_rate; }
float get_duration() const { return calculate_duration(m_num_samples, m_sample_rate); }
uint32_t get_packed_sample_size() const
{
if (m_type == animation_track_type8::rotation)
return get_packed_rotation_size(m_format.rotation);
else
return get_packed_vector_size(m_format.vector);
}
protected:
TrackStream(animation_track_type8 type, track_format8 format) noexcept : m_allocator(nullptr), m_samples(nullptr), m_num_samples(0), m_sample_size(0), m_sample_rate(0.0F), m_type(type), m_format(format), m_bit_rate(0) {}
TrackStream(iallocator& allocator, uint32_t num_samples, uint32_t sample_size, float sample_rate, animation_track_type8 type, track_format8 format, uint8_t bit_rate)
: m_allocator(&allocator)
, m_samples(reinterpret_cast<uint8_t*>(allocator.allocate(sample_size * num_samples + k_padding, 16)))
, m_num_samples(num_samples)
, m_sample_size(sample_size)
, m_sample_rate(sample_rate)
, m_type(type)
, m_format(format)
, m_bit_rate(bit_rate)
{}
TrackStream(const TrackStream&) = delete;
TrackStream(TrackStream&& other) noexcept
: m_allocator(other.m_allocator)
, m_samples(other.m_samples)
, m_num_samples(other.m_num_samples)
, m_sample_size(other.m_sample_size)
, m_sample_rate(other.m_sample_rate)
, m_type(other.m_type)
, m_format(other.m_format)
, m_bit_rate(other.m_bit_rate)
{
new(&other) TrackStream(other.m_type, other.m_format);
}
~TrackStream()
{
if (m_allocator != nullptr && m_num_samples != 0)
m_allocator->deallocate(m_samples, m_sample_size * m_num_samples + k_padding);
}
TrackStream& operator=(const TrackStream&) = delete;
TrackStream& operator=(TrackStream&& rhs) noexcept
{
std::swap(m_allocator, rhs.m_allocator);
std::swap(m_samples, rhs.m_samples);
std::swap(m_num_samples, rhs.m_num_samples);
std::swap(m_sample_size, rhs.m_sample_size);
std::swap(m_sample_rate, rhs.m_sample_rate);
std::swap(m_type, rhs.m_type);
std::swap(m_format, rhs.m_format);
std::swap(m_bit_rate, rhs.m_bit_rate);
return *this;
}
void duplicate(TrackStream& copy) const
{
ACL_ASSERT(copy.m_type == m_type, "Attempting to duplicate streams with incompatible types!");
if (m_allocator != nullptr)
{
copy.m_allocator = m_allocator;
copy.m_samples = reinterpret_cast<uint8_t*>(m_allocator->allocate(m_sample_size * m_num_samples + k_padding, 16));
copy.m_num_samples = m_num_samples;
copy.m_sample_size = m_sample_size;
copy.m_sample_rate = m_sample_rate;
copy.m_format = m_format;
copy.m_bit_rate = m_bit_rate;
std::memcpy(copy.m_samples, m_samples, (size_t)m_sample_size * m_num_samples);
}
}
// In order to guarantee the safety of unaligned SIMD loads of every byte, we add some padding
static constexpr uint32_t k_padding = 15;
iallocator* m_allocator;
uint8_t* m_samples;
uint32_t m_num_samples;
uint32_t m_sample_size;
float m_sample_rate;
animation_track_type8 m_type;
track_format8 m_format;
uint8_t m_bit_rate;
};
class RotationTrackStream final : public TrackStream
{
public:
RotationTrackStream() noexcept : TrackStream(animation_track_type8::rotation, track_format8(rotation_format8::quatf_full)) {}
RotationTrackStream(iallocator& allocator, uint32_t num_samples, uint32_t sample_size, float sample_rate, rotation_format8 format, uint8_t bit_rate = k_invalid_bit_rate)
: TrackStream(allocator, num_samples, sample_size, sample_rate, animation_track_type8::rotation, track_format8(format), bit_rate)
{}
RotationTrackStream(const RotationTrackStream&) = delete;
RotationTrackStream(RotationTrackStream&& other) noexcept
: TrackStream(static_cast<TrackStream&&>(other))
{}
~RotationTrackStream() = default;
RotationTrackStream& operator=(const RotationTrackStream&) = delete;
RotationTrackStream& operator=(RotationTrackStream&& rhs) noexcept
{
TrackStream::operator=(static_cast<TrackStream&&>(rhs));
return *this;
}
RotationTrackStream duplicate() const
{
RotationTrackStream copy;
TrackStream::duplicate(copy);
return copy;
}
rotation_format8 get_rotation_format() const { return m_format.rotation; }
};
class TranslationTrackStream final : public TrackStream
{
public:
TranslationTrackStream() noexcept : TrackStream(animation_track_type8::translation, track_format8(vector_format8::vector3f_full)) {}
TranslationTrackStream(iallocator& allocator, uint32_t num_samples, uint32_t sample_size, float sample_rate, vector_format8 format, uint8_t bit_rate = k_invalid_bit_rate)
: TrackStream(allocator, num_samples, sample_size, sample_rate, animation_track_type8::translation, track_format8(format), bit_rate)
{}
TranslationTrackStream(const TranslationTrackStream&) = delete;
TranslationTrackStream(TranslationTrackStream&& other) noexcept
: TrackStream(static_cast<TrackStream&&>(other))
{}
~TranslationTrackStream() = default;
TranslationTrackStream& operator=(const TranslationTrackStream&) = delete;
TranslationTrackStream& operator=(TranslationTrackStream&& rhs) noexcept
{
TrackStream::operator=(static_cast<TrackStream&&>(rhs));
return *this;
}
TranslationTrackStream duplicate() const
{
TranslationTrackStream copy;
TrackStream::duplicate(copy);
return copy;
}
vector_format8 get_vector_format() const { return m_format.vector; }
};
class ScaleTrackStream final : public TrackStream
{
public:
ScaleTrackStream() noexcept : TrackStream(animation_track_type8::scale, track_format8(vector_format8::vector3f_full)) {}
ScaleTrackStream(iallocator& allocator, uint32_t num_samples, uint32_t sample_size, float sample_rate, vector_format8 format, uint8_t bit_rate = k_invalid_bit_rate)
: TrackStream(allocator, num_samples, sample_size, sample_rate, animation_track_type8::scale, track_format8(format), bit_rate)
{}
ScaleTrackStream(const ScaleTrackStream&) = delete;
ScaleTrackStream(ScaleTrackStream&& other) noexcept
: TrackStream(static_cast<TrackStream&&>(other))
{}
~ScaleTrackStream() = default;
ScaleTrackStream& operator=(const ScaleTrackStream&) = delete;
ScaleTrackStream& operator=(ScaleTrackStream&& rhs) noexcept
{
TrackStream::operator=(static_cast<TrackStream&&>(rhs));
return *this;
}
ScaleTrackStream duplicate() const
{
ScaleTrackStream copy;
TrackStream::duplicate(copy);
return copy;
}
vector_format8 get_vector_format() const { return m_format.vector; }
};
// For a rotation track, the extent only tells us if the track is constant or not
// since the min/max we maintain aren't valid rotations.
// Similarly, the center isn't a valid rotation and is meaningless.
class TrackStreamRange
{
public:
static TrackStreamRange RTM_SIMD_CALL from_min_max(rtm::vector4f_arg0 min, rtm::vector4f_arg1 max)
{
return TrackStreamRange(min, rtm::vector_sub(max, min));
}
static TrackStreamRange RTM_SIMD_CALL from_min_extent(rtm::vector4f_arg0 min, rtm::vector4f_arg1 extent)
{
return TrackStreamRange(min, extent);
}
TrackStreamRange()
: m_min(rtm::vector_zero())
, m_extent(rtm::vector_zero())
{}
rtm::vector4f RTM_SIMD_CALL get_min() const { return m_min; }
rtm::vector4f RTM_SIMD_CALL get_max() const { return rtm::vector_add(m_min, m_extent); }
rtm::vector4f RTM_SIMD_CALL get_center() const { return rtm::vector_add(m_min, rtm::vector_mul(m_extent, 0.5F)); }
rtm::vector4f RTM_SIMD_CALL get_extent() const { return m_extent; }
bool is_constant(float threshold) const { return rtm::vector_all_less_than(rtm::vector_abs(m_extent), rtm::vector_set(threshold)); }
private:
TrackStreamRange(rtm::vector4f_arg0 min, rtm::vector4f_arg1 extent)
: m_min(min)
, m_extent(extent)
{}
rtm::vector4f m_min;
rtm::vector4f m_extent;
};
struct BoneRanges
{
TrackStreamRange rotation;
TrackStreamRange translation;
TrackStreamRange scale;
};
struct SegmentContext;
struct BoneStreams
{
SegmentContext* segment;
uint32_t bone_index;
uint32_t parent_bone_index;
uint32_t output_index;
RotationTrackStream rotations;
TranslationTrackStream translations;
ScaleTrackStream scales;
bool is_rotation_constant;
bool is_rotation_default;
bool is_translation_constant;
bool is_translation_default;
bool is_scale_constant;
bool is_scale_default;
bool is_stripped_from_output() const { return output_index == k_invalid_track_index; }
BoneStreams duplicate() const
{
BoneStreams copy;
copy.segment = segment;
copy.bone_index = bone_index;
copy.parent_bone_index = parent_bone_index;
copy.output_index = output_index;
copy.rotations = rotations.duplicate();
copy.translations = translations.duplicate();
copy.scales = scales.duplicate();
copy.is_rotation_constant = is_rotation_constant;
copy.is_rotation_default = is_rotation_default;
copy.is_translation_constant = is_translation_constant;
copy.is_translation_default = is_translation_default;
copy.is_scale_constant = is_scale_constant;
copy.is_scale_default = is_scale_default;
return copy;
}
};
}
}
ACL_IMPL_FILE_PRAGMA_POP