cocos-engine-external/sources/acl/compression/track.h

360 lines
16 KiB
C++

#pragma once
////////////////////////////////////////////////////////////////////////////////
// The MIT License (MIT)
//
// Copyright (c) 2019 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/impl/compiler_utils.h"
#include "acl/core/iallocator.h"
#include "acl/core/string.h"
#include "acl/core/track_desc.h"
#include "acl/core/track_traits.h"
#include "acl/core/track_types.h"
#include <cstdint>
ACL_IMPL_FILE_PRAGMA_PUSH
#if defined(ACL_COMPILER_MSVC)
#pragma warning(push)
// warning C4582: 'union': constructor is not implicitly called (/Wall)
// This is fine because a track is empty until it is constructed with a valid description.
// Afterwards, access is typesafe.
#pragma warning(disable : 4582)
#endif
namespace acl
{
//////////////////////////////////////////////////////////////////////////
// An untyped track of data. A track is a time series of values sampled
// uniformly over time at a specific sample rate. Tracks can either own
// their memory or reference an external buffer.
// For convenience, this type can be cast with the `track_cast(..)` family
// of functions. Each track type has the same size as every track description
// is contained within a union.
//////////////////////////////////////////////////////////////////////////
class track
{
public:
//////////////////////////////////////////////////////////////////////////
// Creates an empty, untyped track.
track() noexcept;
//////////////////////////////////////////////////////////////////////////
// Move constructor for a track.
track(track&& other) noexcept;
//////////////////////////////////////////////////////////////////////////
// Destroys the track. If it owns the memory referenced, it will be freed.
~track();
//////////////////////////////////////////////////////////////////////////
// Move assignment for a track.
track& operator=(track&& other) noexcept;
//////////////////////////////////////////////////////////////////////////
// Returns a pointer to an untyped sample at the specified index.
void* operator[](uint32_t index);
//////////////////////////////////////////////////////////////////////////
// Returns a pointer to an untyped sample at the specified index.
const void* operator[](uint32_t index) const;
//////////////////////////////////////////////////////////////////////////
// Returns true if the track owns its memory, false otherwise.
bool is_owner() const { return m_allocator != nullptr; }
//////////////////////////////////////////////////////////////////////////
// Returns true if the track owns its memory, false otherwise.
bool is_ref() const { return m_allocator == nullptr; }
//////////////////////////////////////////////////////////////////////////
// Returns true if the track doesn't contain any data, false otherwise.
bool is_empty() const { return m_num_samples == 0; }
//////////////////////////////////////////////////////////////////////////
// Returns a pointer to the allocator instance or nullptr if there is none present.
iallocator* get_allocator() const { return m_allocator; }
//////////////////////////////////////////////////////////////////////////
// Returns the number of samples contained within the track.
uint32_t get_num_samples() const { return m_num_samples; }
//////////////////////////////////////////////////////////////////////////
// Returns the stride in bytes in between samples as laid out in memory.
// This is always sizeof(sample_type) unless the memory isn't owned internally.
uint32_t get_stride() const { return m_stride; }
//////////////////////////////////////////////////////////////////////////
// Returns the track type.
track_type8 get_type() const { return m_type; }
//////////////////////////////////////////////////////////////////////////
// Returns the track category.
track_category8 get_category() const { return m_category; }
//////////////////////////////////////////////////////////////////////////
// Returns the size in bytes of each track sample.
uint32_t get_sample_size() const { return m_sample_size; }
//////////////////////////////////////////////////////////////////////////
// Returns the track sample rate.
// A track has its sampled uniformly distributed in time at a fixed rate (e.g. 30 samples per second).
float get_sample_rate() const { return m_sample_rate; }
//////////////////////////////////////////////////////////////////////////
// Returns the track name.
const string& get_name() const { return m_name; }
//////////////////////////////////////////////////////////////////////////
// Sets the track name.
void set_name(const string& name) { m_name = name.get_copy(); }
//////////////////////////////////////////////////////////////////////////
// Returns the track output index.
// When compressing, it is often desirable to strip or re-order the tracks we output.
// This can be used to sort by LOD or to strip stale tracks. Tracks with an invalid
// track index are stripped in the output.
uint32_t get_output_index() const;
//////////////////////////////////////////////////////////////////////////
// Returns the track description.
template<typename desc_type>
desc_type& get_description();
//////////////////////////////////////////////////////////////////////////
// Returns the track description.
template<typename desc_type>
const desc_type& get_description() const;
//////////////////////////////////////////////////////////////////////////
// Returns a copy of the track where the memory will be owned by the copy.
track get_copy(iallocator& allocator) const;
//////////////////////////////////////////////////////////////////////////
// Returns a reference to the track where the memory isn't owned.
track get_ref() const;
//////////////////////////////////////////////////////////////////////////
// Returns whether a track is valid or not.
// A track is valid if:
// - It is empty
// - It has a positive and finite sample rate
// - A valid description
error_result is_valid() const;
protected:
//////////////////////////////////////////////////////////////////////////
// We prohibit copying, use get_copy() and get_ref() instead.
track(const track&) = delete;
track& operator=(const track&) = delete;
//////////////////////////////////////////////////////////////////////////
// Internal constructor.
// Creates an empty, untyped track.
track(track_type8 type, track_category8 category) noexcept;
//////////////////////////////////////////////////////////////////////////
// Internal constructor.
track(iallocator* allocator, uint8_t* data, uint32_t num_samples, uint32_t stride, size_t data_size, float sample_rate, track_type8 type, track_category8 category, uint8_t sample_size) noexcept;
//////////////////////////////////////////////////////////////////////////
// Internal helper.
void get_copy_impl(iallocator& allocator, track& out_track) const;
//////////////////////////////////////////////////////////////////////////
// Internal helper.
void get_ref_impl(track& out_track) const;
iallocator* m_allocator; // Optional allocator that owns the memory
uint8_t* m_data; // Pointer to the samples
uint32_t m_num_samples; // The number of samples
uint32_t m_stride; // The stride in bytes in between samples as layed out in memory
size_t m_data_size; // The total size of the buffer used by the samples
float m_sample_rate; // The track sample rate
track_type8 m_type; // The track type
track_category8 m_category; // The track category
uint16_t m_sample_size; // The size in bytes of each sample
//////////////////////////////////////////////////////////////////////////
// A union of every track description.
// This ensures every track has the same size regardless of its type.
union track_desc_untyped
{
track_desc_scalarf scalar;
track_desc_transformf transform;
track_desc_untyped() {}
explicit track_desc_untyped(const track_desc_scalarf& desc) : scalar(desc) {}
explicit track_desc_untyped(const track_desc_transformf& desc) : transform(desc) {}
};
track_desc_untyped m_desc; // The track description
string m_name; // An optional name
};
//////////////////////////////////////////////////////////////////////////
// A typed track of data. See `track` for details.
//////////////////////////////////////////////////////////////////////////
template<track_type8 track_type_>
class track_typed final : public track
{
public:
//////////////////////////////////////////////////////////////////////////
// The track type.
static constexpr track_type8 type = track_type_;
//////////////////////////////////////////////////////////////////////////
// The track category.
static constexpr track_category8 category = track_traits<track_type_>::category;
//////////////////////////////////////////////////////////////////////////
// The type of each sample in this track.
using sample_type = typename track_traits<track_type_>::sample_type;
//////////////////////////////////////////////////////////////////////////
// The type of the track description.
using desc_type = typename track_traits<track_type_>::desc_type;
//////////////////////////////////////////////////////////////////////////
// Constructs an empty typed track.
track_typed() noexcept : track(type, category) { static_assert(sizeof(track_typed) == sizeof(track), "You cannot add member variables to this class"); }
//////////////////////////////////////////////////////////////////////////
// Destroys the track and potentially frees any memory it might own.
~track_typed() = default;
//////////////////////////////////////////////////////////////////////////
// Move assignment for a track.
track_typed(track_typed&& other) noexcept : track(static_cast<track&&>(other)) {}
//////////////////////////////////////////////////////////////////////////
// Move assignment for a track.
track_typed& operator=(track_typed&& other) noexcept { return static_cast<track_typed&>(track::operator=(static_cast<track&&>(other))); }
//////////////////////////////////////////////////////////////////////////
// Returns the sample at the specified index.
// If this track does not own the memory, mutable references aren't allowed and an
// invalid reference will be returned, leading to a crash.
sample_type& operator[](uint32_t index);
//////////////////////////////////////////////////////////////////////////
// Returns the sample at the specified index.
const sample_type& operator[](uint32_t index) const;
//////////////////////////////////////////////////////////////////////////
// Returns the track description.
desc_type& get_description();
//////////////////////////////////////////////////////////////////////////
// Returns the track description.
const desc_type& get_description() const;
//////////////////////////////////////////////////////////////////////////
// Returns the track type.
track_type8 get_type() const { return type; }
//////////////////////////////////////////////////////////////////////////
// Returns the track category.
track_category8 get_category() const { return category; }
//////////////////////////////////////////////////////////////////////////
// Returns a copy of the track where the memory will be owned by the copy.
track_typed get_copy(iallocator& allocator) const;
//////////////////////////////////////////////////////////////////////////
// Returns a reference to the track where the memory isn't owned.
track_typed get_ref() const;
//////////////////////////////////////////////////////////////////////////
// Creates a track that copies the data and owns the memory.
static track_typed<track_type_> make_copy(const desc_type& desc, iallocator& allocator, const sample_type* data, uint32_t num_samples, float sample_rate, uint32_t stride = sizeof(sample_type));
//////////////////////////////////////////////////////////////////////////
// Creates a track and preallocates but does not initialize the memory that it owns.
static track_typed<track_type_> make_reserve(const desc_type& desc, iallocator& allocator, uint32_t num_samples, float sample_rate);
//////////////////////////////////////////////////////////////////////////
// Creates a track and takes ownership of the already allocated memory.
static track_typed<track_type_> make_owner(const desc_type& desc, iallocator& allocator, sample_type* data, uint32_t num_samples, float sample_rate, uint32_t stride = sizeof(sample_type));
//////////////////////////////////////////////////////////////////////////
// Creates a track that just references the data without owning it.
static track_typed<track_type_> make_ref(const desc_type& desc, sample_type* data, uint32_t num_samples, float sample_rate, uint32_t stride = sizeof(sample_type));
private:
//////////////////////////////////////////////////////////////////////////
// We prohibit copying, use get_copy() and get_ref() instead.
track_typed(const track_typed&) = delete;
track_typed& operator=(const track_typed&) = delete;
//////////////////////////////////////////////////////////////////////////
// Internal constructor.
track_typed(iallocator* allocator, uint8_t* data, uint32_t num_samples, uint32_t stride, size_t data_size, float sample_rate, const desc_type& desc) noexcept;
};
//////////////////////////////////////////////////////////////////////////
// Casts an untyped track into the desired track type while asserting for safety.
template<typename track_type>
track_type& track_cast(track& track_);
//////////////////////////////////////////////////////////////////////////
// Casts an untyped track into the desired track type while asserting for safety.
template<typename track_type>
const track_type& track_cast(const track& track_);
//////////////////////////////////////////////////////////////////////////
// Casts an untyped track into the desired track type. Returns nullptr if the types
// are not compatible or if the input is nullptr.
template<typename track_type>
track_type* track_cast(track* track_);
//////////////////////////////////////////////////////////////////////////
// Casts an untyped track into the desired track type. Returns nullptr if the types
// are not compatible or if the input is nullptr.
template<typename track_type>
const track_type* track_cast(const track* track_);
//////////////////////////////////////////////////////////////////////////
// Create aliases for the various typed track types.
using track_float1f = track_typed<track_type8::float1f>;
using track_float2f = track_typed<track_type8::float2f>;
using track_float3f = track_typed<track_type8::float3f>;
using track_float4f = track_typed<track_type8::float4f>;
using track_vector4f = track_typed<track_type8::vector4f>;
using track_qvvf = track_typed<track_type8::qvvf>;
}
#include "acl/compression/impl/track.impl.h"
#if defined(ACL_COMPILER_MSVC)
#pragma warning(pop)
#endif
ACL_IMPL_FILE_PRAGMA_POP