Path: blob/master/modules/jolt_physics/shapes/jolt_shape_3d.cpp
10278 views
/**************************************************************************/1/* jolt_shape_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 "jolt_shape_3d.h"3132#include "../misc/jolt_type_conversions.h"33#include "../objects/jolt_shaped_object_3d.h"34#include "jolt_custom_double_sided_shape.h"35#include "jolt_custom_user_data_shape.h"3637#include "Jolt/Physics/Collision/Shape/MutableCompoundShape.h"38#include "Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h"39#include "Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h"40#include "Jolt/Physics/Collision/Shape/ScaledShape.h"41#include "Jolt/Physics/Collision/Shape/SphereShape.h"42#include "Jolt/Physics/Collision/Shape/StaticCompoundShape.h"4344namespace {4546constexpr float DEFAULT_SOLVER_BIAS = 0.0;4748} // namespace4950String JoltShape3D::_owners_to_string() const {51const int owner_count = ref_counts_by_owner.size();5253if (owner_count == 0) {54return "'<unknown>' and 0 other object(s)";55}5657const JoltShapedObject3D &random_owner = *ref_counts_by_owner.begin()->key;5859return vformat("'%s' and %d other object(s)", random_owner.to_string(), owner_count - 1);60}6162JoltShape3D::~JoltShape3D() = default;6364void JoltShape3D::add_owner(JoltShapedObject3D *p_owner) {65ref_counts_by_owner[p_owner]++;66}6768void JoltShape3D::remove_owner(JoltShapedObject3D *p_owner) {69if (--ref_counts_by_owner[p_owner] <= 0) {70ref_counts_by_owner.erase(p_owner);71}72}7374void JoltShape3D::remove_self() {75// `remove_owner` will be called when we `remove_shape`, so we need to copy the map since the76// iterator would be invalidated from underneath us.77const HashMap<JoltShapedObject3D *, int> ref_counts_by_owner_copy = ref_counts_by_owner;7879for (const KeyValue<JoltShapedObject3D *, int> &E : ref_counts_by_owner_copy) {80E.key->remove_shape(this);81}82}8384float JoltShape3D::get_solver_bias() const {85return DEFAULT_SOLVER_BIAS;86}8788void JoltShape3D::set_solver_bias(float p_bias) {89if (!Math::is_equal_approx(p_bias, DEFAULT_SOLVER_BIAS)) {90WARN_PRINT(vformat("Custom solver bias for shapes is not supported when using Jolt Physics. Any such value will be ignored. This shape belongs to %s.", _owners_to_string()));91}92}9394JPH::ShapeRefC JoltShape3D::try_build() {95jolt_ref_mutex.lock();9697if (jolt_ref == nullptr) {98jolt_ref = _build();99}100101jolt_ref_mutex.unlock();102103return jolt_ref;104}105106void JoltShape3D::destroy() {107jolt_ref_mutex.lock();108jolt_ref = nullptr;109jolt_ref_mutex.unlock();110111for (const KeyValue<JoltShapedObject3D *, int> &E : ref_counts_by_owner) {112E.key->_shapes_changed();113}114}115116JPH::ShapeRefC JoltShape3D::with_scale(const JPH::Shape *p_shape, const Vector3 &p_scale) {117ERR_FAIL_NULL_V(p_shape, nullptr);118119const JPH::ScaledShapeSettings shape_settings(p_shape, to_jolt(p_scale));120const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();121ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to scale shape with {scale=%v}. It returned the following error: '%s'.", p_scale, to_godot(shape_result.GetError())));122123return shape_result.Get();124}125126JPH::ShapeRefC JoltShape3D::with_basis_origin(const JPH::Shape *p_shape, const Basis &p_basis, const Vector3 &p_origin) {127ERR_FAIL_NULL_V(p_shape, nullptr);128129const JPH::RotatedTranslatedShapeSettings shape_settings(to_jolt(p_origin), to_jolt(p_basis), p_shape);130131const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();132ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to offset shape with {basis=%s origin=%v}. It returned the following error: '%s'.", p_basis, p_origin, to_godot(shape_result.GetError())));133134return shape_result.Get();135}136137JPH::ShapeRefC JoltShape3D::with_center_of_mass_offset(const JPH::Shape *p_shape, const Vector3 &p_offset) {138ERR_FAIL_NULL_V(p_shape, nullptr);139140const JPH::OffsetCenterOfMassShapeSettings shape_settings(to_jolt(p_offset), p_shape);141const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();142ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to offset center of mass with {offset=%v}. It returned the following error: '%s'.", p_offset, to_godot(shape_result.GetError())));143144return shape_result.Get();145}146147JPH::ShapeRefC JoltShape3D::with_center_of_mass(const JPH::Shape *p_shape, const Vector3 &p_center_of_mass) {148ERR_FAIL_NULL_V(p_shape, nullptr);149150const Vector3 center_of_mass_inner = to_godot(p_shape->GetCenterOfMass());151const Vector3 center_of_mass_offset = p_center_of_mass - center_of_mass_inner;152153if (center_of_mass_offset == Vector3()) {154return p_shape;155}156157return with_center_of_mass_offset(p_shape, center_of_mass_offset);158}159160JPH::ShapeRefC JoltShape3D::with_user_data(const JPH::Shape *p_shape, uint64_t p_user_data) {161JoltCustomUserDataShapeSettings shape_settings(p_shape);162shape_settings.mUserData = (JPH::uint64)p_user_data;163164const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();165ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to override user data. It returned the following error: '%s'.", to_godot(shape_result.GetError())));166167return shape_result.Get();168}169170JPH::ShapeRefC JoltShape3D::with_double_sided(const JPH::Shape *p_shape, bool p_back_face_collision) {171ERR_FAIL_NULL_V(p_shape, nullptr);172173const JoltCustomDoubleSidedShapeSettings shape_settings(p_shape, p_back_face_collision);174const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();175ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to make shape double-sided. It returned the following error: '%s'.", to_godot(shape_result.GetError())));176177return shape_result.Get();178}179180JPH::ShapeRefC JoltShape3D::without_custom_shapes(const JPH::Shape *p_shape) {181switch (p_shape->GetSubType()) {182case JoltCustomShapeSubType::RAY:183case JoltCustomShapeSubType::MOTION: {184// Replace unsupported shapes with a small sphere.185return new JPH::SphereShape(0.1f);186}187188case JoltCustomShapeSubType::OVERRIDE_USER_DATA:189case JoltCustomShapeSubType::DOUBLE_SIDED: {190const JPH::DecoratedShape *shape = static_cast<const JPH::DecoratedShape *>(p_shape);191192// Replace unsupported decorator shapes with the inner shape.193return without_custom_shapes(shape->GetInnerShape());194}195196case JPH::EShapeSubType::StaticCompound: {197const JPH::StaticCompoundShape *shape = static_cast<const JPH::StaticCompoundShape *>(p_shape);198199JPH::StaticCompoundShapeSettings settings;200201for (const JPH::CompoundShape::SubShape &sub_shape : shape->GetSubShapes()) {202settings.AddShape(shape->GetCenterOfMass() + sub_shape.GetPositionCOM() - sub_shape.GetRotation() * sub_shape.mShape->GetCenterOfMass(), sub_shape.GetRotation(), without_custom_shapes(sub_shape.mShape));203}204205const JPH::ShapeSettings::ShapeResult shape_result = settings.Create();206ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to recreate static compound shape during filtering of custom shapes. It returned the following error: '%s'.", to_godot(shape_result.GetError())));207208return shape_result.Get();209}210211case JPH::EShapeSubType::MutableCompound: {212const JPH::MutableCompoundShape *shape = static_cast<const JPH::MutableCompoundShape *>(p_shape);213214JPH::MutableCompoundShapeSettings settings;215216for (const JPH::MutableCompoundShape::SubShape &sub_shape : shape->GetSubShapes()) {217settings.AddShape(shape->GetCenterOfMass() + sub_shape.GetPositionCOM() - sub_shape.GetRotation() * sub_shape.mShape->GetCenterOfMass(), sub_shape.GetRotation(), without_custom_shapes(sub_shape.mShape));218}219220const JPH::ShapeSettings::ShapeResult shape_result = settings.Create();221ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to recreate mutable compound shape during filtering of custom shapes. It returned the following error: '%s'.", to_godot(shape_result.GetError())));222223return shape_result.Get();224}225226case JPH::EShapeSubType::RotatedTranslated: {227const JPH::RotatedTranslatedShape *shape = static_cast<const JPH::RotatedTranslatedShape *>(p_shape);228229const JPH::Shape *inner_shape = shape->GetInnerShape();230const JPH::ShapeRefC new_inner_shape = without_custom_shapes(inner_shape);231232if (inner_shape == new_inner_shape) {233return p_shape;234}235236return new JPH::RotatedTranslatedShape(shape->GetPosition(), shape->GetRotation(), new_inner_shape);237}238239case JPH::EShapeSubType::Scaled: {240const JPH::ScaledShape *shape = static_cast<const JPH::ScaledShape *>(p_shape);241242const JPH::Shape *inner_shape = shape->GetInnerShape();243const JPH::ShapeRefC new_inner_shape = without_custom_shapes(inner_shape);244245if (inner_shape == new_inner_shape) {246return p_shape;247}248249return new JPH::ScaledShape(new_inner_shape, shape->GetScale());250}251252case JPH::EShapeSubType::OffsetCenterOfMass: {253const JPH::OffsetCenterOfMassShape *shape = static_cast<const JPH::OffsetCenterOfMassShape *>(p_shape);254255const JPH::Shape *inner_shape = shape->GetInnerShape();256const JPH::ShapeRefC new_inner_shape = without_custom_shapes(inner_shape);257258if (inner_shape == new_inner_shape) {259return p_shape;260}261262return new JPH::OffsetCenterOfMassShape(new_inner_shape, shape->GetOffset());263}264265default: {266return p_shape;267}268}269}270271Vector3 JoltShape3D::make_scale_valid(const JPH::Shape *p_shape, const Vector3 &p_scale) {272return to_godot(p_shape->MakeScaleValid(to_jolt(p_scale)));273}274275bool JoltShape3D::is_scale_valid(const Vector3 &p_scale, const Vector3 &p_valid_scale, real_t p_tolerance) {276return Math::is_equal_approx(p_scale.x, p_valid_scale.x, p_tolerance) && Math::is_equal_approx(p_scale.y, p_valid_scale.y, p_tolerance) && Math::is_equal_approx(p_scale.z, p_valid_scale.z, p_tolerance);277}278279280