#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/impl/compressed_headers.h" #include "acl/compression/compression_settings.h" #include "acl/compression/impl/clip_context.h" #include "acl/compression/impl/segment_context.h" #include "acl/compression/impl/write_range_data.h" #include "acl/compression/impl/write_stream_data.h" #include ACL_IMPL_FILE_PRAGMA_PUSH namespace acl { namespace acl_impl { inline uint32_t write_segment_start_indices(const clip_context& clip, uint32_t* segment_start_indices) { uint32_t size_written = 0; const uint32_t num_segments = clip.num_segments; for (uint32_t segment_index = 0; segment_index < num_segments; ++segment_index) { const SegmentContext& segment = clip.segments[segment_index]; segment_start_indices[segment_index] = segment.clip_sample_offset; size_written += sizeof(uint32_t); } // Write our sentinel value segment_start_indices[clip.num_segments] = 0xFFFFFFFFU; size_written += sizeof(uint32_t); return size_written; } inline uint32_t write_segment_headers(const clip_context& clip, const compression_settings& settings, segment_header* segment_headers, uint32_t segment_data_start_offset) { uint32_t size_written = 0; const uint32_t format_per_track_data_size = get_format_per_track_data_size(clip, settings.rotation_format, settings.translation_format, settings.scale_format); uint32_t segment_data_offset = segment_data_start_offset; for (uint32_t segment_index = 0; segment_index < clip.num_segments; ++segment_index) { const SegmentContext& segment = clip.segments[segment_index]; segment_header& header = segment_headers[segment_index]; ACL_ASSERT(header.animated_pose_bit_size == 0, "Buffer overrun detected"); header.animated_pose_bit_size = segment.animated_pose_bit_size; header.segment_data = segment_data_offset; segment_data_offset = align_to(segment_data_offset + format_per_track_data_size, 2); // Aligned to 2 bytes segment_data_offset = align_to(segment_data_offset + segment.range_data_size, 4); // Aligned to 4 bytes segment_data_offset = segment_data_offset + segment.animated_data_size; size_written += sizeof(segment_header); ACL_ASSERT((segment_data_offset - (uint32_t)header.segment_data) == segment.segment_data_size, "Unexpected segment size"); } return size_written; } inline uint32_t write_segment_data(const clip_context& clip, const compression_settings& settings, range_reduction_flags8 range_reduction, transform_tracks_header& header, const uint32_t* output_bone_mapping, uint32_t num_output_bones) { segment_header* segment_headers = header.get_segment_headers(); const uint32_t format_per_track_data_size = get_format_per_track_data_size(clip, settings.rotation_format, settings.translation_format, settings.scale_format); uint32_t size_written = 0; const uint32_t num_segments = clip.num_segments; for (uint32_t segment_index = 0; segment_index < num_segments; ++segment_index) { const SegmentContext& segment = clip.segments[segment_index]; segment_header& segment_header_ = segment_headers[segment_index]; uint8_t* format_per_track_data = nullptr; uint8_t* range_data = nullptr; uint8_t* animated_data = nullptr; header.get_segment_data(segment_header_, format_per_track_data, range_data, animated_data); ACL_ASSERT(format_per_track_data[0] == 0, "Buffer overrun detected"); ACL_ASSERT(range_data[0] == 0, "Buffer overrun detected"); ACL_ASSERT(animated_data[0] == 0, "Buffer overrun detected"); if (format_per_track_data_size != 0) { const uint32_t size = write_format_per_track_data(segment, format_per_track_data, format_per_track_data_size, output_bone_mapping, num_output_bones); (void)size; ACL_ASSERT(size == format_per_track_data_size, "Unexpected format per track data size"); } if (segment.range_data_size != 0) { const uint32_t size = write_segment_range_data(segment, range_reduction, range_data, segment.range_data_size, output_bone_mapping, num_output_bones); (void)size; ACL_ASSERT(size == segment.range_data_size, "Unexpected range data size"); } if (segment.animated_data_size != 0) { const uint32_t size = write_animated_track_data(segment, animated_data, segment.animated_data_size, output_bone_mapping, num_output_bones); (void)size; ACL_ASSERT(size == segment.animated_data_size, "Unexpected animated data size"); } size_written += segment.segment_data_size; } return size_written; } } } ACL_IMPL_FILE_PRAGMA_POP