Files
fs2open.github.com/code/model/animation/modelanimation_moveables.cpp
Goober5000andClaude Opus 4.6 3f85d6172a use std::move() for local variables that are copied but not reused (#7308)
* use std::move() for local variables that are copied but not reused

Addresses ~140 Coverity "Variable copied when it could be moved"
defects across 74 files.  Every std::move() targets a local variable
whose value is consumed by push_back, emplace, assignment, lambda
capture, or a function call and is never read again afterward.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* clang: use std::make_shared

* clang: use std::make_unique

* address feedback

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-05-07 14:40:38 +09:00

441 lines
17 KiB
C++

#include "model/animation/modelanimation_moveables.h"
#include "model/animation/modelanimation_segments.h"
namespace animation {
ModelAnimationMoveableOrientation::ModelAnimationMoveableOrientation(std::shared_ptr<ModelAnimationSubmodel> submodel, const angles& defaultOrient) :
m_submodel(std::move(submodel)), m_defaultPosOrient(defaultOrient) { }
void ModelAnimationMoveableOrientation::update(polymodel_instance* pmi, const SCP_vector<std::any>& args) {
if(args.size() < 3){
Error(LOCATION,"Tried updating moveable orientation with too few (%d of 3) arguments!", (int) args.size());
return;
}
auto& anim = m_instances[pmi->id].animation;
try {
auto p = std::any_cast<int>(args[0]), h = std::any_cast<int>(args[1]), b = std::any_cast<int>(args[2]);
anim->forceRecalculate(pmi);
auto& setOrientation = *std::static_pointer_cast<ModelAnimationSegmentSetOrientation>(anim->m_animation);
setOrientation.m_targetAngle = angles{fl_radians((float)p), fl_radians((float)b), fl_radians((float)h)};
anim->start(pmi, ModelAnimationDirection::FWD);
}
catch (const std::bad_any_cast& e){
Error(LOCATION, "Argument error trying to update orientation moveable: %s", e.what());
}
}
void ModelAnimationMoveableOrientation::initialize(ModelAnimationSet* parentSet, polymodel_instance* pmi) {
auto& anim = m_instances[pmi->id].animation;
anim = std::make_shared<ModelAnimation>(false, false, true, parentSet);
anim->setAnimation(std::make_shared<ModelAnimationSegmentSetOrientation>(parentSet->getSubmodel(m_submodel), m_defaultPosOrient, ModelAnimationCoordinateRelation::RELATIVE_COORDS));
anim->start(pmi,ModelAnimationDirection::FWD);
}
std::shared_ptr<ModelAnimationMoveable> ModelAnimationMoveableOrientation::parser() {
required_string("+Angle:");
angles angle;
stuff_angles_deg_phb(&angle);
auto submodel = ModelAnimationParseHelper::parseSubmodel();
if(submodel == nullptr)
error_display(1, "Could not create moveable! Moveable Orientation has no target submodel!");
return std::make_shared<ModelAnimationMoveableOrientation>(std::move(submodel), angle);
}
ModelAnimationMoveableRotation::ModelAnimationMoveableRotation(std::shared_ptr<ModelAnimationSubmodel> submodel, const angles& defaultOrient, const angles& velocity, const std::optional<angles>& acceleration) :
m_submodel(std::move(submodel)), m_defaultPosOrient(defaultOrient), m_velocity(velocity), m_acceleration(acceleration) { }
void ModelAnimationMoveableRotation::update(polymodel_instance* pmi, const SCP_vector<std::any>& args) {
if(args.size() < 3){
Error(LOCATION,"Tried updating moveable rotation with too few (%d of 3) arguments!", (int) args.size());
return;
}
auto& anim = m_instances[pmi->id].animation;
try {
auto p = std::any_cast<int>(args[0]), h = std::any_cast<int>(args[1]), b = std::any_cast<int>(args[2]);
auto& sequence = *std::static_pointer_cast<ModelAnimationSegmentSerial>(anim->m_animation);
auto& setOrientation = *std::static_pointer_cast<ModelAnimationSegmentSetOrientation>(sequence.m_segments[0]);
auto& rotation = *std::static_pointer_cast<ModelAnimationSegmentRotation>(sequence.m_segments[1]);
ModelAnimationSubmodelBuffer buffer;
buffer[rotation.m_submodel].data.orientation = IDENTITY_MATRIX;
//Will now only contain the delta of the rotation
anim->m_animation->calculateAnimation(buffer, anim->getTime(pmi->id), pmi->id);
anim->forceRecalculate(pmi);
setOrientation.m_targetOrientation = buffer[rotation.m_submodel].data.orientation;
rotation.m_targetAngle = angles{fl_radians((float)p), fl_radians((float)b), fl_radians((float)h)};
anim->start(pmi, ModelAnimationDirection::FWD);
}
catch (const std::bad_any_cast& e){
Error(LOCATION, "Argument error trying to update rotation moveable: %s", e.what());
}
}
void ModelAnimationMoveableRotation::initialize(ModelAnimationSet* parentSet, polymodel_instance* pmi) {
auto& anim = m_instances[pmi->id].animation;
anim = std::make_shared<ModelAnimation>(false, false, true, parentSet);
matrix orient;
vm_angles_2_matrix(&orient, &m_defaultPosOrient);
auto submodel = parentSet->getSubmodel(m_submodel);
auto sequence = std::make_shared<ModelAnimationSegmentSerial>();
sequence->addSegment(std::make_shared<ModelAnimationSegmentSetOrientation>(submodel, orient, ModelAnimationCoordinateRelation::RELATIVE_COORDS));
sequence->addSegment(std::make_shared<ModelAnimationSegmentRotation>(std::move(submodel), m_defaultPosOrient, m_velocity, std::nullopt, m_acceleration, ModelAnimationCoordinateRelation::ABSOLUTE_COORDS));
anim->setAnimation(sequence);
anim->start(pmi,ModelAnimationDirection::FWD);
}
std::shared_ptr<ModelAnimationMoveable> ModelAnimationMoveableRotation::parser() {
required_string("+Angle:");
angles angle;
stuff_angles_deg_phb(&angle);
required_string("+Velocity:");
angles velocity;
stuff_angles_deg_phb(&velocity);
std::optional<angles> acceleration;
if (optional_string("+Acceleration:")) {
angles parse;
stuff_angles_deg_phb(&parse);
acceleration = parse;
}
auto submodel = ModelAnimationParseHelper::parseSubmodel();
if(submodel == nullptr)
error_display(1, "Could not create moveable! Moveable Rotation has no target submodel!");
return std::make_shared<ModelAnimationMoveableRotation>(std::move(submodel), angle, velocity, acceleration);
}
ModelAnimationMoveableTranslation::ModelAnimationMoveableTranslation(std::shared_ptr<ModelAnimationSubmodel> submodel, const vec3d& defaultOffset, const vec3d& velocity, const std::optional<vec3d>& acceleration) :
m_submodel(std::move(submodel)), m_defaultOffset(defaultOffset), m_velocity(velocity), m_acceleration(acceleration) { }
void ModelAnimationMoveableTranslation::update(polymodel_instance* pmi, const SCP_vector<std::any>& args) {
if(args.size() < 3){
Error(LOCATION,"Tried updating moveable translation with too few (%d of 3) arguments!", (int) args.size());
return;
}
auto& anim = m_instances[pmi->id].animation;
try {
auto x = std::any_cast<int>(args[0]), y = std::any_cast<int>(args[1]), z = std::any_cast<int>(args[2]);
auto& sequence = *std::static_pointer_cast<ModelAnimationSegmentSerial>(anim->m_animation);
auto& setOffset = *std::static_pointer_cast<ModelAnimationSegmentSetOffset>(sequence.m_segments[0]);
auto& translation = *std::static_pointer_cast<ModelAnimationSegmentTranslation>(sequence.m_segments[1]);
ModelAnimationSubmodelBuffer buffer;
buffer[translation.m_submodel].data.position = ZERO_VECTOR;
//Will now only contain the delta of the translation
anim->m_animation->calculateAnimation(buffer, anim->getTime(pmi->id), pmi->id);
anim->forceRecalculate(pmi);
setOffset.m_target = buffer[translation.m_submodel].data.position;
translation.m_target = vec3d{{{x * 0.01f, y * 0.01f, z * 0.01f}}};
anim->start(pmi, ModelAnimationDirection::FWD);
}
catch (const std::bad_any_cast& e){
Error(LOCATION, "Argument error trying to update translation moveable: %s", e.what());
}
}
void ModelAnimationMoveableTranslation::initialize(ModelAnimationSet* parentSet, polymodel_instance* pmi) {
auto& anim = m_instances[pmi->id].animation;
anim = std::make_shared<ModelAnimation>(false, false, true, parentSet);
auto submodel = parentSet->getSubmodel(m_submodel);
auto sequence = std::make_shared<ModelAnimationSegmentSerial>();
sequence->addSegment(std::make_shared<ModelAnimationSegmentSetOffset>(submodel, m_defaultOffset, ModelAnimationCoordinateRelation::RELATIVE_COORDS));
sequence->addSegment(std::make_shared<ModelAnimationSegmentTranslation>(std::move(submodel), m_defaultOffset, m_velocity, std::nullopt, m_acceleration, ModelAnimationSegmentTranslation::CoordinateSystem::COORDS_PARENT, ModelAnimationCoordinateRelation::ABSOLUTE_COORDS));
anim->setAnimation(sequence);
anim->start(pmi,ModelAnimationDirection::FWD);
}
std::shared_ptr<ModelAnimationMoveable> ModelAnimationMoveableTranslation::parser() {
required_string("+Target:");
vec3d angle;
stuff_vec3d(&angle);
required_string("+Velocity:");
vec3d velocity;
stuff_vec3d(&velocity);
std::optional<vec3d> acceleration;
if (optional_string("+Acceleration:")) {
vec3d parse;
stuff_vec3d(&parse);
acceleration = parse;
}
auto submodel = ModelAnimationParseHelper::parseSubmodel();
if(submodel == nullptr)
error_display(1, "Could not create moveable! Moveable Translation has no target submodel!");
return std::make_shared<ModelAnimationMoveableTranslation>(std::move(submodel), angle, velocity, acceleration);
}
ModelAnimationMoveableAxisRotation::ModelAnimationMoveableAxisRotation(std::shared_ptr<ModelAnimationSubmodel> submodel, const float& velocity, const std::optional<float>& acceleration, const vec3d& axis) :
m_submodel(std::move(submodel)), m_velocity(velocity), m_acceleration(acceleration), m_axis(axis) { }
void ModelAnimationMoveableAxisRotation::update(polymodel_instance* pmi, const SCP_vector<std::any>& args) {
if(args.empty()){
Error(LOCATION,"Tried updating moveable axis rotation with too few (%d of 1) arguments!", (int) args.size());
return;
}
auto& anim = m_instances[pmi->id].animation;
try {
auto ang = std::any_cast<int>(args[0]);
auto& sequence = *std::static_pointer_cast<ModelAnimationSegmentSerial>(anim->m_animation);
auto& setOrientation = *std::static_pointer_cast<ModelAnimationSegmentSetOrientation>(sequence.m_segments[0]);
auto& rotation = *std::static_pointer_cast<ModelAnimationSegmentAxisRotation>(sequence.m_segments[1]);
ModelAnimationSubmodelBuffer buffer;
buffer[rotation.m_submodel].data.orientation = IDENTITY_MATRIX;
//Will now only contain the delta of the rotation
sequence.m_segments[1]->calculateAnimation(buffer, anim->getTime(pmi->id), pmi->id);
anim->forceRecalculate(pmi);
matrix startOrient = *setOrientation.m_targetOrientation;
matrix newOrient;
//Apply rotation to old default state
vm_matrix_x_matrix(&newOrient, &startOrient, &buffer[rotation.m_submodel].data.orientation);
setOrientation.m_targetOrientation = newOrient;
float currentAngle;
vm_closest_angle_to_matrix(&newOrient, &m_axis, &currentAngle);
//CurrentAngle is 0 to 2Pi, convert to -pi to pi
if (currentAngle > PI)
currentAngle -= PI2;
rotation.m_targetAngle = fl_radians((float)ang) - currentAngle;
anim->start(pmi, ModelAnimationDirection::FWD);
}
catch(const std::bad_any_cast& e){
Error(LOCATION, "Argument error trying to update rotation moveable: %s", e.what());
}
}
void ModelAnimationMoveableAxisRotation::initialize(ModelAnimationSet* parentSet, polymodel_instance* pmi) {
auto& anim = m_instances[pmi->id].animation;
anim = std::make_shared<ModelAnimation>(false, false, true, parentSet);
auto submodel = parentSet->getSubmodel(m_submodel);
auto sequence = std::make_shared<ModelAnimationSegmentSerial>();
sequence->addSegment(std::make_shared<ModelAnimationSegmentSetOrientation>(submodel, vmd_identity_matrix, ModelAnimationCoordinateRelation::RELATIVE_COORDS));
sequence->addSegment(std::make_shared<ModelAnimationSegmentAxisRotation>(std::move(submodel), 0.0f, m_velocity, std::nullopt, m_acceleration, m_axis));
anim->setAnimation(sequence);
anim->start(pmi,ModelAnimationDirection::FWD);
}
std::shared_ptr<ModelAnimationMoveable> ModelAnimationMoveableAxisRotation::parser() {
required_string("+Axis:");
vec3d axis;
stuff_vec3d(&axis);
required_string("+Velocity:");
float velocity;
stuff_float(&velocity);
velocity = fl_radians(velocity);
std::optional<float> acceleration;
if (optional_string("+Acceleration:")) {
float parse;
stuff_float(&parse);
acceleration = fl_radians(parse);
}
auto submodel = ModelAnimationParseHelper::parseSubmodel();
if(submodel == nullptr)
error_display(1, "Could not create moveable! Moveable Axis Rotation has no target submodel!");
return std::make_shared<ModelAnimationMoveableAxisRotation>(std::move(submodel), velocity, acceleration, axis);
}
ModelAnimationMoveableIK::ModelAnimationMoveableIK(std::vector<moveable_chainlink> chain, float time) :
m_time(time), m_chain(std::move(chain)) { }
void ModelAnimationMoveableIK::update(polymodel_instance* pmi, const SCP_vector<std::any>& args) {
if(args.size() < 3){
Error(LOCATION,"Tried updating moveable IK with too few (%d of 3) arguments!", (int) args.size());
return;
}
auto& anim = m_instances[pmi->id].animation;
try {
auto x = std::any_cast<int>(args[0]), y = std::any_cast<int>(args[1]), z = std::any_cast<int>(args[2]);
std::optional<matrix> orient;
if(args.size() >= 6 && args[3].type() == typeid(int)) {
auto p = std::any_cast<int>(args[3]), h = std::any_cast<int>(args[4]), b = std::any_cast<int>(args[5]);
matrix rot;
angles ang{ fl_radians(p), fl_radians(b), fl_radians(h) };
vm_angles_2_matrix(&rot, &ang);
orient = rot;
}
auto& sequence = *std::static_pointer_cast<ModelAnimationSegmentSerial>(anim->m_animation);
auto& setOrientationParallel = *std::static_pointer_cast<ModelAnimationSegmentParallel>(sequence.m_segments[0]);
auto& ik = *std::static_pointer_cast<ModelAnimationSegmentIK>(sequence.m_segments[1]);
ModelAnimationSubmodelBuffer buffer;
for(const auto& segment : setOrientationParallel.m_segments){
auto& orientation = *std::static_pointer_cast<ModelAnimationSegmentSetOrientation>(segment);
buffer[orientation.m_submodel].data.orientation = IDENTITY_MATRIX;
}
//Will now only contain the delta of the IK
anim->m_animation->calculateAnimation(buffer, anim->getTime(pmi->id), pmi->id);
anim->forceRecalculate(pmi);
for(const auto& segment : setOrientationParallel.m_segments){
auto& orientation = *std::static_pointer_cast<ModelAnimationSegmentSetOrientation>(segment);
orientation.m_targetOrientation = buffer[orientation.m_submodel].data.orientation;
}
ik.m_targetRotation = orient;
ik.m_targetPosition = vec3d{{{x * 0.01f, y * 0.01f, z * 0.01f}}};
anim->start(pmi, ModelAnimationDirection::FWD);
}
catch(const std::bad_any_cast& e){
Error(LOCATION, "Argument error trying to update rotation moveable: %s", e.what());
}
}
void ModelAnimationMoveableIK::initialize(ModelAnimationSet* parentSet, polymodel_instance* pmi) {
auto& anim = m_instances[pmi->id].animation;
anim = std::make_shared<ModelAnimation>(false, false, true, parentSet);
auto sequence = std::make_shared<ModelAnimationSegmentSerial>();
auto parallelSetOrient = std::make_shared<ModelAnimationSegmentParallel>();
for(const auto& link : m_chain) {
auto submodel = parentSet->getSubmodel(link.submodel);
parallelSetOrient->addSegment(std::make_shared<ModelAnimationSegmentSetOrientation>(submodel, vmd_identity_matrix, ModelAnimationCoordinateRelation::RELATIVE_COORDS));
}
sequence->addSegment(parallelSetOrient);
auto parallelIK = std::make_shared<ModelAnimationSegmentParallel>();
vec3d startPos = ZERO_VECTOR;
for(size_t i = 1; i < m_chain.size(); ++i) {
startPos += parentSet->getSubmodel(m_chain[i].submodel)->findSubmodel(pmi).second->offset;
}
auto segment = std::make_shared<ModelAnimationSegmentIK>(startPos, std::nullopt);
segment->m_segment = parallelIK;
for(const auto& link : m_chain) {
auto submodel = parentSet->getSubmodel(link.submodel);
auto rotation = std::make_shared<ModelAnimationSegmentRotation>(submodel, std::optional<angles>({0,0,0}), std::nullopt, m_time, link.acceleration, ModelAnimationCoordinateRelation::ABSOLUTE_COORDS);
parallelIK->addSegment(rotation);
segment->m_chain.push_back({submodel, link.constraint, std::move(rotation)});
}
sequence->addSegment(segment);
anim->setAnimation(sequence);
anim->start(pmi,ModelAnimationDirection::FWD);
}
std::shared_ptr<ModelAnimationMoveable> ModelAnimationMoveableIK::parser() {
required_string("+Time:");
float time;
stuff_float(&time);
std::vector<moveable_chainlink> chain;
while (optional_string("$Chain Link:")) {
auto submodel = ModelAnimationParseHelper::parseSubmodel();
std::optional<angles> acceleration;
if (optional_string("+Acceleration:")) {
angles accel;
stuff_angles_deg_phb(&accel);
acceleration = accel;
}
std::shared_ptr<ik_constraint> constraint;
if (optional_string("+Constraint:")) {
int type = required_string_one_of(2, "Window", "Hinge");
switch (type) {
case 0: { //Window
angles window;
required_string("Window");
required_string("+Window Size:");
stuff_angles_deg_phb(&window);
constraint = std::make_shared<ik_constraint_window>(window);
break;
}
case 1: { //Hinge
vec3d axis;
required_string("Hinge");
required_string("+Axis:");
stuff_vec3d(&axis);
vm_vec_normalize(&axis);
constraint = std::make_shared<ik_constraint_hinge>(axis);
break;
}
default:
UNREACHABLE("IK constraint of unknown type specified!");
break;
}
} else
constraint = std::make_shared<ik_constraint>();
chain.push_back({std::move(submodel), std::move(constraint), acceleration});
}
return std::make_shared<ModelAnimationMoveableIK>(std::move(chain), time);
}
}