#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/error_result.h" #include "acl/core/iallocator.h" #include "acl/core/interpolation_utils.h" #include "acl/core/track_types.h" #include "acl/core/track_writer.h" #include "acl/core/utils.h" #include "acl/compression/track.h" #include #include #include #include #include ACL_IMPL_FILE_PRAGMA_PUSH namespace acl { ////////////////////////////////////////////////////////////////////////// // An array of tracks. // Although each track contained within is untyped, each track must have // the same type. They must all have the same sample rate and the same // number of samples. ////////////////////////////////////////////////////////////////////////// class track_array { public: ////////////////////////////////////////////////////////////////////////// // Constructs an empty track array. track_array() noexcept; ////////////////////////////////////////////////////////////////////////// // Constructs an array with the specified number of tracks. // Tracks will be empty and untyped by default. track_array(iallocator& allocator, uint32_t num_tracks); ////////////////////////////////////////////////////////////////////////// // Move constructor for a track array. track_array(track_array&& other) noexcept; ////////////////////////////////////////////////////////////////////////// // Destroys a track array. ~track_array(); ////////////////////////////////////////////////////////////////////////// // Move assignment for a track array. track_array& operator=(track_array&& other) noexcept; ////////////////////////////////////////////////////////////////////////// // 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 tracks contained in this array. uint32_t get_num_tracks() const { return m_num_tracks; } ////////////////////////////////////////////////////////////////////////// // Returns the number of samples per track in this array. uint32_t get_num_samples_per_track() const { return m_allocator != nullptr && m_num_tracks != 0 ? m_tracks->get_num_samples() : 0; } ////////////////////////////////////////////////////////////////////////// // Returns the track type for tracks in this array. track_type8 get_track_type() const { return m_allocator != nullptr && m_num_tracks != 0 ? m_tracks->get_type() : track_type8::float1f; } ////////////////////////////////////////////////////////////////////////// // Returns the track category for tracks in this array. track_category8 get_track_category() const { return m_allocator != nullptr && m_num_tracks != 0 ? m_tracks->get_category() : track_category8::scalarf; } ////////////////////////////////////////////////////////////////////////// // Returns the sample rate for tracks in this array. float get_sample_rate() const { return m_allocator != nullptr && m_num_tracks != 0 ? m_tracks->get_sample_rate() : 0.0F; } ////////////////////////////////////////////////////////////////////////// // Returns the duration for tracks in this array. float get_duration() const { return m_allocator != nullptr && m_num_tracks != 0 ? calculate_duration(uint32_t(m_tracks->get_num_samples()), m_tracks->get_sample_rate()) : 0.0F; } ////////////////////////////////////////////////////////////////////////// // 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 at the specified index. track& operator[](uint32_t index); ////////////////////////////////////////////////////////////////////////// // Returns the track at the specified index. const track& operator[](uint32_t index) const; ////////////////////////////////////////////////////////////////////////// // Iterator begin() and end() implementations. track* begin() { return m_tracks; } const track* begin() const { return m_tracks; } const track* end() { return m_tracks + m_num_tracks; } const track* end() const { return m_tracks + m_num_tracks; } ////////////////////////////////////////////////////////////////////////// // Returns true if the track array doesn't contain any data, false otherwise. bool is_empty() const { return m_num_tracks == 0; } ////////////////////////////////////////////////////////////////////////// // Returns whether a track array is valid or not. // An array is valid if: // - It is empty // - All tracks have the same type // - All tracks have the same number of samples // - All tracks have the same sample rate // - All tracks are valid error_result is_valid() const; ////////////////////////////////////////////////////////////////////////// // Sample all tracks within this array at the specified sample time and // desired rounding policy. Track samples are written out using the `track_writer` provided. template void sample_tracks(float sample_time, sample_rounding_policy rounding_policy, track_writer_type& writer) const; ////////////////////////////////////////////////////////////////////////// // Sample a single track within this array at the specified sample time and // desired rounding policy. The track sample is written out using the `track_writer` provided. template void sample_track(uint32_t track_index, float sample_time, sample_rounding_policy rounding_policy, track_writer_type& writer) const; ////////////////////////////////////////////////////////////////////////// // Returns the raw size for this track array. Note that this differs from the actual // memory used by an instance of this class. It is meant for comparison against // the compressed size. uint32_t get_raw_size() const; protected: ////////////////////////////////////////////////////////////////////////// // We prohibit copying track_array(const track_array&) = delete; track_array& operator=(const track_array&) = delete; iallocator* m_allocator; // The allocator used to allocate our tracks track* m_tracks; // The track list uint32_t m_num_tracks; // The number of tracks string m_name; // An optional name }; ////////////////////////////////////////////////////////////////////////// // A typed track array. See `track_array` for details. ////////////////////////////////////////////////////////////////////////// template class track_array_typed final : public track_array { public: ////////////////////////////////////////////////////////////////////////// // The track type. static constexpr track_type8 type = track_type_; ////////////////////////////////////////////////////////////////////////// // The track category. static constexpr track_category8 category = track_traits::category; ////////////////////////////////////////////////////////////////////////// // The track member type. using track_member_type = track_typed; ////////////////////////////////////////////////////////////////////////// // Constructs an empty track array. track_array_typed() noexcept : track_array() { static_assert(sizeof(track_array_typed) == sizeof(track_array), "You cannot add member variables to this class"); } ////////////////////////////////////////////////////////////////////////// // Constructs an array with the specified number of tracks. // Tracks will be empty and untyped by default. track_array_typed(iallocator& allocator, uint32_t num_tracks) : track_array(allocator, num_tracks) {} ////////////////////////////////////////////////////////////////////////// // Move constructor for a track array. track_array_typed(track_array_typed&& other) noexcept : track_array(static_cast(other)) {} ////////////////////////////////////////////////////////////////////////// // Destroys a track array. ~track_array_typed() = default; ////////////////////////////////////////////////////////////////////////// // Move assignment for a track array. track_array_typed& operator=(track_array_typed&& other) noexcept { return static_cast(track_array::operator=(static_cast(other))); } ////////////////////////////////////////////////////////////////////////// // Returns the track type for tracks in this array. track_type8 get_track_type() const { return type; } ////////////////////////////////////////////////////////////////////////// // Returns the track category for tracks in this array. track_category8 get_track_category() const { return category; } ////////////////////////////////////////////////////////////////////////// // Returns the track at the specified index. track_member_type& operator[](uint32_t index); ////////////////////////////////////////////////////////////////////////// // Returns the track at the specified index. const track_member_type& operator[](uint32_t index) const; ////////////////////////////////////////////////////////////////////////// // Iterator begin() and end() implementations. track_member_type* begin() { return track_cast(m_tracks); } const track_member_type* begin() const { return track_cast(m_tracks); } const track_member_type* end() { return track_cast(m_tracks) + m_num_tracks; } const track_member_type* end() const { return track_cast(m_tracks) + m_num_tracks; } }; ////////////////////////////////////////////////////////////////////////// // Casts an untyped track array into the desired track array type while asserting for safety. template track_array_type& track_array_cast(track_array& track_array_); ////////////////////////////////////////////////////////////////////////// // Casts an untyped track array into the desired track array type while asserting for safety. template const track_array_type& track_array_cast(const track_array& track_array_); ////////////////////////////////////////////////////////////////////////// // Casts an untyped track array into the desired track array type. Returns nullptr if the types // are not compatible or if the input is nullptr. template track_array_type* track_array_cast(track_array* track_array_); ////////////////////////////////////////////////////////////////////////// // Casts an untyped track array into the desired track array type. Returns nullptr if the types // are not compatible or if the input is nullptr. template const track_array_type* track_array_cast(const track_array* track_array_); ////////////////////////////////////////////////////////////////////////// // Create aliases for the various typed track array types. using track_array_float1f = track_array_typed; using track_array_float2f = track_array_typed; using track_array_float3f = track_array_typed; using track_array_float4f = track_array_typed; using track_array_vector4f = track_array_typed; using track_array_qvvf = track_array_typed; } #include "acl/compression/impl/track_array.impl.h" ACL_IMPL_FILE_PRAGMA_POP