Path: blob/master/scene/3d/copy_transform_modifier_3d.cpp
9896 views
/**************************************************************************/1/* copy_transform_modifier_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "copy_transform_modifier_3d.h"3132bool CopyTransformModifier3D::_set(const StringName &p_path, const Variant &p_value) {33String path = p_path;3435if (path.begins_with("settings/")) {36int which = path.get_slicec('/', 1).to_int();37String what = path.get_slicec('/', 2);38ERR_FAIL_INDEX_V(which, settings.size(), false);3940if (what == "copy") {41set_copy_flags(which, static_cast<BitField<TransformFlag>>((int)p_value));42} else if (what == "axes") {43set_axis_flags(which, static_cast<BitField<AxisFlag>>((int)p_value));44} else if (what == "invert") {45set_invert_flags(which, static_cast<BitField<AxisFlag>>((int)p_value));46} else if (what == "relative") {47set_relative(which, p_value);48} else if (what == "additive") {49set_additive(which, p_value);50} else {51return false;52}53}54return true;55}5657bool CopyTransformModifier3D::_get(const StringName &p_path, Variant &r_ret) const {58String path = p_path;5960if (path.begins_with("settings/")) {61int which = path.get_slicec('/', 1).to_int();62String what = path.get_slicec('/', 2);63ERR_FAIL_INDEX_V(which, settings.size(), false);6465if (what == "copy") {66r_ret = (int)get_copy_flags(which);67} else if (what == "axes") {68r_ret = (int)get_axis_flags(which);69} else if (what == "invert") {70r_ret = (int)get_invert_flags(which);71} else if (what == "relative") {72r_ret = is_relative(which);73} else if (what == "additive") {74r_ret = is_additive(which);75} else {76return false;77}78}79return true;80}8182void CopyTransformModifier3D::_get_property_list(List<PropertyInfo> *p_list) const {83BoneConstraint3D::get_property_list(p_list);8485for (int i = 0; i < settings.size(); i++) {86String path = "settings/" + itos(i) + "/";87p_list->push_back(PropertyInfo(Variant::INT, path + "copy", PROPERTY_HINT_FLAGS, "Position,Rotation,Scale"));88p_list->push_back(PropertyInfo(Variant::INT, path + "axes", PROPERTY_HINT_FLAGS, "X,Y,Z"));89p_list->push_back(PropertyInfo(Variant::INT, path + "invert", PROPERTY_HINT_FLAGS, "X,Y,Z"));90p_list->push_back(PropertyInfo(Variant::BOOL, path + "relative"));91p_list->push_back(PropertyInfo(Variant::BOOL, path + "additive"));92}93}9495void CopyTransformModifier3D::_validate_setting(int p_index) {96settings.write[p_index] = memnew(CopyTransform3DSetting);97}9899void CopyTransformModifier3D::set_copy_flags(int p_index, BitField<TransformFlag> p_copy_flags) {100ERR_FAIL_INDEX(p_index, settings.size());101CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);102setting->copy_flags = p_copy_flags;103notify_property_list_changed();104}105106BitField<CopyTransformModifier3D::TransformFlag> CopyTransformModifier3D::get_copy_flags(int p_index) const {107ERR_FAIL_INDEX_V(p_index, settings.size(), 0);108CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);109return setting->copy_flags;110}111112void CopyTransformModifier3D::set_axis_flags(int p_index, BitField<AxisFlag> p_axis_flags) {113ERR_FAIL_INDEX(p_index, settings.size());114CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);115setting->axis_flags = p_axis_flags;116notify_property_list_changed();117}118119BitField<CopyTransformModifier3D::AxisFlag> CopyTransformModifier3D::get_axis_flags(int p_index) const {120ERR_FAIL_INDEX_V(p_index, settings.size(), 0);121CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);122return setting->axis_flags;123}124125void CopyTransformModifier3D::set_invert_flags(int p_index, BitField<AxisFlag> p_axis_flags) {126ERR_FAIL_INDEX(p_index, settings.size());127CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);128setting->invert_flags = p_axis_flags;129notify_property_list_changed();130}131132BitField<CopyTransformModifier3D::AxisFlag> CopyTransformModifier3D::get_invert_flags(int p_index) const {133ERR_FAIL_INDEX_V(p_index, settings.size(), false);134CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);135return setting->invert_flags;136}137138void CopyTransformModifier3D::set_copy_position(int p_index, bool p_enabled) {139ERR_FAIL_INDEX(p_index, settings.size());140CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);141if (p_enabled) {142setting->copy_flags.set_flag(TRANSFORM_FLAG_POSITION);143} else {144setting->copy_flags.clear_flag(TRANSFORM_FLAG_POSITION);145}146}147148bool CopyTransformModifier3D::is_position_copying(int p_index) const {149ERR_FAIL_INDEX_V(p_index, settings.size(), false);150CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);151return setting->copy_flags.has_flag(TRANSFORM_FLAG_POSITION);152}153154void CopyTransformModifier3D::set_copy_rotation(int p_index, bool p_enabled) {155ERR_FAIL_INDEX(p_index, settings.size());156CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);157if (p_enabled) {158setting->copy_flags.set_flag(TRANSFORM_FLAG_ROTATION);159} else {160setting->copy_flags.clear_flag(TRANSFORM_FLAG_ROTATION);161}162}163164bool CopyTransformModifier3D::is_rotation_copying(int p_index) const {165ERR_FAIL_INDEX_V(p_index, settings.size(), false);166CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);167return setting->copy_flags.has_flag(TRANSFORM_FLAG_ROTATION);168}169170void CopyTransformModifier3D::set_copy_scale(int p_index, bool p_enabled) {171ERR_FAIL_INDEX(p_index, settings.size());172CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);173if (p_enabled) {174setting->copy_flags.set_flag(TRANSFORM_FLAG_SCALE);175} else {176setting->copy_flags.clear_flag(TRANSFORM_FLAG_SCALE);177}178}179180bool CopyTransformModifier3D::is_scale_copying(int p_index) const {181ERR_FAIL_INDEX_V(p_index, settings.size(), false);182CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);183return setting->copy_flags.has_flag(TRANSFORM_FLAG_SCALE);184}185186void CopyTransformModifier3D::set_axis_x_enabled(int p_index, bool p_enabled) {187ERR_FAIL_INDEX(p_index, settings.size());188CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);189if (p_enabled) {190setting->axis_flags.set_flag(AXIS_FLAG_X);191} else {192setting->axis_flags.clear_flag(AXIS_FLAG_X);193}194}195196bool CopyTransformModifier3D::is_axis_x_enabled(int p_index) const {197ERR_FAIL_INDEX_V(p_index, settings.size(), false);198CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);199return setting->axis_flags.has_flag(AXIS_FLAG_X);200}201202void CopyTransformModifier3D::set_axis_y_enabled(int p_index, bool p_enabled) {203ERR_FAIL_INDEX(p_index, settings.size());204CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);205if (p_enabled) {206setting->axis_flags.set_flag(AXIS_FLAG_Y);207} else {208setting->axis_flags.clear_flag(AXIS_FLAG_Y);209}210}211212bool CopyTransformModifier3D::is_axis_y_enabled(int p_index) const {213ERR_FAIL_INDEX_V(p_index, settings.size(), false);214CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);215return setting->axis_flags.has_flag(AXIS_FLAG_Y);216}217218void CopyTransformModifier3D::set_axis_z_enabled(int p_index, bool p_enabled) {219ERR_FAIL_INDEX(p_index, settings.size());220CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);221if (p_enabled) {222setting->axis_flags.set_flag(AXIS_FLAG_Z);223} else {224setting->axis_flags.clear_flag(AXIS_FLAG_Z);225}226}227228bool CopyTransformModifier3D::is_axis_z_enabled(int p_index) const {229ERR_FAIL_INDEX_V(p_index, settings.size(), false);230CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);231return setting->axis_flags.has_flag(AXIS_FLAG_Z);232}233234void CopyTransformModifier3D::set_axis_x_inverted(int p_index, bool p_enabled) {235ERR_FAIL_INDEX(p_index, settings.size());236CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);237if (p_enabled) {238setting->invert_flags.set_flag(AXIS_FLAG_X);239} else {240setting->invert_flags.clear_flag(AXIS_FLAG_X);241}242}243244bool CopyTransformModifier3D::is_axis_x_inverted(int p_index) const {245ERR_FAIL_INDEX_V(p_index, settings.size(), false);246CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);247return setting->invert_flags.has_flag(AXIS_FLAG_X);248}249250void CopyTransformModifier3D::set_axis_y_inverted(int p_index, bool p_enabled) {251ERR_FAIL_INDEX(p_index, settings.size());252CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);253if (p_enabled) {254setting->invert_flags.set_flag(AXIS_FLAG_Y);255} else {256setting->invert_flags.clear_flag(AXIS_FLAG_Y);257}258}259260bool CopyTransformModifier3D::is_axis_y_inverted(int p_index) const {261ERR_FAIL_INDEX_V(p_index, settings.size(), false);262CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);263return setting->invert_flags.has_flag(AXIS_FLAG_Y);264}265266void CopyTransformModifier3D::set_axis_z_inverted(int p_index, bool p_enabled) {267ERR_FAIL_INDEX(p_index, settings.size());268CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);269if (p_enabled) {270setting->invert_flags.set_flag(AXIS_FLAG_Z);271} else {272setting->invert_flags.clear_flag(AXIS_FLAG_Z);273}274}275276bool CopyTransformModifier3D::is_axis_z_inverted(int p_index) const {277ERR_FAIL_INDEX_V(p_index, settings.size(), false);278CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);279return setting->invert_flags.has_flag(AXIS_FLAG_Z);280}281282void CopyTransformModifier3D::set_relative(int p_index, bool p_enabled) {283ERR_FAIL_INDEX(p_index, settings.size());284CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);285setting->relative = p_enabled;286}287288bool CopyTransformModifier3D::is_relative(int p_index) const {289ERR_FAIL_INDEX_V(p_index, settings.size(), 0);290CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);291return setting->relative;292}293294void CopyTransformModifier3D::set_additive(int p_index, bool p_enabled) {295ERR_FAIL_INDEX(p_index, settings.size());296CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);297setting->additive = p_enabled;298}299300bool CopyTransformModifier3D::is_additive(int p_index) const {301ERR_FAIL_INDEX_V(p_index, settings.size(), 0);302CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);303return setting->additive;304}305306void CopyTransformModifier3D::_bind_methods() {307ClassDB::bind_method(D_METHOD("set_copy_flags", "index", "copy_flags"), &CopyTransformModifier3D::set_copy_flags);308ClassDB::bind_method(D_METHOD("get_copy_flags", "index"), &CopyTransformModifier3D::get_copy_flags);309ClassDB::bind_method(D_METHOD("set_axis_flags", "index", "axis_flags"), &CopyTransformModifier3D::set_axis_flags);310ClassDB::bind_method(D_METHOD("get_axis_flags", "index"), &CopyTransformModifier3D::get_axis_flags);311ClassDB::bind_method(D_METHOD("set_invert_flags", "index", "axis_flags"), &CopyTransformModifier3D::set_invert_flags);312ClassDB::bind_method(D_METHOD("get_invert_flags", "index"), &CopyTransformModifier3D::get_invert_flags);313314ClassDB::bind_method(D_METHOD("set_copy_position", "index", "enabled"), &CopyTransformModifier3D::set_copy_position);315ClassDB::bind_method(D_METHOD("is_position_copying", "index"), &CopyTransformModifier3D::is_position_copying);316ClassDB::bind_method(D_METHOD("set_copy_rotation", "index", "enabled"), &CopyTransformModifier3D::set_copy_rotation);317ClassDB::bind_method(D_METHOD("is_rotation_copying", "index"), &CopyTransformModifier3D::is_rotation_copying);318ClassDB::bind_method(D_METHOD("set_copy_scale", "index", "enabled"), &CopyTransformModifier3D::set_copy_scale);319ClassDB::bind_method(D_METHOD("is_scale_copying", "index"), &CopyTransformModifier3D::is_scale_copying);320321ClassDB::bind_method(D_METHOD("set_axis_x_enabled", "index", "enabled"), &CopyTransformModifier3D::set_axis_x_enabled);322ClassDB::bind_method(D_METHOD("is_axis_x_enabled", "index"), &CopyTransformModifier3D::is_axis_x_enabled);323ClassDB::bind_method(D_METHOD("set_axis_y_enabled", "index", "enabled"), &CopyTransformModifier3D::set_axis_y_enabled);324ClassDB::bind_method(D_METHOD("is_axis_y_enabled", "index"), &CopyTransformModifier3D::is_axis_y_enabled);325ClassDB::bind_method(D_METHOD("set_axis_z_enabled", "index", "enabled"), &CopyTransformModifier3D::set_axis_z_enabled);326ClassDB::bind_method(D_METHOD("is_axis_z_enabled", "index"), &CopyTransformModifier3D::is_axis_z_enabled);327328ClassDB::bind_method(D_METHOD("set_axis_x_inverted", "index", "enabled"), &CopyTransformModifier3D::set_axis_x_inverted);329ClassDB::bind_method(D_METHOD("is_axis_x_inverted", "index"), &CopyTransformModifier3D::is_axis_x_inverted);330ClassDB::bind_method(D_METHOD("set_axis_y_inverted", "index", "enabled"), &CopyTransformModifier3D::set_axis_y_inverted);331ClassDB::bind_method(D_METHOD("is_axis_y_inverted", "index"), &CopyTransformModifier3D::is_axis_y_inverted);332ClassDB::bind_method(D_METHOD("set_axis_z_inverted", "index", "enabled"), &CopyTransformModifier3D::set_axis_z_inverted);333ClassDB::bind_method(D_METHOD("is_axis_z_inverted", "index"), &CopyTransformModifier3D::is_axis_z_inverted);334335ClassDB::bind_method(D_METHOD("set_relative", "index", "enabled"), &CopyTransformModifier3D::set_relative);336ClassDB::bind_method(D_METHOD("is_relative", "index"), &CopyTransformModifier3D::is_relative);337ClassDB::bind_method(D_METHOD("set_additive", "index", "enabled"), &CopyTransformModifier3D::set_additive);338ClassDB::bind_method(D_METHOD("is_additive", "index"), &CopyTransformModifier3D::is_additive);339340ADD_ARRAY_COUNT("Settings", "setting_count", "set_setting_count", "get_setting_count", "settings/");341342BIND_BITFIELD_FLAG(TRANSFORM_FLAG_POSITION);343BIND_BITFIELD_FLAG(TRANSFORM_FLAG_ROTATION);344BIND_BITFIELD_FLAG(TRANSFORM_FLAG_SCALE);345BIND_BITFIELD_FLAG(TRANSFORM_FLAG_ALL);346347BIND_BITFIELD_FLAG(AXIS_FLAG_X);348BIND_BITFIELD_FLAG(AXIS_FLAG_Y);349BIND_BITFIELD_FLAG(AXIS_FLAG_Z);350BIND_BITFIELD_FLAG(AXIS_FLAG_ALL);351}352353void CopyTransformModifier3D::_process_constraint(int p_index, Skeleton3D *p_skeleton, int p_apply_bone, int p_reference_bone, float p_amount) {354CopyTransform3DSetting *setting = static_cast<CopyTransform3DSetting *>(settings[p_index]);355356Transform3D destination = p_skeleton->get_bone_pose(p_reference_bone);357if (setting->relative) {358Vector3 scl_relative = destination.basis.get_scale() / p_skeleton->get_bone_rest(p_reference_bone).basis.get_scale();359destination.basis = p_skeleton->get_bone_rest(p_reference_bone).basis.get_rotation_quaternion().inverse() * destination.basis.get_rotation_quaternion();360destination.basis.scale_local(scl_relative);361destination.origin = destination.origin - p_skeleton->get_bone_rest(p_reference_bone).origin;362}363Vector3 dest_pos = destination.origin;364Quaternion dest_rot = destination.basis.get_rotation_quaternion();365Vector3 dest_scl = destination.basis.get_scale();366367// Mask pos and scale.368for (int i = 0; i < 3; i++) {369if (!setting->axis_flags.has_flag(static_cast<AxisFlag>(1 << i))) {370dest_pos[i] = 0.0;371dest_scl[i] = 1.0;372}373}374375// Mask rot.376switch (static_cast<int>(setting->axis_flags)) {377case 0: {378dest_rot = Quaternion();379} break;380case AXIS_FLAG_X: {381Vector3 axis = get_vector_from_axis(Vector3::AXIS_X);382dest_rot = Quaternion(axis, get_roll_angle(dest_rot, axis));383} break;384case AXIS_FLAG_Y: {385Vector3 axis = get_vector_from_axis(Vector3::AXIS_Y);386dest_rot = Quaternion(axis, get_roll_angle(dest_rot, axis));387} break;388case AXIS_FLAG_Z: {389Vector3 axis = get_vector_from_axis(Vector3::AXIS_Z);390dest_rot = Quaternion(axis, get_roll_angle(dest_rot, axis));391} break;392case AXIS_FLAG_X | AXIS_FLAG_Y: {393Vector3 axis = get_vector_from_axis(Vector3::AXIS_Z);394dest_rot = dest_rot * Quaternion(axis, get_roll_angle(dest_rot, axis)).inverse();395} break;396case AXIS_FLAG_Y | AXIS_FLAG_Z: {397Vector3 axis = get_vector_from_axis(Vector3::AXIS_X);398dest_rot = dest_rot * Quaternion(axis, get_roll_angle(dest_rot, axis)).inverse();399} break;400case AXIS_FLAG_Z | AXIS_FLAG_X: {401Vector3 axis = get_vector_from_axis(Vector3::AXIS_Y);402dest_rot = dest_rot * Quaternion(axis, get_roll_angle(dest_rot, axis)).inverse();403} break;404case AXIS_FLAG_ALL: {405} break;406}407408// Process inversion.409for (int i = 0; i < 3; i++) {410AxisFlag axis = static_cast<AxisFlag>(1 << i);411if (setting->axis_flags.has_flag(axis) && setting->invert_flags.has_flag(axis)) {412dest_pos[i] *= -1;413dest_rot[i] *= -1;414dest_scl[i] = 1.0 / dest_scl[i];415}416}417dest_rot.normalize();418419if (setting->additive) {420destination.origin = p_skeleton->get_bone_pose_position(p_apply_bone) + dest_pos;421destination.basis = p_skeleton->get_bone_pose_rotation(p_apply_bone) * Basis(dest_rot);422destination.basis.scale_local(p_skeleton->get_bone_pose_scale(p_apply_bone) * dest_scl);423} else if (setting->relative) {424Transform3D rest = p_skeleton->get_bone_rest(p_apply_bone);425destination.origin = rest.origin + dest_pos;426destination.basis = rest.basis.get_rotation_quaternion() * Basis(dest_rot);427destination.basis.scale_local(rest.basis.get_scale() * dest_scl);428} else {429destination.origin = dest_pos;430destination.basis = Basis(dest_rot);431destination.basis.scale_local(dest_scl);432}433434// Process interpolation depends on the amount.435destination = p_skeleton->get_bone_pose(p_apply_bone).interpolate_with(destination, p_amount);436437// Apply transform depends on the element mask.438if (setting->copy_flags.has_flag(TRANSFORM_FLAG_POSITION)) {439p_skeleton->set_bone_pose_position(p_apply_bone, destination.origin);440}441if (setting->copy_flags.has_flag(TRANSFORM_FLAG_ROTATION)) {442p_skeleton->set_bone_pose_rotation(p_apply_bone, destination.basis.get_rotation_quaternion());443}444if (setting->copy_flags.has_flag(TRANSFORM_FLAG_SCALE)) {445p_skeleton->set_bone_pose_scale(p_apply_bone, destination.basis.get_scale());446}447}448449CopyTransformModifier3D::~CopyTransformModifier3D() {450clear_settings();451}452453454