cocos-engine-external/sources/acl/io/clip_writer.h

381 lines
15 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.
////////////////////////////////////////////////////////////////////////////////
#if defined(SJSON_CPP_WRITER)
#include "acl/compression/compression_settings.h"
#include "acl/compression/track_array.h"
#include "acl/core/impl/compiler_utils.h"
#include "acl/core/iallocator.h"
#include "acl/core/error.h"
#include "acl/core/track_desc.h"
#include <rtm/quatd.h>
#include <rtm/vector4d.h>
#include <cstdint>
#include <cinttypes>
#include <cstdio>
ACL_IMPL_FILE_PRAGMA_PUSH
namespace acl
{
namespace acl_impl
{
inline const char* format_hex_float(float value, char* buffer, size_t buffer_size)
{
union FloatToUInt32
{
uint32_t u32;
float flt;
constexpr explicit FloatToUInt32(float flt_value) : flt(flt_value) {}
};
snprintf(buffer, buffer_size, "%" PRIX32, FloatToUInt32(value).u32);
return buffer;
};
inline void write_sjson_settings(const compression_settings& settings, sjson::Writer& writer)
{
writer["settings"] = [&](sjson::ObjectWriter& settings_writer)
{
settings_writer["level"] = get_compression_level_name(settings.level);
settings_writer["rotation_format"] = get_rotation_format_name(settings.rotation_format);
settings_writer["translation_format"] = get_vector_format_name(settings.translation_format);
settings_writer["scale_format"] = get_vector_format_name(settings.scale_format);
settings_writer["segmenting"] = [&](sjson::ObjectWriter& segmenting_writer)
{
segmenting_writer["ideal_num_samples"] = settings.segmenting.ideal_num_samples;
segmenting_writer["max_num_samples"] = settings.segmenting.max_num_samples;
};
};
writer.insert_newline();
}
inline void write_sjson_header(const track_array& track_list, sjson::Writer& writer)
{
writer["version"] = 5;
writer.insert_newline();
writer["track_list"] = [&](sjson::ObjectWriter& header_writer)
{
header_writer["name"] = track_list.get_name().c_str();
header_writer["num_samples"] = track_list.get_num_samples_per_track();
header_writer["sample_rate"] = track_list.get_sample_rate();
header_writer["is_binary_exact"] = true;
#if 0 // TODO
clip_writer["additive_format"] = get_additive_clip_format_name(clip.get_additive_format());
const AnimationClip* base_clip = clip.get_additive_base();
if (base_clip != nullptr)
{
clip_writer["additive_base_name"] = base_clip->get_name().c_str();
clip_writer["additive_base_num_samples"] = base_clip->get_num_samples();
clip_writer["additive_base_sample_rate"] = base_clip->get_sample_rate();
}
#endif
};
writer.insert_newline();
}
inline void write_sjson_scalar_desc(const track_desc_scalarf& desc, sjson::ObjectWriter& writer)
{
char buffer[32] = { 0 };
writer["precision"] = format_hex_float(desc.precision, buffer, sizeof(buffer));
writer["output_index"] = desc.output_index;
}
inline void write_sjson_transform_desc(const track_desc_transformf& desc, sjson::ObjectWriter& writer)
{
char buffer[32] = { 0 };
writer["precision"] = format_hex_float(desc.precision, buffer, sizeof(buffer));
writer["output_index"] = desc.output_index;
writer["parent_index"] = desc.parent_index;
writer["shell_distance"] = format_hex_float(desc.shell_distance, buffer, sizeof(buffer));
writer["constant_rotation_threshold_angle"] = format_hex_float(desc.constant_rotation_threshold_angle, buffer, sizeof(buffer));
writer["constant_translation_threshold"] = format_hex_float(desc.constant_translation_threshold, buffer, sizeof(buffer));
writer["constant_scale_threshold"] = format_hex_float(desc.constant_scale_threshold, buffer, sizeof(buffer));
}
inline void write_sjson_tracks(const track_array& track_list, sjson::Writer& writer)
{
char buffer[32] = { 0 };
writer["tracks"] = [&](sjson::ArrayWriter& tracks_writer)
{
const uint32_t num_tracks = track_list.get_num_tracks();
if (num_tracks > 0)
tracks_writer.push_newline();
for (const track& track_ : track_list)
{
tracks_writer.push([&](sjson::ObjectWriter& track_writer)
{
track_writer["name"] = track_.get_name().c_str();
track_writer["type"] = get_track_type_name(track_.get_type());
switch (track_.get_type())
{
case track_type8::float1f:
{
const track_float1f& track__ = track_cast<track_float1f>(track_);
write_sjson_scalar_desc(track__.get_description(), track_writer);
track_writer["data"] = [&](sjson::ArrayWriter& data_writer)
{
const uint32_t num_samples = track__.get_num_samples();
if (num_samples > 0)
data_writer.push_newline();
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
{
data_writer.push([&](sjson::ArrayWriter& sample_writer)
{
const float sample = track__[sample_index];
sample_writer.push(acl_impl::format_hex_float(sample, buffer, sizeof(buffer)));
});
data_writer.push_newline();
}
};
break;
}
case track_type8::float2f:
{
const track_float2f& track__ = track_cast<track_float2f>(track_);
write_sjson_scalar_desc(track__.get_description(), track_writer);
track_writer["data"] = [&](sjson::ArrayWriter& data_writer)
{
const uint32_t num_samples = track__.get_num_samples();
if (num_samples > 0)
data_writer.push_newline();
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
{
data_writer.push([&](sjson::ArrayWriter& sample_writer)
{
const rtm::float2f& sample = track__[sample_index];
sample_writer.push(acl_impl::format_hex_float(sample.x, buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(sample.y, buffer, sizeof(buffer)));
});
data_writer.push_newline();
}
};
break;
}
case track_type8::float3f:
{
const track_float3f& track__ = track_cast<track_float3f>(track_);
write_sjson_scalar_desc(track__.get_description(), track_writer);
track_writer["data"] = [&](sjson::ArrayWriter& data_writer)
{
const uint32_t num_samples = track__.get_num_samples();
if (num_samples > 0)
data_writer.push_newline();
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
{
data_writer.push([&](sjson::ArrayWriter& sample_writer)
{
const rtm::float3f& sample = track__[sample_index];
sample_writer.push(acl_impl::format_hex_float(sample.x, buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(sample.y, buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(sample.z, buffer, sizeof(buffer)));
});
data_writer.push_newline();
}
};
break;
}
case track_type8::float4f:
{
const track_float4f& track__ = track_cast<track_float4f>(track_);
write_sjson_scalar_desc(track__.get_description(), track_writer);
track_writer["data"] = [&](sjson::ArrayWriter& data_writer)
{
const uint32_t num_samples = track__.get_num_samples();
if (num_samples > 0)
data_writer.push_newline();
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
{
data_writer.push([&](sjson::ArrayWriter& sample_writer)
{
const rtm::float4f& sample = track__[sample_index];
sample_writer.push(acl_impl::format_hex_float(sample.x, buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(sample.y, buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(sample.z, buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(sample.w, buffer, sizeof(buffer)));
});
data_writer.push_newline();
}
};
break;
}
case track_type8::vector4f:
{
const track_vector4f& track__ = track_cast<track_vector4f>(track_);
write_sjson_scalar_desc(track__.get_description(), track_writer);
track_writer["data"] = [&](sjson::ArrayWriter& data_writer)
{
const uint32_t num_samples = track__.get_num_samples();
if (num_samples > 0)
data_writer.push_newline();
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
{
data_writer.push([&](sjson::ArrayWriter& sample_writer)
{
const rtm::vector4f& sample = track__[sample_index];
sample_writer.push(acl_impl::format_hex_float(rtm::vector_get_x(sample), buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(rtm::vector_get_y(sample), buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(rtm::vector_get_z(sample), buffer, sizeof(buffer)));
sample_writer.push(acl_impl::format_hex_float(rtm::vector_get_w(sample), buffer, sizeof(buffer)));
});
data_writer.push_newline();
}
};
break;
}
case track_type8::qvvf:
{
const track_qvvf& track__ = track_cast<track_qvvf>(track_);
write_sjson_transform_desc(track__.get_description(), track_writer);
track_writer["data"] = [&](sjson::ArrayWriter& data_writer)
{
const uint32_t num_samples = track__.get_num_samples();
if (num_samples > 0)
data_writer.push_newline();
for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index)
{
data_writer.push([&](sjson::ArrayWriter& sample_writer)
{
const rtm::qvvf& sample = track__[sample_index];
sample_writer.push([&](sjson::ArrayWriter& rotation_writer)
{
rotation_writer.push(acl_impl::format_hex_float(rtm::quat_get_x(sample.rotation), buffer, sizeof(buffer)));
rotation_writer.push(acl_impl::format_hex_float(rtm::quat_get_y(sample.rotation), buffer, sizeof(buffer)));
rotation_writer.push(acl_impl::format_hex_float(rtm::quat_get_z(sample.rotation), buffer, sizeof(buffer)));
rotation_writer.push(acl_impl::format_hex_float(rtm::quat_get_w(sample.rotation), buffer, sizeof(buffer)));
});
sample_writer.push([&](sjson::ArrayWriter& translation_writer)
{
translation_writer.push(acl_impl::format_hex_float(rtm::vector_get_x(sample.translation), buffer, sizeof(buffer)));
translation_writer.push(acl_impl::format_hex_float(rtm::vector_get_y(sample.translation), buffer, sizeof(buffer)));
translation_writer.push(acl_impl::format_hex_float(rtm::vector_get_z(sample.translation), buffer, sizeof(buffer)));
});
sample_writer.push([&](sjson::ArrayWriter& scale_writer)
{
scale_writer.push(acl_impl::format_hex_float(rtm::vector_get_x(sample.scale), buffer, sizeof(buffer)));
scale_writer.push(acl_impl::format_hex_float(rtm::vector_get_y(sample.scale), buffer, sizeof(buffer)));
scale_writer.push(acl_impl::format_hex_float(rtm::vector_get_z(sample.scale), buffer, sizeof(buffer)));
});
});
data_writer.push_newline();
}
};
break;
}
default:
ACL_ASSERT(false, "Unknown track type");
break;
}
});
}
};
writer.insert_newline();
}
inline error_result write_track_list(const track_array& track_list, const compression_settings* settings, const char* acl_filename)
{
if (acl_filename == nullptr)
return error_result("'acl_filename' cannot be NULL!");
const size_t filename_len = std::strlen(acl_filename);
if (filename_len < 10 || strncmp(acl_filename + filename_len - 10, ".acl.sjson", 10) != 0)
return error_result("'acl_filename' file must be an ACL SJSON file of the form: *.acl.sjson");
std::FILE* file = nullptr;
#ifdef _WIN32
char path[64 * 1024] = { 0 };
snprintf(path, get_array_size(path), "\\\\?\\%s", acl_filename);
fopen_s(&file, path, "w");
#else
file = fopen(acl_filename, "w");
#endif
if (file == nullptr)
return error_result("Failed to open ACL file for writing");
sjson::FileStreamWriter stream_writer(file);
sjson::Writer writer(stream_writer);
write_sjson_header(track_list, writer);
if (settings != nullptr)
write_sjson_settings(*settings, writer);
write_sjson_tracks(track_list, writer);
std::fclose(file);
return error_result();
}
}
//////////////////////////////////////////////////////////////////////////
// Write out an SJSON ACL track list file.
//////////////////////////////////////////////////////////////////////////
inline error_result write_track_list(const track_array& track_list, const char* acl_filename)
{
return acl_impl::write_track_list(track_list, nullptr, acl_filename);
}
//////////////////////////////////////////////////////////////////////////
// Write out an SJSON ACL track list file.
//////////////////////////////////////////////////////////////////////////
inline error_result write_track_list(const track_array& track_list, const compression_settings& settings, const char* acl_filename)
{
return acl_impl::write_track_list(track_list, &settings, acl_filename);
}
}
ACL_IMPL_FILE_PRAGMA_POP
#endif // #if defined(SJSON_CPP_WRITER)