267 lines
9.4 KiB
C++
267 lines
9.4 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/bitset.h"
|
|
#include "acl/core/track_desc.h"
|
|
#include "acl/core/variable_bit_rates.h"
|
|
#include "acl/compression/track_array.h"
|
|
#include "acl/compression/impl/track_range.h"
|
|
|
|
#include <rtm/vector4f.h>
|
|
|
|
#include <cstdint>
|
|
|
|
ACL_IMPL_FILE_PRAGMA_PUSH
|
|
|
|
namespace acl
|
|
{
|
|
namespace acl_impl
|
|
{
|
|
struct scalar_bit_rate
|
|
{
|
|
uint8_t value;
|
|
};
|
|
|
|
struct qvv_bit_rate
|
|
{
|
|
uint8_t rotation;
|
|
uint8_t translation;
|
|
uint8_t scale;
|
|
};
|
|
|
|
union track_bit_rate
|
|
{
|
|
scalar_bit_rate scalar;
|
|
qvv_bit_rate qvv;
|
|
|
|
track_bit_rate() : qvv{k_invalid_bit_rate, k_invalid_bit_rate, k_invalid_bit_rate} {}
|
|
};
|
|
|
|
struct track_list_context
|
|
{
|
|
iallocator* allocator;
|
|
const track_array* reference_list;
|
|
|
|
track_array track_list;
|
|
|
|
track_range* range_list;
|
|
uint32_t* constant_tracks_bitset;
|
|
track_bit_rate* bit_rate_list;
|
|
uint32_t* track_output_indices;
|
|
|
|
uint32_t num_tracks;
|
|
uint32_t num_output_tracks;
|
|
uint32_t num_samples;
|
|
float sample_rate;
|
|
float duration;
|
|
|
|
track_list_context()
|
|
: allocator(nullptr)
|
|
, reference_list(nullptr)
|
|
, track_list()
|
|
, range_list(nullptr)
|
|
, constant_tracks_bitset(nullptr)
|
|
, bit_rate_list(nullptr)
|
|
, track_output_indices(nullptr)
|
|
, num_tracks(0)
|
|
, num_output_tracks(0)
|
|
, num_samples(0)
|
|
, sample_rate(0.0F)
|
|
, duration(0.0F)
|
|
{}
|
|
|
|
~track_list_context()
|
|
{
|
|
if (allocator != nullptr)
|
|
{
|
|
deallocate_type_array(*allocator, range_list, num_tracks);
|
|
|
|
const bitset_description bitset_desc = bitset_description::make_from_num_bits(num_tracks);
|
|
deallocate_type_array(*allocator, constant_tracks_bitset, bitset_desc.get_size());
|
|
|
|
deallocate_type_array(*allocator, bit_rate_list, num_tracks);
|
|
|
|
deallocate_type_array(*allocator, track_output_indices, num_output_tracks);
|
|
}
|
|
}
|
|
|
|
bool is_valid() const { return allocator != nullptr; }
|
|
bool is_constant(uint32_t track_index) const { return bitset_test(constant_tracks_bitset, bitset_description::make_from_num_bits(num_tracks), track_index); }
|
|
|
|
track_list_context(const track_list_context&) = delete;
|
|
track_list_context(track_list_context&&) = delete;
|
|
track_list_context& operator=(const track_list_context&) = delete;
|
|
track_list_context& operator=(track_list_context&&) = delete;
|
|
};
|
|
|
|
// Promote scalar tracks to vector tracks for SIMD alignment and padding
|
|
inline track_array copy_and_promote_track_list(iallocator& allocator, const track_array& ref_track_list, bool& out_are_samples_valid)
|
|
{
|
|
using namespace rtm;
|
|
|
|
const uint32_t num_tracks = ref_track_list.get_num_tracks();
|
|
const uint32_t num_samples = ref_track_list.get_num_samples_per_track();
|
|
const float sample_rate = ref_track_list.get_sample_rate();
|
|
bool are_samples_valid = true;
|
|
|
|
track_array out_track_list(allocator, num_tracks);
|
|
|
|
for (uint32_t track_index = 0; track_index < num_tracks; ++track_index)
|
|
{
|
|
const track& ref_track = ref_track_list[track_index];
|
|
track& out_track = out_track_list[track_index];
|
|
|
|
switch (ref_track.get_type())
|
|
{
|
|
case track_type8::float1f:
|
|
{
|
|
const track_float1f& typed_ref_track = track_cast<const track_float1f>(ref_track);
|
|
track_vector4f track = track_vector4f::make_reserve(ref_track.get_description<track_desc_scalarf>(), allocator, num_samples, sample_rate);
|
|
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
|
|
{
|
|
const vector4f sample = vector_load1(&typed_ref_track[sample_index]);
|
|
are_samples_valid &= scalar_is_finite(scalarf(vector_get_x(sample)));
|
|
track[sample_index] = sample;
|
|
}
|
|
out_track = std::move(track);
|
|
break;
|
|
}
|
|
case track_type8::float2f:
|
|
{
|
|
const track_float2f& typed_ref_track = track_cast<const track_float2f>(ref_track);
|
|
track_vector4f track = track_vector4f::make_reserve(ref_track.get_description<track_desc_scalarf>(), allocator, num_samples, sample_rate);
|
|
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
|
|
{
|
|
const vector4f sample = vector_load2(&typed_ref_track[sample_index]);
|
|
are_samples_valid &= vector_is_finite2(sample);
|
|
track[sample_index] = sample;
|
|
}
|
|
out_track = std::move(track);
|
|
break;
|
|
}
|
|
case track_type8::float3f:
|
|
{
|
|
const track_float3f& typed_ref_track = track_cast<const track_float3f>(ref_track);
|
|
track_vector4f track = track_vector4f::make_reserve(ref_track.get_description<track_desc_scalarf>(), allocator, num_samples, sample_rate);
|
|
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
|
|
{
|
|
const vector4f sample = vector_load3(&typed_ref_track[sample_index]);
|
|
are_samples_valid &= vector_is_finite3(sample);
|
|
track[sample_index] = sample;
|
|
}
|
|
out_track = std::move(track);
|
|
break;
|
|
}
|
|
case track_type8::float4f:
|
|
{
|
|
const track_float4f& typed_ref_track = track_cast<const track_float4f>(ref_track);
|
|
track_vector4f track = track_vector4f::make_reserve(ref_track.get_description<track_desc_scalarf>(), allocator, num_samples, sample_rate);
|
|
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
|
|
{
|
|
const vector4f sample = vector_load(&typed_ref_track[sample_index]);
|
|
are_samples_valid &= vector_is_finite(sample);
|
|
track[sample_index] = sample;
|
|
}
|
|
out_track = std::move(track);
|
|
break;
|
|
}
|
|
case track_type8::vector4f:
|
|
{
|
|
const track_vector4f& typed_ref_track = track_cast<const track_vector4f>(ref_track);
|
|
track_vector4f track = track_vector4f::make_reserve(ref_track.get_description<track_desc_scalarf>(), allocator, num_samples, sample_rate);
|
|
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
|
|
{
|
|
const vector4f sample = typed_ref_track[sample_index];
|
|
are_samples_valid &= vector_is_finite(sample);
|
|
track[sample_index] = sample;
|
|
}
|
|
out_track = std::move(track);
|
|
break;
|
|
}
|
|
default:
|
|
ACL_ASSERT(false, "Unexpected track type");
|
|
are_samples_valid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
out_are_samples_valid = are_samples_valid;
|
|
return out_track_list;
|
|
}
|
|
|
|
inline uint32_t* create_output_track_mapping(iallocator& allocator, const track_array& track_list, uint32_t& out_num_output_tracks)
|
|
{
|
|
const uint32_t num_tracks = track_list.get_num_tracks();
|
|
uint32_t num_output_tracks = num_tracks;
|
|
for (uint32_t track_index = 0; track_index < num_tracks; ++track_index)
|
|
{
|
|
const uint32_t output_index = track_list[track_index].get_output_index();
|
|
if (output_index == k_invalid_track_index)
|
|
num_output_tracks--; // Stripped from the output
|
|
}
|
|
|
|
uint32_t* output_indices = allocate_type_array<uint32_t>(allocator, num_output_tracks);
|
|
for (uint32_t track_index = 0; track_index < num_tracks; ++track_index)
|
|
{
|
|
const uint32_t output_index = track_list[track_index].get_output_index();
|
|
if (output_index != k_invalid_track_index)
|
|
output_indices[output_index] = track_index;
|
|
}
|
|
|
|
out_num_output_tracks = num_output_tracks;
|
|
return output_indices;
|
|
}
|
|
|
|
inline bool initialize_context(iallocator& allocator, const track_array& track_list, track_list_context& context)
|
|
{
|
|
ACL_ASSERT(track_list.is_valid().empty(), "Invalid track list");
|
|
ACL_ASSERT(!context.is_valid(), "Context already initialized");
|
|
|
|
bool are_samples_valid = true;
|
|
|
|
context.allocator = &allocator;
|
|
context.reference_list = &track_list;
|
|
context.track_list = copy_and_promote_track_list(allocator, track_list, are_samples_valid);
|
|
context.range_list = nullptr;
|
|
context.constant_tracks_bitset = nullptr;
|
|
context.track_output_indices = nullptr;
|
|
context.num_tracks = track_list.get_num_tracks();
|
|
context.num_output_tracks = 0;
|
|
context.num_samples = track_list.get_num_samples_per_track();
|
|
context.sample_rate = track_list.get_sample_rate();
|
|
context.duration = track_list.get_duration();
|
|
|
|
context.track_output_indices = create_output_track_mapping(allocator, track_list, context.num_output_tracks);
|
|
|
|
return are_samples_valid;
|
|
}
|
|
}
|
|
}
|
|
|
|
ACL_IMPL_FILE_PRAGMA_POP
|