509 lines
24 KiB
C++
509 lines
24 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.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "acl/core/additive_utils.h"
|
|
#include "acl/core/impl/compiler_utils.h"
|
|
#include "acl/core/hash.h"
|
|
|
|
#include <rtm/matrix3x4f.h>
|
|
#include <rtm/qvvf.h>
|
|
#include <rtm/scalarf.h>
|
|
|
|
ACL_IMPL_FILE_PRAGMA_PUSH
|
|
|
|
namespace acl
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Interface for all skeletal error metrics.
|
|
// An error metric is responsible for a few things:
|
|
// - converting from rtm::qvvf into whatever transform type the metric uses (optional)
|
|
// - applying local space transforms on top of base transforms (optional)
|
|
// - transforming local space transforms into object space
|
|
// - evaluating the error function
|
|
//
|
|
// Most functions require two implementations: with and without scale support.
|
|
// This is entirely for performance reasons as most clips do not have any scale.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
class itransform_error_metric
|
|
{
|
|
public:
|
|
virtual ~itransform_error_metric() {}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Returns the unique name of the error metric.
|
|
virtual const char* get_name() const = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Returns a unique hash to represent the error metric.
|
|
virtual uint32_t get_hash() const { return hash32(get_name()); }
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Returns the transform size used by the error metric.
|
|
virtual size_t get_transform_size(bool has_scale) const = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Returns whether or not the error metric uses a transform that isn't rtm::qvvf.
|
|
// If this is the case, we need to convert from rtm::qvvf into the transform type
|
|
// used by the error metric.
|
|
virtual bool needs_conversion(bool has_scale) const { (void)has_scale; return false; }
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Input arguments for the 'convert_transforms*' functions.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
struct convert_transforms_args
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// A list of transform indices that are dirty and need conversion.
|
|
const uint32_t* dirty_transform_indices;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The number of dirty transforms that need conversion.
|
|
uint32_t num_dirty_transforms;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The input transforms in rtm::qvvf format to be converted.
|
|
const rtm::qvvf* transforms;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The number of transforms in the input and output buffers.
|
|
uint32_t num_transforms;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Converts from rtm::qvvf into the transform type used by the error metric.
|
|
// Called when 'needs_conversion' returns true.
|
|
virtual void convert_transforms(const convert_transforms_args& args, void* out_transforms) const
|
|
{
|
|
(void)args;
|
|
(void)out_transforms;
|
|
ACL_ASSERT(false, "Not implemented");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Converts from rtm::qvvf into the transform type used by the error metric.
|
|
// Called when 'needs_conversion' returns true.
|
|
virtual void convert_transforms_no_scale(const convert_transforms_args& args, void* out_transforms) const
|
|
{
|
|
(void)args;
|
|
(void)out_transforms;
|
|
ACL_ASSERT(false, "Not implemented");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Input arguments for the 'local_to_object_space*' functions.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
struct local_to_object_space_args
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// A list of transform indices that are dirty and need transformation.
|
|
const uint32_t* dirty_transform_indices;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The number of dirty transforms that need transformation.
|
|
uint32_t num_dirty_transforms;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// A list of parent transform indices for every transform.
|
|
// An index of 0xFFFF represents a root transform with no parent.
|
|
const uint32_t* parent_transform_indices;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The input transforms in the type expected by the error metric to be transformed.
|
|
const void* local_transforms;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The number of transforms in the input and output buffers.
|
|
uint32_t num_transforms;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Takes local space transforms into object space.
|
|
virtual void local_to_object_space(const local_to_object_space_args& args, void* out_object_transforms) const
|
|
{
|
|
(void)args;
|
|
(void)out_object_transforms;
|
|
ACL_ASSERT(false, "Not implemented");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Takes local space transforms into object space.
|
|
virtual void local_to_object_space_no_scale(const local_to_object_space_args& args, void* out_object_transforms) const
|
|
{
|
|
(void)args;
|
|
(void)out_object_transforms;
|
|
ACL_ASSERT(false, "Not implemented");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Input arguments for the 'apply_additive_to_base*' functions.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
struct apply_additive_to_base_args
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// A list of transform indices that are dirty and need the base applied.
|
|
const uint32_t* dirty_transform_indices;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The number of dirty transforms that need the base applied.
|
|
uint32_t num_dirty_transforms;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The input local space transforms in the type expected by the error metric.
|
|
const void* local_transforms;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The input base transforms in the type expected by the error metric.
|
|
const void* base_transforms;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The number of transforms in the input and output buffers.
|
|
uint32_t num_transforms;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Applies local space transforms on top of base transforms.
|
|
// This is called when a clip has an additive base.
|
|
virtual void apply_additive_to_base(const apply_additive_to_base_args& args, void* out_transforms) const
|
|
{
|
|
(void)args;
|
|
(void)out_transforms;
|
|
ACL_ASSERT(false, "Not implemented");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Applies local space transforms on top of base transforms.
|
|
// This is called when a clip has an additive base.
|
|
virtual void apply_additive_to_base_no_scale(const apply_additive_to_base_args& args, void* out_transforms) const
|
|
{
|
|
(void)args;
|
|
(void)out_transforms;
|
|
ACL_ASSERT(false, "Not implemented");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Input arguments for the 'calculate_error*' functions.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
struct calculate_error_args
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// A point on our rigid shell along the X axis.
|
|
rtm::vector4f shell_point_x;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// A point on our rigid shell along the Y axis.
|
|
rtm::vector4f shell_point_y;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// A point on our rigid shell along the Z axis.
|
|
rtm::vector4f shell_point_z;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The first transform used to measure the error.
|
|
// In the type expected by the error metric.
|
|
// Could be in local or object space (same space as lossy).
|
|
const void* transform0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// The second transform used to measure the error.
|
|
// In the type expected by the error metric.
|
|
// Could be in local or object space (same space as raw).
|
|
const void* transform1;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// We measure the error on a rigid shell around each transform.
|
|
// This shell takes the form of a sphere at a certain distance.
|
|
// When no scale is present, measuring any two points is sufficient
|
|
// but when there is scale, measuring all three is necessary.
|
|
// See ./docs/error_metrics.md for details.
|
|
void construct_sphere_shell(float shell_distance)
|
|
{
|
|
shell_point_x = rtm::vector_set(shell_distance, 0.0F, 0.0F, 0.0F);
|
|
shell_point_y = rtm::vector_set(0.0F, shell_distance, 0.0F, 0.0F);
|
|
shell_point_z = rtm::vector_set(0.0F, 0.0F, shell_distance, 0.0F);
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Measures the error between a raw and lossy transform.
|
|
virtual rtm::scalarf RTM_SIMD_CALL calculate_error(const calculate_error_args& args) const = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Measures the error between a raw and lossy transform.
|
|
virtual rtm::scalarf RTM_SIMD_CALL calculate_error_no_scale(const calculate_error_args& args) const = 0;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Uses rtm::qvvf arithmetic for local and object space error.
|
|
// Note that this can cause inaccuracy when dealing with shear/skew.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
class qvvf_transform_error_metric : public itransform_error_metric
|
|
{
|
|
public:
|
|
virtual const char* get_name() const override { return "qvvf_transform_error_metric"; }
|
|
|
|
virtual size_t get_transform_size(bool has_scale) const override { (void)has_scale; return sizeof(rtm::qvvf); }
|
|
virtual bool needs_conversion(bool has_scale) const override { (void)has_scale; return false; }
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK void local_to_object_space(const local_to_object_space_args& args, void* out_object_transforms) const override
|
|
{
|
|
const uint32_t* dirty_transform_indices = args.dirty_transform_indices;
|
|
const uint32_t* parent_transform_indices = args.parent_transform_indices;
|
|
const rtm::qvvf* local_transforms_ = static_cast<const rtm::qvvf*>(args.local_transforms);
|
|
rtm::qvvf* out_object_transforms_ = static_cast<rtm::qvvf*>(out_object_transforms);
|
|
|
|
const uint32_t num_dirty_transforms = args.num_dirty_transforms;
|
|
for (uint32_t dirty_transform_index = 0; dirty_transform_index < num_dirty_transforms; ++dirty_transform_index)
|
|
{
|
|
const uint32_t transform_index = dirty_transform_indices[dirty_transform_index];
|
|
const uint32_t parent_transform_index = parent_transform_indices[transform_index];
|
|
|
|
rtm::qvvf obj_transform;
|
|
if (parent_transform_index == k_invalid_track_index)
|
|
obj_transform = local_transforms_[transform_index]; // Just copy the root as-is, it has no parent and thus local and object space transforms are equal
|
|
else
|
|
obj_transform = rtm::qvv_mul(local_transforms_[transform_index], out_object_transforms_[parent_transform_index]);
|
|
|
|
out_object_transforms_[transform_index] = obj_transform;
|
|
}
|
|
}
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK void local_to_object_space_no_scale(const local_to_object_space_args& args, void* out_object_transforms) const override
|
|
{
|
|
const uint32_t* dirty_transform_indices = args.dirty_transform_indices;
|
|
const uint32_t* parent_transform_indices = args.parent_transform_indices;
|
|
const rtm::qvvf* local_transforms_ = static_cast<const rtm::qvvf*>(args.local_transforms);
|
|
rtm::qvvf* out_object_transforms_ = static_cast<rtm::qvvf*>(out_object_transforms);
|
|
|
|
const uint32_t num_dirty_transforms = args.num_dirty_transforms;
|
|
for (uint32_t dirty_transform_index = 0; dirty_transform_index < num_dirty_transforms; ++dirty_transform_index)
|
|
{
|
|
const uint32_t transform_index = dirty_transform_indices[dirty_transform_index];
|
|
const uint32_t parent_transform_index = parent_transform_indices[transform_index];
|
|
|
|
rtm::qvvf obj_transform;
|
|
if (parent_transform_index == k_invalid_track_index)
|
|
obj_transform = local_transforms_[transform_index]; // Just copy the root as-is, it has no parent and thus local and object space transforms are equal
|
|
else
|
|
obj_transform = rtm::qvv_mul_no_scale(local_transforms_[transform_index], out_object_transforms_[parent_transform_index]);
|
|
|
|
out_object_transforms_[transform_index] = obj_transform;
|
|
}
|
|
}
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK rtm::scalarf RTM_SIMD_CALL calculate_error(const calculate_error_args& args) const override
|
|
{
|
|
const rtm::qvvf& raw_transform_ = *static_cast<const rtm::qvvf*>(args.transform0);
|
|
const rtm::qvvf& lossy_transform_ = *static_cast<const rtm::qvvf*>(args.transform1);
|
|
|
|
// Note that because we have scale, we must measure all three axes
|
|
const rtm::vector4f vtx0 = args.shell_point_x;
|
|
const rtm::vector4f vtx1 = args.shell_point_y;
|
|
const rtm::vector4f vtx2 = args.shell_point_z;
|
|
|
|
const rtm::vector4f raw_vtx0 = rtm::qvv_mul_point3(vtx0, raw_transform_);
|
|
const rtm::vector4f raw_vtx1 = rtm::qvv_mul_point3(vtx1, raw_transform_);
|
|
const rtm::vector4f raw_vtx2 = rtm::qvv_mul_point3(vtx2, raw_transform_);
|
|
|
|
const rtm::vector4f lossy_vtx0 = rtm::qvv_mul_point3(vtx0, lossy_transform_);
|
|
const rtm::vector4f lossy_vtx1 = rtm::qvv_mul_point3(vtx1, lossy_transform_);
|
|
const rtm::vector4f lossy_vtx2 = rtm::qvv_mul_point3(vtx2, lossy_transform_);
|
|
|
|
const rtm::scalarf vtx0_error = rtm::vector_distance3(raw_vtx0, lossy_vtx0);
|
|
const rtm::scalarf vtx1_error = rtm::vector_distance3(raw_vtx1, lossy_vtx1);
|
|
const rtm::scalarf vtx2_error = rtm::vector_distance3(raw_vtx2, lossy_vtx2);
|
|
|
|
return rtm::scalar_max(rtm::scalar_max(vtx0_error, vtx1_error), vtx2_error);
|
|
}
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK rtm::scalarf RTM_SIMD_CALL calculate_error_no_scale(const calculate_error_args& args) const override
|
|
{
|
|
const rtm::qvvf& raw_transform_ = *static_cast<const rtm::qvvf*>(args.transform0);
|
|
const rtm::qvvf& lossy_transform_ = *static_cast<const rtm::qvvf*>(args.transform1);
|
|
|
|
const rtm::vector4f vtx0 = args.shell_point_x;
|
|
const rtm::vector4f vtx1 = args.shell_point_y;
|
|
|
|
const rtm::vector4f raw_vtx0 = rtm::qvv_mul_point3_no_scale(vtx0, raw_transform_);
|
|
const rtm::vector4f raw_vtx1 = rtm::qvv_mul_point3_no_scale(vtx1, raw_transform_);
|
|
|
|
const rtm::vector4f lossy_vtx0 = rtm::qvv_mul_point3_no_scale(vtx0, lossy_transform_);
|
|
const rtm::vector4f lossy_vtx1 = rtm::qvv_mul_point3_no_scale(vtx1, lossy_transform_);
|
|
|
|
const rtm::scalarf vtx0_error = rtm::vector_distance3(raw_vtx0, lossy_vtx0);
|
|
const rtm::scalarf vtx1_error = rtm::vector_distance3(raw_vtx1, lossy_vtx1);
|
|
|
|
return rtm::scalar_max(vtx0_error, vtx1_error);
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Uses a mix of rtm::qvvf and rtm::matrix3x4f arithmetic.
|
|
// The local space error is always calculated with rtm::qvvf arithmetic.
|
|
// The object space error is calculated with rtm::qvvf arithmetic if there is no scale
|
|
// and with rtm::matrix3x4f arithmetic if there is scale.
|
|
// Note that this can cause inaccuracy issues if there are very large or very small
|
|
// scale values.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
class qvvf_matrix3x4f_transform_error_metric : public qvvf_transform_error_metric
|
|
{
|
|
public:
|
|
virtual const char* get_name() const override { return "qvvf_matrix3x4f_transform_error_metric"; }
|
|
|
|
virtual size_t get_transform_size(bool has_scale) const override { return has_scale ? sizeof(rtm::matrix3x4f) : sizeof(rtm::qvvf); }
|
|
virtual bool needs_conversion(bool has_scale) const override { return has_scale; }
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK void convert_transforms(const convert_transforms_args& args, void* out_transforms) const override
|
|
{
|
|
const uint32_t* dirty_transform_indices = args.dirty_transform_indices;
|
|
const rtm::qvvf* transforms_ = args.transforms;
|
|
rtm::matrix3x4f* out_transforms_ = static_cast<rtm::matrix3x4f*>(out_transforms);
|
|
|
|
const uint32_t num_dirty_transforms = args.num_dirty_transforms;
|
|
for (uint32_t dirty_transform_index = 0; dirty_transform_index < num_dirty_transforms; ++dirty_transform_index)
|
|
{
|
|
const uint32_t transform_index = dirty_transform_indices[dirty_transform_index];
|
|
|
|
const rtm::qvvf& transform_qvv = transforms_[transform_index];
|
|
rtm::matrix3x4f transform_mtx = rtm::matrix_from_qvv(transform_qvv);
|
|
|
|
out_transforms_[transform_index] = transform_mtx;
|
|
}
|
|
}
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK void local_to_object_space(const local_to_object_space_args& args, void* out_object_transforms) const override
|
|
{
|
|
const uint32_t* dirty_transform_indices = args.dirty_transform_indices;
|
|
const uint32_t* parent_transform_indices = args.parent_transform_indices;
|
|
const rtm::matrix3x4f* local_transforms_ = static_cast<const rtm::matrix3x4f*>(args.local_transforms);
|
|
rtm::matrix3x4f* out_object_transforms_ = static_cast<rtm::matrix3x4f*>(out_object_transforms);
|
|
|
|
const uint32_t num_dirty_transforms = args.num_dirty_transforms;
|
|
for (uint32_t dirty_transform_index = 0; dirty_transform_index < num_dirty_transforms; ++dirty_transform_index)
|
|
{
|
|
const uint32_t transform_index = dirty_transform_indices[dirty_transform_index];
|
|
const uint32_t parent_transform_index = parent_transform_indices[transform_index];
|
|
|
|
rtm::matrix3x4f obj_transform;
|
|
if (parent_transform_index == k_invalid_track_index)
|
|
obj_transform = local_transforms_[transform_index]; // Just copy the root as-is, it has no parent and thus local and object space transforms are equal
|
|
else
|
|
obj_transform = rtm::matrix_mul(local_transforms_[transform_index], out_object_transforms_[parent_transform_index]);
|
|
|
|
out_object_transforms_[transform_index] = obj_transform;
|
|
}
|
|
}
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK rtm::scalarf RTM_SIMD_CALL calculate_error(const calculate_error_args& args) const override
|
|
{
|
|
const rtm::matrix3x4f& raw_transform_ = *static_cast<const rtm::matrix3x4f*>(args.transform0);
|
|
const rtm::matrix3x4f& lossy_transform_ = *static_cast<const rtm::matrix3x4f*>(args.transform1);
|
|
|
|
// Note that because we have scale, we must measure all three axes
|
|
const rtm::vector4f vtx0 = args.shell_point_x;
|
|
const rtm::vector4f vtx1 = args.shell_point_y;
|
|
const rtm::vector4f vtx2 = args.shell_point_z;
|
|
|
|
const rtm::vector4f raw_vtx0 = rtm::matrix_mul_point3(vtx0, raw_transform_);
|
|
const rtm::vector4f raw_vtx1 = rtm::matrix_mul_point3(vtx1, raw_transform_);
|
|
const rtm::vector4f raw_vtx2 = rtm::matrix_mul_point3(vtx2, raw_transform_);
|
|
|
|
const rtm::vector4f lossy_vtx0 = rtm::matrix_mul_point3(vtx0, lossy_transform_);
|
|
const rtm::vector4f lossy_vtx1 = rtm::matrix_mul_point3(vtx1, lossy_transform_);
|
|
const rtm::vector4f lossy_vtx2 = rtm::matrix_mul_point3(vtx2, lossy_transform_);
|
|
|
|
const rtm::scalarf vtx0_error = rtm::vector_distance3(raw_vtx0, lossy_vtx0);
|
|
const rtm::scalarf vtx1_error = rtm::vector_distance3(raw_vtx1, lossy_vtx1);
|
|
const rtm::scalarf vtx2_error = rtm::vector_distance3(raw_vtx2, lossy_vtx2);
|
|
|
|
return rtm::scalar_max(rtm::scalar_max(vtx0_error, vtx1_error), vtx2_error);
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Uses rtm::qvvf arithmetic for local and object space error.
|
|
// This error metric should be used whenever a clip is additive or relative.
|
|
// Note that this can cause inaccuracy when dealing with shear/skew.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
template<additive_clip_format8 additive_format>
|
|
class additive_qvvf_transform_error_metric : public qvvf_transform_error_metric
|
|
{
|
|
public:
|
|
virtual const char* get_name() const override
|
|
{
|
|
switch (additive_format)
|
|
{
|
|
default:
|
|
case additive_clip_format8::none: return "additive_qvvf_transform_error_metric<none>";
|
|
case additive_clip_format8::relative: return "additive_qvvf_transform_error_metric<relative>";
|
|
case additive_clip_format8::additive0: return "additive_qvvf_transform_error_metric<additive0>";
|
|
case additive_clip_format8::additive1: return "additive_qvvf_transform_error_metric<additive1>";
|
|
}
|
|
}
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK void apply_additive_to_base(const apply_additive_to_base_args& args, void* out_transforms) const override
|
|
{
|
|
const uint32_t* dirty_transform_indices = args.dirty_transform_indices;
|
|
const rtm::qvvf* local_transforms_ = static_cast<const rtm::qvvf*>(args.local_transforms);
|
|
const rtm::qvvf* base_transforms_ = static_cast<const rtm::qvvf*>(args.base_transforms);
|
|
rtm::qvvf* out_transforms_ = static_cast<rtm::qvvf*>(out_transforms);
|
|
|
|
const uint32_t num_dirty_transforms = args.num_dirty_transforms;
|
|
for (uint32_t dirty_transform_index = 0; dirty_transform_index < num_dirty_transforms; ++dirty_transform_index)
|
|
{
|
|
const uint32_t transform_index = dirty_transform_indices[dirty_transform_index];
|
|
|
|
const rtm::qvvf& local_transform = local_transforms_[transform_index];
|
|
const rtm::qvvf& base_transform = base_transforms_[transform_index];
|
|
const rtm::qvvf transform = acl::apply_additive_to_base(additive_format, base_transform, local_transform);
|
|
|
|
out_transforms_[transform_index] = transform;
|
|
}
|
|
}
|
|
|
|
virtual ACL_DISABLE_SECURITY_COOKIE_CHECK void apply_additive_to_base_no_scale(const apply_additive_to_base_args& args, void* out_transforms) const override
|
|
{
|
|
const uint32_t* dirty_transform_indices = args.dirty_transform_indices;
|
|
const rtm::qvvf* local_transforms_ = static_cast<const rtm::qvvf*>(args.local_transforms);
|
|
const rtm::qvvf* base_transforms_ = static_cast<const rtm::qvvf*>(args.base_transforms);
|
|
rtm::qvvf* out_transforms_ = static_cast<rtm::qvvf*>(out_transforms);
|
|
|
|
const uint32_t num_dirty_transforms = args.num_dirty_transforms;
|
|
for (uint32_t dirty_transform_index = 0; dirty_transform_index < num_dirty_transforms; ++dirty_transform_index)
|
|
{
|
|
const uint32_t transform_index = dirty_transform_indices[dirty_transform_index];
|
|
|
|
const rtm::qvvf& local_transform = local_transforms_[transform_index];
|
|
const rtm::qvvf& base_transform = base_transforms_[transform_index];
|
|
const rtm::qvvf transform = acl::apply_additive_to_base_no_scale(additive_format, base_transform, local_transform);
|
|
|
|
out_transforms_[transform_index] = transform;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
ACL_IMPL_FILE_PRAGMA_POP
|