diff options
Diffstat (limited to 'modules')
135 files changed, 1992 insertions, 2063 deletions
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index d17e880fc0..f816691cde 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -39,10 +39,6 @@ #include <BulletCollision/CollisionDispatch/btGhostObject.h> #include <btBulletCollisionCommon.h> -/** - @author AndreaCatania -*/ - AreaBullet::AreaBullet() : RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_AREA) { btGhost = bulletnew(btGhostObject); diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h index caf81ef1be..740378d0e3 100644 --- a/modules/bullet/area_bullet.h +++ b/modules/bullet/area_bullet.h @@ -28,18 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AREABULLET_H -#define AREABULLET_H +#ifndef AREA_BULLET_H +#define AREA_BULLET_H #include "collision_object_bullet.h" #include "core/templates/vector.h" #include "servers/physics_server_3d.h" #include "space_bullet.h" -/** - @author AndreaCatania -*/ - class btGhostObject; class AreaBullet : public RigidCollisionObjectBullet { @@ -163,4 +159,4 @@ public: virtual void on_exit_area(AreaBullet *p_area); }; -#endif +#endif // AREA_BULLET_H diff --git a/modules/bullet/btRayShape.cpp b/modules/bullet/btRayShape.cpp index e67c9baacd..14bc7442a7 100644 --- a/modules/bullet/btRayShape.cpp +++ b/modules/bullet/btRayShape.cpp @@ -34,10 +34,6 @@ #include <LinearMath/btAabbUtil2.h> -/** - @author AndreaCatania -*/ - btRayShape::btRayShape(btScalar length) : btConvexInternalShape() { m_shapeType = CUSTOM_CONVEX_SHAPE_TYPE; diff --git a/modules/bullet/btRayShape.h b/modules/bullet/btRayShape.h index 5d0a05b369..90e4524d64 100644 --- a/modules/bullet/btRayShape.h +++ b/modules/bullet/btRayShape.h @@ -35,10 +35,6 @@ #include <BulletCollision/CollisionShapes/btConvexInternalShape.h> -/** - @author AndreaCatania -*/ - /// Ray shape around z axis ATTRIBUTE_ALIGNED16(class) btRayShape : public btConvexInternalShape { diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 9bf3e186ee..7e9e621032 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -45,10 +45,6 @@ #include <assert.h> -/** - @author AndreaCatania -*/ - #define CreateThenReturnRID(owner, ridData) \ RID rid = owner.make_rid(ridData); \ ridData->set_self(rid); \ diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 5840eff815..06a6f62bcd 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -41,10 +41,6 @@ #include "soft_body_bullet.h" #include "space_bullet.h" -/** - @author AndreaCatania -*/ - class BulletPhysicsServer3D : public PhysicsServer3D { GDCLASS(BulletPhysicsServer3D, PhysicsServer3D); @@ -395,4 +391,4 @@ public: JointBullet *get_joint(RID p_rid) const; }; -#endif +#endif // BULLET_PHYSICS_SERVER_H diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp index 571457f48f..a0698683e8 100644 --- a/modules/bullet/bullet_types_converter.cpp +++ b/modules/bullet/bullet_types_converter.cpp @@ -30,10 +30,6 @@ #include "bullet_types_converter.h" -/** - @author AndreaCatania -*/ - // ++ BULLET to GODOT ++++++++++ void B_TO_G(btVector3 const &inVal, Vector3 &outVal) { outVal[0] = inVal[0]; diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h index b4d6dccc05..4ee855c266 100644 --- a/modules/bullet/bullet_types_converter.h +++ b/modules/bullet/bullet_types_converter.h @@ -40,10 +40,6 @@ #include <LinearMath/btTransform.h> #include <LinearMath/btVector3.h> -/** - @author AndreaCatania -*/ - // Bullet to Godot extern void B_TO_G(btVector3 const &inVal, Vector3 &outVal); extern void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal); @@ -59,4 +55,5 @@ extern void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal); extern void G_TO_B(Transform3D const &inVal, btTransform &outVal); extern void UNSCALE_BT_BASIS(btTransform &scaledBasis); -#endif + +#endif // BULLET_TYPES_CONVERTER_H diff --git a/modules/bullet/bullet_utilities.h b/modules/bullet/bullet_utilities.h index b832d3fc61..ab24cb5de6 100644 --- a/modules/bullet/bullet_utilities.h +++ b/modules/bullet/bullet_utilities.h @@ -31,10 +31,6 @@ #ifndef BULLET_UTILITIES_H #define BULLET_UTILITIES_H -/** - @author AndreaCatania -*/ - #define bulletnew(cl) \ new cl @@ -43,4 +39,5 @@ delete cl; \ cl = nullptr; \ } -#endif + +#endif // BULLET_UTILITIES_H diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index 6bf01a63df..bc8e1a0718 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -39,10 +39,6 @@ #include <btBulletCollisionCommon.h> -/** - @author AndreaCatania -*/ - // We enable dynamic AABB tree so that we can actually perform a broadphase on bodies with compound collision shapes. // This is crucial for the performance of kinematic bodies and for bodies with transforming shapes. #define enableDynamicAabbTree true diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index 09be2d99d2..8e9c34df27 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -39,10 +39,6 @@ #include <LinearMath/btTransform.h> -/** - @author AndreaCatania -*/ - class AreaBullet; class ShapeBullet; class btCollisionObject; @@ -256,4 +252,4 @@ private: void internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody = false); }; -#endif +#endif // COLLISION_OBJECT_BULLET_H diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp index 544d711259..fc73036713 100644 --- a/modules/bullet/cone_twist_joint_bullet.cpp +++ b/modules/bullet/cone_twist_joint_bullet.cpp @@ -36,10 +36,6 @@ #include <BulletDynamics/ConstraintSolver/btConeTwistConstraint.h> -/** - @author AndreaCatania -*/ - ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) : JointBullet() { Transform3D scaled_AFrame(rbAFrame.scaled(rbA->get_body_scale())); diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h index ebb51868f4..c81e11f144 100644 --- a/modules/bullet/cone_twist_joint_bullet.h +++ b/modules/bullet/cone_twist_joint_bullet.h @@ -33,10 +33,6 @@ #include "joint_bullet.h" -/** - @author AndreaCatania -*/ - class RigidBodyBullet; class ConeTwistJointBullet : public JointBullet { @@ -50,4 +46,5 @@ public: void set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value); real_t get_param(PhysicsServer3D::ConeTwistJointParam p_param) const; }; -#endif + +#endif // CONE_TWIST_JOINT_BULLET_H diff --git a/modules/bullet/constraint_bullet.cpp b/modules/bullet/constraint_bullet.cpp index 5b4b0e75bc..c788f09cb9 100644 --- a/modules/bullet/constraint_bullet.cpp +++ b/modules/bullet/constraint_bullet.cpp @@ -33,10 +33,6 @@ #include "collision_object_bullet.h" #include "space_bullet.h" -/** - @author AndreaCatania -*/ - ConstraintBullet::ConstraintBullet() {} void ConstraintBullet::setup(btTypedConstraint *p_constraint) { diff --git a/modules/bullet/constraint_bullet.h b/modules/bullet/constraint_bullet.h index 5e63d7a1b5..5dc3958ee1 100644 --- a/modules/bullet/constraint_bullet.h +++ b/modules/bullet/constraint_bullet.h @@ -36,10 +36,6 @@ #include <BulletDynamics/ConstraintSolver/btTypedConstraint.h> -/** - @author AndreaCatania -*/ - class RigidBodyBullet; class SpaceBullet; class btTypedConstraint; @@ -68,4 +64,5 @@ public: _FORCE_INLINE_ btTypedConstraint *get_bt_constraint() { return constraint; } }; -#endif + +#endif // CONSTRAINT_BULLET_H diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp index 01e1ecbdf6..0210064dc8 100644 --- a/modules/bullet/generic_6dof_joint_bullet.cpp +++ b/modules/bullet/generic_6dof_joint_bullet.cpp @@ -36,10 +36,6 @@ #include <BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h> -/** - @author AndreaCatania -*/ - Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : JointBullet() { for (int i = 0; i < 3; i++) { diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h index b5d1db8fd6..cc4ccf7ac4 100644 --- a/modules/bullet/generic_6dof_joint_bullet.h +++ b/modules/bullet/generic_6dof_joint_bullet.h @@ -33,10 +33,6 @@ #include "joint_bullet.h" -/** - @author AndreaCatania -*/ - class RigidBodyBullet; class Generic6DOFJointBullet : public JointBullet { @@ -70,4 +66,4 @@ public: bool get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const; }; -#endif +#endif // GENERIC_6DOF_JOINT_BULLET_H diff --git a/modules/bullet/godot_collision_configuration.cpp b/modules/bullet/godot_collision_configuration.cpp index 0e872fa1c1..354c4e271b 100644 --- a/modules/bullet/godot_collision_configuration.cpp +++ b/modules/bullet/godot_collision_configuration.cpp @@ -35,10 +35,6 @@ #include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h> #include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h> -/** - @author AndreaCatania -*/ - GodotCollisionConfiguration::GodotCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo) : btDefaultCollisionConfiguration(constructionInfo) { void *mem = nullptr; diff --git a/modules/bullet/godot_collision_configuration.h b/modules/bullet/godot_collision_configuration.h index 3b1bc3a97d..7e29f6e03a 100644 --- a/modules/bullet/godot_collision_configuration.h +++ b/modules/bullet/godot_collision_configuration.h @@ -34,10 +34,6 @@ #include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h> #include <BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h> -/** - @author AndreaCatania -*/ - class btDiscreteDynamicsWorld; class GodotCollisionConfiguration : public btDefaultCollisionConfiguration { @@ -63,4 +59,5 @@ public: virtual btCollisionAlgorithmCreateFunc *getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1); virtual btCollisionAlgorithmCreateFunc *getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1); }; -#endif + +#endif // GODOT_COLLISION_CONFIGURATION_H diff --git a/modules/bullet/godot_collision_dispatcher.cpp b/modules/bullet/godot_collision_dispatcher.cpp index c926462eda..2ab1c7dd84 100644 --- a/modules/bullet/godot_collision_dispatcher.cpp +++ b/modules/bullet/godot_collision_dispatcher.cpp @@ -32,10 +32,6 @@ #include "collision_object_bullet.h" -/** - @author AndreaCatania -*/ - const int GodotCollisionDispatcher::CASTED_TYPE_AREA = static_cast<int>(CollisionObjectBullet::TYPE_AREA); GodotCollisionDispatcher::GodotCollisionDispatcher(btCollisionConfiguration *collisionConfiguration) : diff --git a/modules/bullet/godot_collision_dispatcher.h b/modules/bullet/godot_collision_dispatcher.h index 77b8cee0a6..97cae1ce6a 100644 --- a/modules/bullet/godot_collision_dispatcher.h +++ b/modules/bullet/godot_collision_dispatcher.h @@ -31,14 +31,8 @@ #ifndef GODOT_COLLISION_DISPATCHER_H #define GODOT_COLLISION_DISPATCHER_H -#include <cstdint> - #include <btBulletDynamicsCommon.h> -/** - @author AndreaCatania -*/ - /// This class is required to implement custom collision behaviour in the narrowphase class GodotCollisionDispatcher : public btCollisionDispatcher { private: @@ -49,4 +43,5 @@ public: virtual bool needsCollision(const btCollisionObject *body0, const btCollisionObject *body1); virtual bool needsResponse(const btCollisionObject *body0, const btCollisionObject *body1); }; -#endif + +#endif // GODOT_COLLISION_DISPATCHER_H diff --git a/modules/bullet/godot_motion_state.h b/modules/bullet/godot_motion_state.h index a37fef9d90..f1a5e0e3b5 100644 --- a/modules/bullet/godot_motion_state.h +++ b/modules/bullet/godot_motion_state.h @@ -35,10 +35,6 @@ #include <LinearMath/btMotionState.h> -/** - @author AndreaCatania -*/ - class RigidBodyBullet; // This class is responsible to move kinematic actor @@ -96,4 +92,5 @@ public: return bodyCurrentWorldTransform; } }; -#endif + +#endif // GODOT_MOTION_STATE_H diff --git a/modules/bullet/godot_ray_world_algorithm.cpp b/modules/bullet/godot_ray_world_algorithm.cpp index 3b7513916d..697ca12e7b 100644 --- a/modules/bullet/godot_ray_world_algorithm.cpp +++ b/modules/bullet/godot_ray_world_algorithm.cpp @@ -35,10 +35,6 @@ #include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h> -/** - @author AndreaCatania -*/ - // Epsilon to account for floating point inaccuracies #define RAY_PENETRATION_DEPTH_EPSILON 0.01 diff --git a/modules/bullet/godot_ray_world_algorithm.h b/modules/bullet/godot_ray_world_algorithm.h index f554108a75..94bdefb720 100644 --- a/modules/bullet/godot_ray_world_algorithm.h +++ b/modules/bullet/godot_ray_world_algorithm.h @@ -35,10 +35,6 @@ #include <BulletCollision/CollisionDispatch/btCollisionCreateFunc.h> #include <BulletCollision/CollisionDispatch/btCollisionDispatcher.h> -/** - @author AndreaCatania -*/ - class btDiscreteDynamicsWorld; class GodotRayWorldAlgorithm : public btActivatingCollisionAlgorithm { diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index d4b6e90117..35b26fc2ec 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -34,11 +34,8 @@ #include "bullet_types_converter.h" #include "collision_object_bullet.h" #include "rigid_body_bullet.h" -#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h> -/** - @author AndreaCatania -*/ +#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h> bool godotContactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { if (!colObj1Wrap->getCollisionObject()->getCollisionShape()->isCompound()) { diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h index 94be993212..dd64762529 100644 --- a/modules/bullet/godot_result_callbacks.h +++ b/modules/bullet/godot_result_callbacks.h @@ -36,10 +36,6 @@ #include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h> #include <btBulletDynamicsCommon.h> -/** - @author AndreaCatania -*/ - class RigidBodyBullet; /// This callback is injected inside bullet server and allow me to smooth contacts against trimesh @@ -225,4 +221,5 @@ struct GodotDeepPenetrationContactResultCallback : public btManifoldResult { virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth); }; + #endif // GODOT_RESULT_CALLBACKS_H diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp index 116d8caba7..0b1bb7890d 100644 --- a/modules/bullet/hinge_joint_bullet.cpp +++ b/modules/bullet/hinge_joint_bullet.cpp @@ -36,10 +36,6 @@ #include <BulletDynamics/ConstraintSolver/btHingeConstraint.h> -/** - @author AndreaCatania -*/ - HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameA, const Transform3D &frameB) : JointBullet() { Transform3D scaled_AFrame(frameA.scaled(rbA->get_body_scale())); diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h index 7b87576442..5575be564f 100644 --- a/modules/bullet/hinge_joint_bullet.h +++ b/modules/bullet/hinge_joint_bullet.h @@ -33,10 +33,6 @@ #include "joint_bullet.h" -/** - @author AndreaCatania -*/ - class HingeJointBullet : public JointBullet { class btHingeConstraint *hingeConstraint; @@ -54,4 +50,5 @@ public: void set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value); bool get_flag(PhysicsServer3D::HingeJointFlag p_flag) const; }; -#endif + +#endif // HINGE_JOINT_BULLET_H diff --git a/modules/bullet/joint_bullet.cpp b/modules/bullet/joint_bullet.cpp deleted file mode 100644 index 65a891e890..0000000000 --- a/modules/bullet/joint_bullet.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/*************************************************************************/ -/* joint_bullet.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "joint_bullet.h" - -#include "space_bullet.h" - -/** - @author AndreaCatania -*/ - -JointBullet::JointBullet() : - ConstraintBullet() {} - -JointBullet::~JointBullet() {} diff --git a/modules/bullet/joint_bullet.h b/modules/bullet/joint_bullet.h index 75f6055b2f..427221dd77 100644 --- a/modules/bullet/joint_bullet.h +++ b/modules/bullet/joint_bullet.h @@ -34,18 +34,15 @@ #include "constraint_bullet.h" #include "servers/physics_server_3d.h" -/** - @author AndreaCatania -*/ - class RigidBodyBullet; class btTypedConstraint; class JointBullet : public ConstraintBullet { public: - JointBullet(); - virtual ~JointBullet(); + JointBullet() {} + virtual ~JointBullet() {} virtual PhysicsServer3D::JointType get_type() const = 0; }; -#endif + +#endif // JOINT_BULLET_H diff --git a/modules/bullet/pin_joint_bullet.cpp b/modules/bullet/pin_joint_bullet.cpp index 03853cc830..72fdd5c408 100644 --- a/modules/bullet/pin_joint_bullet.cpp +++ b/modules/bullet/pin_joint_bullet.cpp @@ -35,10 +35,6 @@ #include <BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h> -/** - @author AndreaCatania -*/ - PinJointBullet::PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a, RigidBodyBullet *p_body_b, const Vector3 &p_pos_b) : JointBullet() { if (p_body_b) { diff --git a/modules/bullet/pin_joint_bullet.h b/modules/bullet/pin_joint_bullet.h index 0510cf99ad..0a688d55f9 100644 --- a/modules/bullet/pin_joint_bullet.h +++ b/modules/bullet/pin_joint_bullet.h @@ -33,10 +33,6 @@ #include "joint_bullet.h" -/** - @author AndreaCatania -*/ - class RigidBodyBullet; class PinJointBullet : public JointBullet { @@ -57,4 +53,5 @@ public: Vector3 getPivotInA(); Vector3 getPivotInB(); }; -#endif + +#endif // PIN_JOINT_BULLET_H diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp index 675a5c8491..d5d0ee2cf4 100644 --- a/modules/bullet/register_types.cpp +++ b/modules/bullet/register_types.cpp @@ -34,10 +34,6 @@ #include "core/config/project_settings.h" #include "core/object/class_db.h" -/** - @author AndreaCatania -*/ - #ifndef _3D_DISABLED PhysicsServer3D *_createBulletPhysicsCallback() { return memnew(BulletPhysicsServer3D); diff --git a/modules/bullet/register_types.h b/modules/bullet/register_types.h index 739614dc52..93847d6dc3 100644 --- a/modules/bullet/register_types.h +++ b/modules/bullet/register_types.h @@ -31,10 +31,7 @@ #ifndef REGISTER_BULLET_TYPES_H #define REGISTER_BULLET_TYPES_H -/** - @author AndreaCatania -*/ - void register_bullet_types(); void unregister_bullet_types(); -#endif + +#endif // REGISTER_BULLET_TYPES_H diff --git a/modules/bullet/rid_bullet.h b/modules/bullet/rid_bullet.h index 982654441e..260d303cac 100644 --- a/modules/bullet/rid_bullet.h +++ b/modules/bullet/rid_bullet.h @@ -33,10 +33,6 @@ #include "core/templates/rid.h" -/** - @author AndreaCatania -*/ - class BulletPhysicsServer3D; class RIDBullet { @@ -50,4 +46,5 @@ public: _FORCE_INLINE_ void _set_physics_server(BulletPhysicsServer3D *p_physicsServer) { physicsServer = p_physicsServer; } _FORCE_INLINE_ BulletPhysicsServer3D *get_physics_server() const { return physicsServer; } }; -#endif + +#endif // RID_BULLET_H diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 0112712736..0603963332 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -42,12 +42,6 @@ #include <BulletDynamics/Dynamics/btRigidBody.h> #include <btBulletCollisionCommon.h> -#include <assert.h> - -/** - @author AndreaCatania -*/ - BulletPhysicsDirectBodyState3D *BulletPhysicsDirectBodyState3D::singleton = nullptr; Vector3 BulletPhysicsDirectBodyState3D::get_total_gravity() const { diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index f41c5ca1c9..cd433c968f 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BODYBULLET_H -#define BODYBULLET_H +#ifndef RIGID_BODY_BULLET_H +#define RIGID_BODY_BULLET_H #include "collision_object_bullet.h" #include "space_bullet.h" @@ -37,10 +37,6 @@ #include <BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h> #include <LinearMath/btTransform.h> -/** - @author AndreaCatania -*/ - class AreaBullet; class SpaceBullet; class btRigidBody; @@ -329,4 +325,4 @@ private: void _internal_set_mass(real_t p_mass); }; -#endif +#endif // RIGID_BODY_BULLET_H diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index 2b2a7dd8f1..77a583ad86 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -42,10 +42,6 @@ #include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h> #include <btBulletCollisionCommon.h> -/** - @author AndreaCatania -*/ - ShapeBullet::ShapeBullet() {} ShapeBullet::~ShapeBullet() {} diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h index 93e9bed201..6377f8915d 100644 --- a/modules/bullet/shape_bullet.h +++ b/modules/bullet/shape_bullet.h @@ -40,10 +40,6 @@ #include <LinearMath/btScalar.h> #include <LinearMath/btVector3.h> -/** - @author AndreaCatania -*/ - class ShapeBullet; class btCollisionShape; class ShapeOwnerBullet; @@ -244,4 +240,5 @@ public: private: void setup(real_t p_length, bool p_slips_on_slope); }; -#endif + +#endif // SHAPE_BULLET_H diff --git a/modules/bullet/shape_owner_bullet.cpp b/modules/bullet/shape_owner_bullet.cpp deleted file mode 100644 index 7f516e83c0..0000000000 --- a/modules/bullet/shape_owner_bullet.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/*************************************************************************/ -/* shape_owner_bullet.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "shape_owner_bullet.h" - -/** - @author AndreaCatania -*/ diff --git a/modules/bullet/shape_owner_bullet.h b/modules/bullet/shape_owner_bullet.h index 5f8bb61503..11cf1bc2d5 100644 --- a/modules/bullet/shape_owner_bullet.h +++ b/modules/bullet/shape_owner_bullet.h @@ -33,10 +33,6 @@ #include "rid_bullet.h" -/** - @author AndreaCatania -*/ - class ShapeBullet; class btCollisionShape; class CollisionObjectBullet; @@ -51,4 +47,5 @@ public: virtual void remove_shape_full(class ShapeBullet *p_shape) = 0; virtual ~ShapeOwnerBullet() {} }; -#endif + +#endif // SHAPE_OWNER_BULLET_H diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp index a3190609a1..61c3b3b0a3 100644 --- a/modules/bullet/slider_joint_bullet.cpp +++ b/modules/bullet/slider_joint_bullet.cpp @@ -36,10 +36,6 @@ #include <BulletDynamics/ConstraintSolver/btSliderConstraint.h> -/** - @author AndreaCatania -*/ - SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : JointBullet() { Transform3D scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h index 556f4e9e64..c355eb340b 100644 --- a/modules/bullet/slider_joint_bullet.h +++ b/modules/bullet/slider_joint_bullet.h @@ -33,10 +33,6 @@ #include "joint_bullet.h" -/** - @author AndreaCatania -*/ - class RigidBodyBullet; class SliderJointBullet : public JointBullet { @@ -118,4 +114,5 @@ public: void set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value); real_t get_param(PhysicsServer3D::SliderJointParam p_param) const; }; -#endif + +#endif // SLIDER_JOINT_BULLET_H diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h index fea26e9449..82a7bb3b0c 100644 --- a/modules/bullet/soft_body_bullet.h +++ b/modules/bullet/soft_body_bullet.h @@ -49,10 +49,6 @@ #define None 0L #endif -/** - @author AndreaCatania -*/ - class RenderingServerHandler; class SoftBodyBullet : public CollisionObjectBullet { diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 55e822ba5a..460b78d778 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -54,10 +54,6 @@ #include <assert.h> -/** - @author AndreaCatania -*/ - BulletPhysicsDirectSpaceState::BulletPhysicsDirectSpaceState(SpaceBullet *p_space) : PhysicsDirectSpaceState3D(), space(p_space) {} diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 154bb6f01b..f858c5fcb5 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -43,10 +43,6 @@ #include <LinearMath/btTransform.h> #include <LinearMath/btVector3.h> -/** - @author AndreaCatania -*/ - class AreaBullet; class btBroadphaseInterface; class btCollisionDispatcher; @@ -220,4 +216,5 @@ private: int add_separation_result(PhysicsServer3D::SeparationResult *r_results, const SpaceBullet::RecoverResult &p_recover_result, int p_shape_id, const btCollisionObject *p_other_object) const; int recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer3D::SeparationResult *r_results); }; -#endif + +#endif // SPACE_BULLET_H diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm index 626cc3f285..391006bfc2 100644 --- a/modules/camera/camera_osx.mm +++ b/modules/camera/camera_osx.mm @@ -231,7 +231,7 @@ void CameraFeedOSX::set_device(AVCaptureDevice *p_device) { // get some info NSString *device_name = p_device.localizedName; - name = device_name.UTF8String; + name = String::utf8(device_name.UTF8String); position = CameraFeed::FEED_UNSPECIFIED; if ([p_device position] == AVCaptureDevicePositionBack) { position = CameraFeed::FEED_BACK; diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 71891c8704..9a6a33fad3 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -50,7 +50,7 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() { create_handle_material("handles"); } -String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const { +String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -72,7 +72,7 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, return ""; } -Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const { +Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -98,7 +98,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo return Variant(); } -void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { +void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); Transform3D gt = cs->get_global_transform(); @@ -201,7 +201,7 @@ void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_i } } -void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { +void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -343,6 +343,16 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->add_lines(lines, material); p_gizmo->add_collision_segments(lines); + Array csg_meshes = cs->get_meshes(); + if (csg_meshes.size() != 2) { + return; + } + + Ref<Mesh> csg_mesh = csg_meshes[1]; + if (csg_mesh.is_valid()) { + p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh()); + } + if (p_gizmo->is_selected()) { // Draw a translucent representation of the CSG node Ref<ArrayMesh> mesh = memnew(ArrayMesh); diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index 1dcee642c7..46761370dd 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -45,10 +45,10 @@ public: virtual bool is_selectable_when_hidden() const override; virtual void redraw(EditorNode3DGizmo *p_gizmo) override; - virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; - virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) override; + virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; + virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) override; CSGShape3DGizmoPlugin(); }; diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp index 2b29f4d97e..643a74f83e 100644 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -1092,7 +1092,7 @@ HashMap<int, R> FBXMeshData::extract_per_vertex_data( const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR05"); ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR06"); - const int index_to_direct = p_mapping_data.index[polygon_vertex_index]; + const int index_to_direct = get_vertex_from_polygon_vertex(p_mapping_data.index, polygon_vertex_index); T value = p_mapping_data.data[index_to_direct]; aggregate_vertex_data[vertex_index].push_back({ polygon_id, value }); } @@ -1297,7 +1297,7 @@ HashMap<int, T> FBXMeshData::extract_per_polygon( } else { ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR62"); - const int index_to_direct = p_fbx_data.index[polygon_index]; + const int index_to_direct = get_vertex_from_polygon_vertex(p_fbx_data.index, polygon_index); T value = p_fbx_data.data[index_to_direct]; aggregate_polygon_data[polygon_index].push_back(value); } diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp index e03680010b..4cca907bf2 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -83,7 +83,7 @@ uint32_t EditorSceneFormatImporterFBX::get_import_flags() const { return IMPORT_SCENE; } -Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, +Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { // done for performance when re-importing lots of files when testing importer in verbose only! if (OS::get_singleton()->is_stdout_verbose()) { @@ -1468,3 +1468,8 @@ void EditorSceneFormatImporterFBX::BuildDocumentNodes( } } } +Ref<Animation> EditorSceneFormatImporterFBX::import_animation(const String &p_path, + uint32_t p_flags, const Map<StringName, Variant> &p_options, + int p_bake_fps) { + return Ref<Animation>(); +} diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h index a6ea8058a7..eebcb86409 100644 --- a/modules/fbx/editor_scene_importer_fbx.h +++ b/modules/fbx/editor_scene_importer_fbx.h @@ -127,7 +127,10 @@ public: virtual void get_extensions(List<String> *r_extensions) const override; virtual uint32_t get_import_flags() const override; - virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Ref<Animation> import_animation(const String &p_path, + uint32_t p_flags, const Map<StringName, Variant> &p_options, + int p_bake_fps) override; }; #endif // TOOLS_ENABLED diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub index 476cb9cf2a..27d0777c17 100644 --- a/modules/freetype/SCsub +++ b/modules/freetype/SCsub @@ -48,6 +48,7 @@ if env["builtin_freetype"]: "src/pshinter/pshinter.c", "src/psnames/psnames.c", "src/raster/raster.c", + "src/sdf/sdf.c", "src/smooth/smooth.c", "src/truetype/truetype.c", "src/type1/type1.c", diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 6425123e63..5cc295bbab 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -60,7 +60,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l bool in_keyword = false; bool in_word = false; bool in_function_name = false; + bool in_lambda = false; bool in_variable_declaration = false; + bool in_signal_declaration = false; bool in_function_args = false; bool in_member_variable = false; bool in_node_path = false; @@ -105,12 +107,15 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l /* color regions */ if (is_a_symbol || in_region != -1) { int from = j; - for (; from < line_length; from++) { - if (str[from] == '\\') { - from++; - continue; + + if (in_region == -1) { + for (; from < line_length; from++) { + if (str[from] == '\\') { + from++; + continue; + } + break; } - break; } if (from != line_length) { @@ -142,6 +147,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l /* check if it's the whole line */ if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) { + if (from + end_key_length > line_length) { + // If it's key length and there is a '\', dont skip to highlight esc chars. + if (str.find("\\", from) >= 0) { + break; + } + } prev_color = color_regions[in_region].color; highlighter_info["color"] = color_regions[c].color; color_map[j] = highlighter_info; @@ -161,13 +172,25 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l /* if we are in one find the end key */ if (in_region != -1) { + Color region_color = color_regions[in_region].color; + if (in_node_path && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) { + region_color = node_path_color; + } + + prev_color = region_color; + highlighter_info["color"] = region_color; + color_map[j] = highlighter_info; + /* search the line */ int region_end_index = -1; int end_key_length = color_regions[in_region].end_key.length(); const char32_t *end_key = color_regions[in_region].end_key.get_data(); for (; from < line_length; from++) { if (line_length - from < end_key_length) { - break; + // Don't break if '\' to highlight esc chars. + if (str.find("\\", from) < 0) { + break; + } } if (!is_symbol(str[from])) { @@ -175,7 +198,16 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } if (str[from] == '\\') { + Dictionary escape_char_highlighter_info; + escape_char_highlighter_info["color"] = symbol_color; + color_map[from] = escape_char_highlighter_info; + from++; + + Dictionary region_continue_highlighter_info; + prev_color = region_color; + region_continue_highlighter_info["color"] = region_color; + color_map[from + 1] = region_continue_highlighter_info; continue; } @@ -192,10 +224,6 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - prev_color = color_regions[in_region].color; - highlighter_info["color"] = color_regions[in_region].color; - color_map[j] = highlighter_info; - previous_type = REGION; previous_text = ""; previous_column = j; @@ -289,20 +317,36 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } if (!in_function_name && in_word && !in_keyword) { - int k = j; - while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { - k++; - } + if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::SIGNAL)) { + in_signal_declaration = true; + } else { + int k = j; + while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { + k++; + } - // check for space between name and bracket - while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { - k++; - } + // check for space between name and bracket + while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { + k++; + } - if (str[k] == '(') { - in_function_name = true; - } else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) { - in_variable_declaration = true; + if (str[k] == '(') { + in_function_name = true; + } else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) { + in_variable_declaration = true; + } + + // Check for lambda. + if (in_function_name && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { + k = j - 1; + while (k > 0 && (str[k] == '\t' || str[k] == ' ')) { + k--; + } + + if (str[k] == ':') { + in_lambda = true; + } + } } } @@ -348,7 +392,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } in_variable_declaration = false; + in_signal_declaration = false; in_function_name = false; + in_lambda = false; in_member_variable = false; } @@ -376,10 +422,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } else if (in_member_variable) { next_type = MEMBER; color = member_color; + } else if (in_signal_declaration) { + next_type = SIGNAL; + + color = member_color; } else if (in_function_name) { next_type = FUNCTION; - if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { + if (!in_lambda && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { color = function_definition_color; } else { color = function_color; diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index ac4995bee7..1ae0d72896 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -58,6 +58,7 @@ private: SYMBOL, NUMBER, FUNCTION, + SIGNAL, KEYWORD, MEMBER, IDENTIFIER, diff --git a/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd b/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd new file mode 100644 index 0000000000..27383b878d --- /dev/null +++ b/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd @@ -0,0 +1,41 @@ +# meta-description: Visual shader's node plugin template + +@tool +extends _BASE_ +class_name VisualShaderNode_CLASS_ + +func _get_name() -> String: + return "_CLASS_" + +func _get_category() -> String: + return "" + +func _get_description() -> String: + return "" + +func _get_return_icon_type() -> int: + return PORT_TYPE_SCALAR + +func _get_input_port_count() -> int: + return 0 + +func _get_input_port_name(port: int) -> String: + return "" + +func _get_input_port_type(port: int) -> int: + return PORT_TYPE_SCALAR + +func _get_output_port_count() -> int: + return 1 + +func _get_output_port_name(port: int) -> String: + return "result" + +func _get_output_port_type(port: int) -> int: + return PORT_TYPE_SCALAR + +func _get_global_code(mode: Shader.Mode) -> String: + return "" + +func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shader.Mode, type: VisualShader.Type) -> String: + return output_vars[0] + " = 0.0;" diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 6f7e913864..84db97625b 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -2206,7 +2206,6 @@ GDScriptLanguage::GDScriptLanguage() { GLOBAL_DEF("debug/gdscript/warnings/enable", true); GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false); GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true); - GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false); for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); bool default_enabled = !warning.begins_with("unsafe_"); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index ffd34080e3..0d295c3a51 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -881,12 +881,23 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { for (int i = 0; i < p_class->members.size(); i++) { GDScriptParser::ClassNode::Member member = p_class->members[i]; if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) { - resolve_function_body(member.function); - // Apply annotations. for (GDScriptParser::AnnotationNode *&E : member.function->annotations) { E->apply(parser, member.function); } + +#ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : member.function->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } +#endif // DEBUG_ENABLED + + resolve_function_body(member.function); + +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED } else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) { if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) { if (member.variable->getter != nullptr) { @@ -925,6 +936,10 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { GDScriptParser::ClassNode::Member member = p_class->members[i]; if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) { #ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : member.function->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) { parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name); } @@ -992,6 +1007,9 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable); } } +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED } } } @@ -1186,7 +1204,23 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) { for (int i = 0; i < p_suite->statements.size(); i++) { GDScriptParser::Node *stmt = p_suite->statements[i]; + for (GDScriptParser::AnnotationNode *&annotation : stmt->annotations) { + annotation->apply(parser, stmt); + } + +#ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : stmt->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } +#endif // DEBUG_ENABLED + resolve_node(stmt); + +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED + decide_suite_type(p_suite, stmt); } } @@ -1834,13 +1868,14 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig push_error("Cannot assign a new value to a constant.", p_assignment->assignee); } - if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) { - bool compatible = true; - GDScriptParser::DataType op_type = assigned_value_type; - if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { - op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value); - } + bool compatible = true; + GDScriptParser::DataType op_type = assigned_value_type; + if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { + op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value); + } + p_assignment->set_datatype(op_type); + if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) { if (compatible) { compatible = is_type_compatible(assignee_type, op_type, true); if (!compatible) { @@ -1865,7 +1900,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig if (assignee_type.has_no_type() || assigned_value_type.is_variant()) { mark_node_unsafe(p_assignment); - if (assignee_type.is_hard_type()) { + if (assignee_type.is_hard_type() && !assignee_type.is_variant()) { p_assignment->use_conversion_assign = true; } } @@ -2606,7 +2641,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod GDScriptParser::DataType result; result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; result.kind = GDScriptParser::DataType::ENUM_VALUE; - result.builtin_type = base.builtin_type; + result.is_constant = true; + result.builtin_type = Variant::INT; result.native_type = base.native_type; result.enum_type = name; p_identifier->set_datatype(result); @@ -3753,6 +3789,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator // Unary version. GDScriptParser::DataType nil_type; nil_type.builtin_type = Variant::NIL; + nil_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; return get_operation_type(p_operation, p_a, nil_type, r_valid, p_source); } @@ -3762,20 +3799,31 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator Variant::Type a_type = p_a.builtin_type; Variant::Type b_type = p_b.builtin_type; - Variant::ValidatedOperatorEvaluator op_eval = Variant::get_validated_operator_evaluator(p_operation, a_type, b_type); - if (op_eval == nullptr) { + bool hard_operation = p_a.is_hard_type() && p_b.is_hard_type(); + bool validated = op_eval != nullptr; + + if (hard_operation && !validated) { r_valid = false; return result; + } else if (hard_operation && validated) { + r_valid = true; + result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; + result.kind = GDScriptParser::DataType::BUILTIN; + result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type); + } else if (!hard_operation && !validated) { + r_valid = true; + result.type_source = GDScriptParser::DataType::UNDETECTED; + result.kind = GDScriptParser::DataType::VARIANT; + result.builtin_type = Variant::NIL; + } else if (!hard_operation && validated) { + r_valid = true; + result.type_source = GDScriptParser::DataType::INFERRED; + result.kind = GDScriptParser::DataType::BUILTIN; + result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type); } - r_valid = true; - result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; - - result.kind = GDScriptParser::DataType::BUILTIN; - result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type); - return result; } diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 8623122edc..82aa14795e 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -688,6 +688,7 @@ void GDScriptByteCodeGenerator::write_ternary_false_expr(const Address &p_expr) void GDScriptByteCodeGenerator::write_end_ternary() { patch_jump(ternary_jump_skip_pos.back()->get()); ternary_jump_skip_pos.pop_back(); + ternary_result.pop_back(); } void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) { diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index af5ada513c..ca125d3a07 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -882,7 +882,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code #endif /* Find chain of sets */ - StringName assign_property; + StringName assign_class_member_property; + + GDScriptCodeGenerator::Address target_member_property; + bool is_member_property = false; + bool member_property_has_setter = false; + bool member_property_is_in_setter = false; + StringName member_property_setter_function; List<const GDScriptParser::SubscriptNode *> chain; @@ -892,11 +898,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code while (true) { chain.push_back(n); if (n->base->type != GDScriptParser::Node::SUBSCRIPT) { - // Check for a built-in property. + // Check for a property. if (n->base->type == GDScriptParser::Node::IDENTIFIER) { GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(n->base); - if (_is_class_member_property(codegen, identifier->name)) { - assign_property = identifier->name; + StringName var_name = identifier->name; + if (_is_class_member_property(codegen, var_name)) { + assign_class_member_property = var_name; + } else if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { + is_member_property = true; + member_property_setter_function = codegen.script->member_indices[var_name].setter; + member_property_has_setter = member_property_setter_function != StringName(); + member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name; + target_member_property.mode = GDScriptCodeGenerator::Address::MEMBER; + target_member_property.address = codegen.script->member_indices[var_name].index; + target_member_property.type = codegen.script->member_indices[var_name].data_type; } } break; @@ -969,17 +984,19 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Perform operator if any. if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { + GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype())); GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype())); if (subscript->is_attribute) { gen->write_get_named(value, name, prev_base); } else { gen->write_get(value, key, prev_base); } - gen->write_binary_operator(value, assignment->variant_op, value, assigned); + gen->write_binary_operator(op_result, assignment->variant_op, value, assigned); + gen->pop_temporary(); if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { gen->pop_temporary(); } - assigned = value; + assigned = op_result; } // Perform assignment. @@ -1013,10 +1030,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code assigned = info.base; } - // If this is a local member, also assign to it. + // If this is a class member property, also assign to it. // This allow things like: position.x += 2.0 - if (assign_property != StringName()) { - gen->write_set_member(assigned, assign_property); + if (assign_class_member_property != StringName()) { + gen->write_set_member(assigned, assign_class_member_property); + } + // Same as above but for members + if (is_member_property) { + if (member_property_has_setter && !member_property_is_in_setter) { + Vector<GDScriptCodeGenerator::Address> args; + args.push_back(assigned); + gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), member_property_setter_function, args); + } else { + gen->write_assign(target_member_property, assigned); + } } if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { @@ -1035,8 +1062,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name; if (has_operation) { - GDScriptCodeGenerator::Address op_result = codegen.add_temporary(); - GDScriptCodeGenerator::Address member = codegen.add_temporary(); + GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype())); + GDScriptCodeGenerator::Address member = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype())); gen->write_get_member(member, name); gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value); gen->pop_temporary(); // Pop member temp. @@ -1053,29 +1080,26 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } } else { // Regular assignment. - GDScriptCodeGenerator::Address target; - + ERR_FAIL_COND_V_MSG(assignment->assignee->type != GDScriptParser::Node::IDENTIFIER, GDScriptCodeGenerator::Address(), "Expected the assignee to be an identifier here."); + GDScriptCodeGenerator::Address member; + bool is_member = false; bool has_setter = false; bool is_in_setter = false; StringName setter_function; - if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) { - StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name; - if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { - setter_function = codegen.script->member_indices[var_name].setter; - if (setter_function != StringName()) { - has_setter = true; - is_in_setter = setter_function == codegen.function_name; - target.mode = GDScriptCodeGenerator::Address::MEMBER; - target.address = codegen.script->member_indices[var_name].index; - } - } + StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name; + if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) { + is_member = true; + setter_function = codegen.script->member_indices[var_name].setter; + has_setter = setter_function != StringName(); + is_in_setter = has_setter && setter_function == codegen.function_name; + member.mode = GDScriptCodeGenerator::Address::MEMBER; + member.address = codegen.script->member_indices[var_name].index; + member.type = codegen.script->member_indices[var_name].data_type; } - if (has_setter) { - if (!is_in_setter) { - // Store stack slot for the temp value. - target = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype())); - } + GDScriptCodeGenerator::Address target; + if (is_member) { + target = member; // _parse_expression could call its getter, but we want to know the actual address } else { target = _parse_expression(codegen, r_error, assignment->assignee); if (r_error) { @@ -1092,7 +1116,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE; if (has_operation) { // Perform operation. - GDScriptCodeGenerator::Address op_result = codegen.add_temporary(); + GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype())); GDScriptCodeGenerator::Address og_value = _parse_expression(codegen, r_error, assignment->assignee); gen->write_binary_operator(op_result, assignment->variant_op, og_value, assigned_value); to_assign = op_result; @@ -1995,7 +2019,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ codegen.generator->start_parameters(); for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) { const GDScriptParser::ParameterNode *parameter = p_func->parameters[i]; - GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value, true); + GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value); if (r_error) { memdelete(codegen.generator); return nullptr; @@ -2069,7 +2093,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ if (p_func) { // if no return statement -> return type is void not unresolved Variant if (p_func->body->has_return) { - gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype()); + gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script); } else { gd_function->return_type = GDScriptDataType(); gd_function->return_type.has_type = true; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 7e5780a6b8..d10e120410 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -580,12 +580,50 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio if (par->default_value) { String def_val = "<unknown>"; - if (par->default_value->type == GDScriptParser::Node::LITERAL) { - const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->default_value); - def_val = literal->value.get_construct_string(); - } else if (par->default_value->type == GDScriptParser::Node::IDENTIFIER) { - const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->default_value); - def_val = id->name.operator String(); + switch (par->default_value->type) { + case GDScriptParser::Node::LITERAL: { + const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->default_value); + def_val = literal->value.get_construct_string(); + } break; + case GDScriptParser::Node::IDENTIFIER: { + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->default_value); + def_val = id->name.operator String(); + } break; + case GDScriptParser::Node::CALL: { + const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(par->default_value); + if (call->is_constant && call->reduced) { + def_val = call->function_name.operator String() + call->reduced_value.operator String(); + } + } break; + case GDScriptParser::Node::ARRAY: { + const GDScriptParser::ArrayNode *arr = static_cast<const GDScriptParser::ArrayNode *>(par->default_value); + if (arr->is_constant && arr->reduced) { + def_val = arr->reduced_value.operator String(); + } + } break; + case GDScriptParser::Node::DICTIONARY: { + const GDScriptParser::DictionaryNode *dict = static_cast<const GDScriptParser::DictionaryNode *>(par->default_value); + if (dict->is_constant && dict->reduced) { + def_val = dict->reduced_value.operator String(); + } + } break; + case GDScriptParser::Node::SUBSCRIPT: { + const GDScriptParser::SubscriptNode *sub = static_cast<const GDScriptParser::SubscriptNode *>(par->default_value); + if (sub->is_constant) { + if (sub->datatype.kind == GDScriptParser::DataType::ENUM_VALUE) { + def_val = sub->get_datatype().to_string(); + } else if (sub->reduced) { + const Variant::Type vt = sub->reduced_value.get_type(); + if (vt == Variant::Type::NIL || vt == Variant::Type::FLOAT || vt == Variant::Type::INT || vt == Variant::Type::STRING || vt == Variant::Type::STRING_NAME || vt == Variant::Type::BOOL || vt == Variant::Type::NODE_PATH) { + def_val = sub->reduced_value.operator String(); + } else { + def_val = sub->get_datatype().to_string() + sub->reduced_value.operator String(); + } + } + } + } break; + default: + break; } arghint += " = " + def_val; } @@ -646,6 +684,11 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } + } else if (p_annotation->name == "@warning_ignore") { + for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) { + ScriptCodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_result.insert(warning.display, warning); + } } } @@ -923,8 +966,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (!_static || Engine::get_singleton()->has_singleton(type)) { List<MethodInfo> methods; - bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize(); - ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters); + ClassDB::get_method_list(type, &methods, false, true); for (const MethodInfo &E : methods) { if (E.name.begins_with("_")) { continue; @@ -1159,6 +1201,10 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::ExpressionNode *p_expression, GDScriptCompletionIdentifier &r_type) { bool found = false; + if (p_expression == nullptr) { + return false; + } + if (p_expression->is_constant) { // Already has a value, so just use that. r_type = _type_from_variant(p_expression->reduced_value); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index d12795d320..5e210074ed 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -39,6 +39,7 @@ #ifdef DEBUG_ENABLED #include "core/os/os.h" #include "core/string/string_builder.h" +#include "gdscript_warning.h" #endif // DEBUG_ENABLED #ifdef TOOLS_ENABLED @@ -132,9 +133,9 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); + register_annotation(MethodInfo("@warning_ignore", { Variant::STRING, "warning" }), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true); // Networking. register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true); - // TODO: Warning annotations. } GDScriptParser::~GDScriptParser() { @@ -196,6 +197,10 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ return; } + if (ignored_warning_codes.has(p_code)) { + return; + } + String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower(); if (ignored_warnings.has(warn_name)) { return; @@ -701,24 +706,21 @@ void GDScriptParser::parse_extends() { template <class T> void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind) { advance(); - T *member = (this->*p_parse_function)(); - if (member == nullptr) { - return; - } + #ifdef TOOLS_ENABLED - int doc_comment_line = member->start_line - 1; + int doc_comment_line = previous.start_line - 1; #endif // TOOLS_ENABLED // Consume annotations. + List<AnnotationNode *> annotations; while (!annotation_stack.is_empty()) { AnnotationNode *last_annotation = annotation_stack.back()->get(); if (last_annotation->applies_to(p_target)) { - member->annotations.push_front(last_annotation); + annotations.push_front(last_annotation); annotation_stack.pop_back(); } else { push_error(vformat(R"(Annotation "%s" cannot be applied to a %s.)", last_annotation->name, p_member_kind)); clear_unused_annotations(); - return; } #ifdef TOOLS_ENABLED if (last_annotation->start_line == doc_comment_line) { @@ -727,6 +729,16 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)() #endif // TOOLS_ENABLED } + T *member = (this->*p_parse_function)(); + if (member == nullptr) { + return; + } + + // Apply annotations. + for (AnnotationNode *&annotation : annotations) { + member->annotations.push_back(annotation); + } + #ifdef TOOLS_ENABLED // Consume doc comments. class_doc_line = MIN(class_doc_line, doc_comment_line - 1); @@ -805,6 +817,8 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) { class_end = true; break; default: + // Display a completion with identifiers. + make_completion_context(COMPLETION_IDENTIFIER, nullptr); push_error(vformat(R"(Unexpected "%s" in class body.)", current.get_name())); advance(); break; @@ -1507,6 +1521,8 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { bool unreachable = current_suite->has_return && !current_suite->has_unreachable_code; #endif + bool is_annotation = false; + switch (current.type) { case GDScriptTokenizer::Token::PASS: advance(); @@ -1576,6 +1592,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { break; case GDScriptTokenizer::Token::ANNOTATION: { advance(); + is_annotation = true; AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT); if (annotation != nullptr) { annotation_stack.push_back(annotation); @@ -1616,6 +1633,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { } } + // Apply annotations to statement. + while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) { + AnnotationNode *last_annotation = annotation_stack.back()->get(); + if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) { + result->annotations.push_front(last_annotation); + annotation_stack.pop_back(); + } else { + push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name)); + clear_unused_annotations(); + } + } + #ifdef DEBUG_ENABLED if (unreachable && result != nullptr) { current_suite->has_unreachable_code = true; @@ -3468,7 +3497,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint_string = hint_string; - // This is called after tne analyzer is done finding the type, so this should be set here. + // This is called after the analyzer is done finding the type, so this should be set here. DataType export_type = variable->get_datatype(); if (p_annotation->name == "@export") { @@ -3510,12 +3539,12 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint = PROPERTY_HINT_ENUM; String enum_hint_string; - for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) { - enum_hint_string += E->key().operator String().capitalize().xml_escape(); + for (OrderedHashMap<StringName, int>::Element E = export_type.enum_values.front(); E; E = E.next()) { + enum_hint_string += E.key().operator String().capitalize().xml_escape(); enum_hint_string += ":"; - enum_hint_string += String::num_int64(E->get()).xml_escape(); + enum_hint_string += String::num_int64(E.value()).xml_escape(); - if (E->next()) { + if (E.next()) { enum_hint_string += ","; } } @@ -3552,7 +3581,24 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node } bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_node) { - ERR_FAIL_V_MSG(false, "Not implemented."); +#ifdef DEBUG_ENABLED + bool has_error = false; + for (const Variant &warning_name : p_annotation->resolved_arguments) { + GDScriptWarning::Code warning = GDScriptWarning::get_code_from_name(String(warning_name).to_upper()); + if (warning == GDScriptWarning::WARNING_MAX) { + push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation); + has_error = true; + } else { + p_node->ignored_warnings.push_back(warning); + } + } + + return !has_error; + +#else // ! DEBUG_ENABLED + // Only available in debug builds. + return true; +#endif // DEBUG_ENABLED } template <Multiplayer::RPCMode t_mode> @@ -4190,7 +4236,11 @@ void GDScriptParser::TreePrinter::print_get_node(GetNodeNode *p_get_node) { } void GDScriptParser::TreePrinter::print_identifier(IdentifierNode *p_identifier) { - push_text(p_identifier->name); + if (p_identifier != nullptr) { + push_text(p_identifier->name); + } else { + push_text("<invalid identifier>"); + } } void GDScriptParser::TreePrinter::print_if(IfNode *p_if, bool p_is_elif) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index b5ff0538eb..e4311d2d5e 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -133,7 +133,7 @@ public: ClassNode *class_type = nullptr; MethodInfo method_info; // For callable/signals. - Map<StringName, int> enum_values; // For enums. + OrderedHashMap<StringName, int> enum_values; // For enums. _FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; } _FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; } @@ -297,6 +297,7 @@ public: int leftmost_column = 0, rightmost_column = 0; Node *next = nullptr; List<AnnotationNode *> annotations; + Vector<uint32_t> ignored_warnings; DataType datatype; @@ -1204,6 +1205,7 @@ private: #ifdef DEBUG_ENABLED List<GDScriptWarning> warnings; Set<String> ignored_warnings; + Set<uint32_t> ignored_warning_codes; Set<int> unsafe_lines; #endif diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 014a2ad3b8..e0facaf61d 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -488,7 +488,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a memnew_placement(&stack[i + 3], Variant(*p_args[i])); continue; } - + // If types already match, don't call Variant::construct(). Constructors of some types + // (e.g. packed arrays) do copies, whereas they pass by reference when inside a Variant. + if (argument_types[i].is_type(*p_args[i], false)) { + memnew_placement(&stack[i + 3], Variant(*p_args[i])); + continue; + } if (!argument_types[i].is_type(*p_args[i], true)) { r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_err.argument = i; diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index fd251b8444..73536f5f8e 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -213,7 +213,7 @@ GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) } } - ERR_FAIL_V_MSG(WARNING_MAX, "Invalid GDScript warning name: " + p_name); + return WARNING_MAX; } #endif // DEBUG_ENABLED diff --git a/modules/gdscript/icons/GDScriptInternal.svg b/modules/gdscript/icons/GDScriptInternal.svg new file mode 100644 index 0000000000..fcabaafbd0 --- /dev/null +++ b/modules/gdscript/icons/GDScriptInternal.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578c-.2364329.0758517-.4668872.16921-.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941c-.1119126.2211335-.2072287.4502818-.28516.68555l-2.2539.5625v2l2.2578.56445c.075942.2357685.1692993.465568.2793.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953c.2211335.111913.4502818.207229.68555.28516l.5625 2.2539h2l.56445-2.2578c.2357685-.07594.465568-.169299.6875-.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941c.111913-.221133.207229-.4502818.28516-.68555l2.2539-.5625v-2l-2.2578-.56445c-.075942-.2357685-.169299-.4655679-.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953c-.221133-.1119126-.4502818-.2072287-.68555-.28516l-.5625-2.2539zm1 5c1.1045695 0 2 .8954305 2 2s-.8954305 2-2 2-2-.8954305-2-2 .8954305-2 2-2z" fill="none" stroke="#e0e0e0"/></svg> diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 5845f84605..47772b8039 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -362,16 +362,16 @@ void GDScriptTest::error_handler(void *p_this, const char *p_function, const cha } builder.append("\n>> on function: "); - builder.append(p_function); + builder.append(String::utf8(p_function)); builder.append("()\n>> "); - builder.append(String(p_file).trim_prefix(self->base_dir)); + builder.append(String::utf8(p_file).trim_prefix(self->base_dir)); builder.append("\n>> "); builder.append(itos(p_line)); builder.append("\n>> "); - builder.append(p_error); + builder.append(String::utf8(p_error)); if (strlen(p_explanation) > 0) { builder.append("\n>> "); - builder.append(p_explanation); + builder.append(String::utf8(p_explanation)); } builder.append("\n"); diff --git a/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd new file mode 100644 index 0000000000..05d9bd6a3d --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd @@ -0,0 +1,9 @@ +# https://github.com/godotengine/godot/issues/56702 + +func test(): + # somewhat obscure feature: referencing parameters in defaults, but only earlier ones! + ref_default("non-optional") + + +func ref_default(nondefault1, defa=nondefault1, defb=defc, defc=1): + prints(nondefault1, nondefault2, defa, defb, defc) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out new file mode 100644 index 0000000000..1d5b5bf393 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Identifier "defc" not declared in the current scope. diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd new file mode 100644 index 0000000000..877a4ea221 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd @@ -0,0 +1,15 @@ +@warning_ignore(unused_private_class_variable) +var _unused = 2 + +@warning_ignore(unused_variable) +func test(): + print("test") + var unused = 3 + + @warning_ignore(redundant_await) + print(await regular_func()) + + print("done") + +func regular_func(): + return 0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out new file mode 100644 index 0000000000..42292774a0 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out @@ -0,0 +1,4 @@ +GDTEST_OK +test +0 +done diff --git a/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd b/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd new file mode 100644 index 0000000000..8156b4ec68 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd @@ -0,0 +1,35 @@ +# https://github.com/godotengine/godot/issues/56702 + +func test(): + const_default() + func_result_default() + # calling again will run the initializer again, + # as the default is not evaluated at time of defining the function (as in python) + # but every time the function is called (as in C++) + func_result_default() + lots_of_defaults("non-optional") + # somewhat obscure feature: referencing earlier parameters + ref_default("non-optional", 42) + + +func const_default(param=42): + print(param) + + +var default_val := 0 + +func get_default(): + default_val += 1 + return default_val + + +func func_result_default(param=get_default()): + print(param) + + +func lots_of_defaults(nondefault, one=1, two=2, three=get_default()): + prints(nondefault, one, two, three) + + +func ref_default(nondefault1, nondefault2, defa=nondefault1, defb=nondefault2 - 1): + prints(nondefault1, nondefault2, defa, defb) diff --git a/modules/gdscript/tests/scripts/runtime/features/params_default_values.out b/modules/gdscript/tests/scripts/runtime/features/params_default_values.out new file mode 100644 index 0000000000..50e0885ae5 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/params_default_values.out @@ -0,0 +1,6 @@ +GDTEST_OK +42 +1 +2 +non-optional 1 2 3 +non-optional 42 non-optional 41 diff --git a/modules/glslang/SCsub b/modules/glslang/SCsub index 1954a32697..22ef1b5ea9 100644 --- a/modules/glslang/SCsub +++ b/modules/glslang/SCsub @@ -12,7 +12,6 @@ thirdparty_obj = [] if env["builtin_glslang"]: thirdparty_dir = "#thirdparty/glslang/" thirdparty_sources = [ - "glslang/CInterface/glslang_c_interface.cpp", "glslang/MachineIndependent/attribute.cpp", "glslang/MachineIndependent/Constant.cpp", "glslang/MachineIndependent/glslang_tab.cpp", @@ -44,7 +43,6 @@ if env["builtin_glslang"]: "glslang/GenericCodeGen/CodeGen.cpp", "glslang/GenericCodeGen/Link.cpp", "OGLCompilersDLL/InitializeDll.cpp", - "SPIRV/CInterface/spirv_c_interface.cpp", "SPIRV/disassemble.cpp", "SPIRV/doc.cpp", "SPIRV/GlslangToSpv.cpp", @@ -54,7 +52,6 @@ if env["builtin_glslang"]: "SPIRV/SpvPostProcess.cpp", "SPIRV/SPVRemapper.cpp", "SPIRV/SpvTools.cpp", - "StandAlone/ResourceLimits.cpp", ] if env["platform"] == "windows": @@ -65,10 +62,12 @@ if env["builtin_glslang"]: thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] # Treat glslang headers as system headers to avoid raising warnings. Not supported on MSVC. + # Include `#thirdparty` to workaround mismatch between location of `SPIRV` in library source + # and in installed public headers. if not env.msvc: - env_glslang.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path]) + env_glslang.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path, "-isystem", Dir("#thirdparty").path]) else: - env_glslang.Prepend(CPPPATH=[thirdparty_dir]) + env_glslang.Prepend(CPPPATH=[thirdparty_dir, "#thirdparty"]) env_glslang.Append(CPPDEFINES=["ENABLE_OPT=0"]) diff --git a/modules/glslang/glslang_resource_limits.h b/modules/glslang/glslang_resource_limits.h new file mode 100644 index 0000000000..05390f95ad --- /dev/null +++ b/modules/glslang/glslang_resource_limits.h @@ -0,0 +1,147 @@ +/*************************************************************************/ +/* glslang_resource_limits.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef GLSLANG_RESOURCE_LIMITS_H +#define GLSLANG_RESOURCE_LIMITS_H + +#include <glslang/Include/ResourceLimits.h> + +// Synchronized with upstream glslang/StandAlone/ResourceLimits.cpp which is not +// part of the public API. + +const TBuiltInResource DefaultTBuiltInResource = { + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 4096, + /* .MaxVaryingFloats = */ 64, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 4096, + /* .MaxDrawBuffers = */ 32, + /* .MaxVertexUniformVectors = */ 128, + /* .MaxVaryingVectors = */ 8, + /* .MaxFragmentUniformVectors = */ 16, + /* .MaxVertexOutputVectors = */ 16, + /* .MaxFragmentInputVectors = */ 15, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 16, + /* .MaxComputeImageUniforms = */ 8, + /* .MaxComputeAtomicCounters = */ 8, + /* .MaxComputeAtomicCounterBuffers = */ 1, + /* .MaxVaryingComponents = */ 60, + /* .MaxVertexOutputComponents = */ 64, + /* .MaxGeometryInputComponents = */ 64, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 8, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, + /* .MaxCombinedShaderOutputResources = */ 8, + /* .MaxImageSamples = */ 0, + /* .MaxVertexImageUniforms = */ 0, + /* .MaxTessControlImageUniforms = */ 0, + /* .MaxTessEvaluationImageUniforms = */ 0, + /* .MaxGeometryImageUniforms = */ 0, + /* .MaxFragmentImageUniforms = */ 8, + /* .MaxCombinedImageUniforms = */ 8, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 0, + /* .MaxTessControlAtomicCounters = */ 0, + /* .MaxTessEvaluationAtomicCounters = */ 0, + /* .MaxGeometryAtomicCounters = */ 0, + /* .MaxFragmentAtomicCounters = */ 8, + /* .MaxCombinedAtomicCounters = */ 8, + /* .MaxAtomicCounterBindings = */ 1, + /* .MaxVertexAtomicCounterBuffers = */ 0, + /* .MaxTessControlAtomicCounterBuffers = */ 0, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, + /* .MaxGeometryAtomicCounterBuffers = */ 0, + /* .MaxFragmentAtomicCounterBuffers = */ 1, + /* .MaxCombinedAtomicCounterBuffers = */ 1, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 4, + /* .maxMeshOutputVerticesNV = */ 256, + /* .maxMeshOutputPrimitivesNV = */ 512, + /* .maxMeshWorkGroupSizeX_NV = */ 32, + /* .maxMeshWorkGroupSizeY_NV = */ 1, + /* .maxMeshWorkGroupSizeZ_NV = */ 1, + /* .maxTaskWorkGroupSizeX_NV = */ 32, + /* .maxTaskWorkGroupSizeY_NV = */ 1, + /* .maxTaskWorkGroupSizeZ_NV = */ 1, + /* .maxMeshViewCountNV = */ 4, + /* .maxDualSourceDrawBuffersEXT = */ 1, + + /* .limits = */ { + /* .nonInductiveForLoops = */ 1, + /* .whileLoops = */ 1, + /* .doWhileLoops = */ 1, + /* .generalUniformIndexing = */ 1, + /* .generalAttributeMatrixVectorIndexing = */ 1, + /* .generalVaryingIndexing = */ 1, + /* .generalSamplerIndexing = */ 1, + /* .generalVariableIndexing = */ 1, + /* .generalConstantMatrixVectorIndexing = */ 1, + } +}; + +#endif // GLSLANG_RESOURCE_LIMITS_H diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp index c67d5ff5ab..8e69ba78c7 100644 --- a/modules/glslang/register_types.cpp +++ b/modules/glslang/register_types.cpp @@ -32,10 +32,11 @@ #include "servers/rendering/rendering_device.h" -#include <SPIRV/GlslangToSpv.h> -#include <StandAlone/ResourceLimits.h> +#include "glslang_resource_limits.h" + #include <glslang/Include/Types.h> #include <glslang/Public/ShaderLang.h> +#include <glslang/SPIRV/GlslangToSpv.h> static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error, const RenderingDevice::Capabilities *p_capabilities) { Vector<uint8_t> ret; @@ -129,7 +130,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage std::string pre_processed_code; //preprocess - if (!shader.preprocess(&glslang::DefaultTBuiltInResource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) { + if (!shader.preprocess(&DefaultTBuiltInResource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) { if (r_error) { (*r_error) = "Failed pre-process:\n"; (*r_error) += shader.getInfoLog(); @@ -144,7 +145,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage shader.setStrings(&cs_strings, 1); //parse - if (!shader.parse(&glslang::DefaultTBuiltInResource, DefaultVersion, false, messages)) { + if (!shader.parse(&DefaultTBuiltInResource, DefaultVersion, false, messages)) { if (r_error) { (*r_error) = "Failed parse:\n"; (*r_error) += shader.getInfoLog(); @@ -190,8 +191,8 @@ static String _get_cache_key_function_glsl(const RenderingDevice::Capabilities * } void preregister_glslang_types() { - // initialize in case it's not initialized. This is done once per thread - // and it's safe to call multiple times + // Initialize in case it's not initialized. This is done once per thread + // and it's safe to call multiple times. glslang::InitializeProcess(); RenderingDevice::shader_set_compile_to_spirv_function(_compile_shader_glsl); RenderingDevice::shader_set_get_cache_key_function(_get_cache_key_function_glsl); diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index 8d8e25e8b3..ed7c018cb9 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -3,30 +3,57 @@ <brief_description> </brief_description> <description> + Append a glTF2 3d format from a file, buffer or scene and then write to the filesystem, buffer or scene. </description> <tutorials> </tutorials> <methods> - <method name="import_scene"> - <return type="Node" /> + <method name="append_from_buffer"> + <return type="int" enum="Error" /> + <argument index="0" name="bytes" type="PackedByteArray" /> + <argument index="1" name="base_path" type="String" /> + <argument index="2" name="state" type="GLTFState" /> + <argument index="3" name="flags" type="int" default="0" /> + <argument index="4" name="bake_fps" type="int" default="30" /> + <description> + </description> + </method> + <method name="append_from_file"> + <return type="int" enum="Error" /> <argument index="0" name="path" type="String" /> - <argument index="1" name="flags" type="int" default="0" /> - <argument index="2" name="bake_fps" type="int" default="30" /> - <argument index="3" name="state" type="GLTFState" default="null" /> + <argument index="1" name="state" type="GLTFState" /> + <argument index="2" name="flags" type="int" default="0" /> + <argument index="3" name="bake_fps" type="int" default="30" /> <description> - Import a scene from glTF2 ".gltf" or ".glb" file. </description> </method> - <method name="save_scene"> + <method name="append_from_scene"> <return type="int" enum="Error" /> <argument index="0" name="node" type="Node" /> + <argument index="1" name="state" type="GLTFState" /> + <argument index="2" name="flags" type="int" default="0" /> + <argument index="3" name="bake_fps" type="int" default="30" /> + <description> + </description> + </method> + <method name="generate_buffer"> + <return type="PackedByteArray" /> + <argument index="0" name="state" type="GLTFState" /> + <description> + </description> + </method> + <method name="generate_scene"> + <return type="Node" /> + <argument index="0" name="state" type="GLTFState" /> + <argument index="1" name="bake_fps" type="int" default="30" /> + <description> + </description> + </method> + <method name="write_to_filesystem"> + <return type="int" enum="Error" /> + <argument index="0" name="state" type="GLTFState" /> <argument index="1" name="path" type="String" /> - <argument index="2" name="src_path" type="String" /> - <argument index="3" name="flags" type="int" default="0" /> - <argument index="4" name="bake_fps" type="float" default="30" /> - <argument index="5" name="state" type="GLTFState" default="null" /> <description> - Save a scene as a glTF2 ".glb" or ".gltf" file. </description> </method> </methods> diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp index dcf57a32ce..fd5741605c 100644 --- a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp @@ -36,6 +36,7 @@ #include "core/templates/vector.h" #include "editor/editor_file_system.h" #include "gltf_document.h" +#include "gltf_state.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/gui/check_box.h" #include "scene/main/node.h" @@ -75,7 +76,15 @@ void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) { List<String> deps; Ref<GLTFDocument> doc; doc.instantiate(); - Error err = doc->save_scene(root, p_file, p_file, 0, 30.0f, Ref<GLTFState>()); + Ref<GLTFState> state; + state.instantiate(); + int32_t flags = 0; + flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; + Error err = doc->append_from_scene(root, state, flags, 30.0f); + if (err != OK) { + ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); + } + err = doc->write_to_filesystem(state, p_file); if (err != OK) { ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); } diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp index ef1ba14001..f063cc1e2b 100644 --- a/modules/gltf/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor_scene_importer_gltf.cpp @@ -48,16 +48,24 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c } Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, - uint32_t p_flags, int p_bake_fps, + uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { Ref<GLTFDocument> doc; doc.instantiate(); - return doc->import_scene_gltf(p_path, p_flags, p_bake_fps, Ref<GLTFState>(), r_missing_deps, r_err); + Ref<GLTFState> state; + state.instantiate(); + Error err = doc->append_from_file(p_path, state, p_flags, p_bake_fps); + if (err != OK) { + *r_err = err; + return nullptr; + } + Node *root = doc->generate_scene(state, p_bake_fps); + return root; } Ref<Animation> EditorSceneFormatImporterGLTF::import_animation(const String &p_path, - uint32_t p_flags, + uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) { return Ref<Animation>(); } diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h index dafd278f24..4410559b3d 100644 --- a/modules/gltf/editor_scene_importer_gltf.h +++ b/modules/gltf/editor_scene_importer_gltf.h @@ -47,9 +47,9 @@ class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual Ref<Animation> import_animation(const String &p_path, - uint32_t p_flags, int p_bake_fps) override; + uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override; }; #endif // TOOLS_ENABLED #endif // EDITOR_SCENE_IMPORTER_GLTF_H diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index d5d2e7c26b..5a931ed839 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -48,6 +48,7 @@ #include "core/error/error_macros.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" +#include "core/io/file_access_memory.h" #include "core/io/json.h" #include "core/math/disjoint_set.h" #include "core/math/vector2.h" @@ -62,6 +63,7 @@ #include "scene/3d/camera_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" +#include "scene/3d/node_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/importer_mesh.h" #include "scene/resources/mesh.h" @@ -82,13 +84,7 @@ #include <cstdint> #include <limits> -Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String &p_path) { - uint64_t begin_time = OS::get_singleton()->get_ticks_usec(); - - state->skeleton3d_to_gltf_skeleton.clear(); - state->skin_and_skeleton3d_to_gltf_skin.clear(); - - _convert_scene_node(state, p_root, -1, -1); +Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { if (!state->buffers.size()) { state->buffers.push_back(Vector<uint8_t>()); } @@ -184,16 +180,6 @@ Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String & return Error::FAILED; } - /* STEP 17 SERIALIZE FILE */ - err = _serialize_file(state, p_path); - if (err != OK) { - return Error::FAILED; - } - uint64_t elapsed = OS::get_singleton()->get_ticks_usec() - begin_time; - float elapsed_sec = double(elapsed) / 1000000.0; - elapsed_sec = Math::snapped(elapsed_sec, 0.01f); - print_verbose("glTF: Export time elapsed seconds " + rtos(elapsed_sec).pad_decimals(2)); - return OK; } @@ -255,18 +241,14 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { return OK; } -Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) { - Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { - return err; - } - +Error GLTFDocument::_parse_glb(FileAccess *f, Ref<GLTFState> state) { + ERR_FAIL_NULL_V(f, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(f->get_position() != 0, ERR_FILE_CANT_READ); uint32_t magic = f->get_32(); ERR_FAIL_COND_V(magic != 0x46546C67, ERR_FILE_UNRECOGNIZED); //glTF f->get_32(); // version f->get_32(); // length - uint32_t chunk_length = f->get_32(); uint32_t chunk_type = f->get_32(); @@ -280,9 +262,9 @@ Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) { text.parse_utf8((const char *)json_data.ptr(), json_data.size()); JSON json; - err = json.parse(text); + Error err = json.parse(text); if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); + _err_print_error("", "", json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); return err; } @@ -753,6 +735,8 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_pa } buffer_data = _parse_base64_uri(uri); } else { // Relative path to an external image file. + ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); + uri = uri.uri_decode(); uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows. buffer_data = FileAccess::get_file_as_array(uri); ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri); @@ -2539,14 +2523,16 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (p.has("mode")) { const int mode = p["mode"]; ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT); + // Convert mesh.primitive.mode to Godot Mesh enum. See: + // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode static const Mesh::PrimitiveType primitives2[7] = { - Mesh::PRIMITIVE_POINTS, - Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_LINES, //loop not supported, should ce converted - Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_TRIANGLES, - Mesh::PRIMITIVE_TRIANGLE_STRIP, - Mesh::PRIMITIVE_TRIANGLES, //fan not supported, should be converted + Mesh::PRIMITIVE_POINTS, // 0 POINTS + Mesh::PRIMITIVE_LINES, // 1 LINES + Mesh::PRIMITIVE_LINES, // 2 LINE_LOOP; loop not supported, should be converted + Mesh::PRIMITIVE_LINE_STRIP, // 3 LINE_STRIP + Mesh::PRIMITIVE_TRIANGLES, // 4 TRIANGLES + Mesh::PRIMITIVE_TRIANGLE_STRIP, // 5 TRIANGLE_STRIP + Mesh::PRIMITIVE_TRIANGLES, // 6 TRIANGLE_FAN fan not supported, should be converted #ifndef _MSC_VER #warning line loop and triangle fan are not supported and need to be converted to lines and triangles #endif @@ -2952,7 +2938,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path Ref<Image> image = state->images[i]->get_image(); ERR_CONTINUE(image.is_null()); - if (p_path.to_lower().ends_with("glb")) { + if (p_path.to_lower().ends_with("glb") || p_path.is_empty()) { GLTFBufferViewIndex bvi; Ref<GLTFBufferView> bv; @@ -2981,6 +2967,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path d["bufferView"] = bvi; d["mimeType"] = "image/png"; } else { + ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER); String name = state->images[i]->get_name(); if (name.is_empty()) { name = itos(i); @@ -2988,13 +2975,14 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path name = _gen_unique_name(state, name); name = name.pad_zeros(3) + ".png"; String texture_dir = "textures"; - String new_texture_dir = p_path.get_base_dir() + "/" + texture_dir; - DirAccessRef da = DirAccess::open(p_path.get_base_dir()); + String path = p_path.get_base_dir(); + String new_texture_dir = path + "/" + texture_dir; + DirAccessRef da = DirAccess::open(path); if (!da->dir_exists(new_texture_dir)) { da->make_dir(new_texture_dir); } image->save_png(new_texture_dir.plus_file(name)); - d["uri"] = texture_dir.plus_file(name); + d["uri"] = texture_dir.plus_file(name).uri_encode(); } images.push_back(d); } @@ -3010,6 +2998,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path } Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_path) { + ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); if (!state->json.has("images")) { return OK; } @@ -3069,6 +3058,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat } } } else { // Relative path to an external image file. + ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); uri = uri.uri_decode(); uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows. // ResourceLoader will rely on the file extension to use the relevant loader. @@ -3402,29 +3392,32 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { tex.instantiate(); { Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); - // Code for uncompressing RG normal maps - Ref<Image> img = normal_texture->get_image(); - Ref<ImageTexture> img_tex = img; - if (img_tex.is_valid()) { - img = img_tex->get_image(); - } - img->decompress(); - img->convert(Image::FORMAT_RGBA8); - img->convert_ra_rgba8_to_rg(); - for (int32_t y = 0; y < img->get_height(); y++) { - for (int32_t x = 0; x < img->get_width(); x++) { - Color c = img->get_pixel(x, y); - Vector2 red_green = Vector2(c.r, c.g); - red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f); - float blue = 1.0f - red_green.dot(red_green); - blue = MAX(0.0f, blue); - c.b = Math::sqrt(blue); - img->set_pixel(x, y, c); + if (normal_texture.is_valid()) { + // Code for uncompressing RG normal maps + Ref<Image> img = normal_texture->get_image(); + if (img.is_valid()) { + Ref<ImageTexture> img_tex = img; + if (img_tex.is_valid()) { + img = img_tex->get_image(); + } + img->decompress(); + img->convert(Image::FORMAT_RGBA8); + img->convert_ra_rgba8_to_rg(); + for (int32_t y = 0; y < img->get_height(); y++) { + for (int32_t x = 0; x < img->get_width(); x++) { + Color c = img->get_pixel(x, y); + Vector2 red_green = Vector2(c.r, c.g); + red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f); + float blue = 1.0f - red_green.dot(red_green); + blue = MAX(0.0f, blue); + c.b = Math::sqrt(blue); + img->set_pixel(x, y, c); + } + } + tex->create_from_image(img); } } - tex->create_from_image(img); } - Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); GLTFTextureIndex gltf_texture_index = -1; if (tex.is_valid() && tex->get_image().is_valid()) { tex->set_name(material->get_name() + "_normal"); @@ -5099,7 +5092,7 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst return mesh_i; } -ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index) { +ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr); @@ -5119,7 +5112,7 @@ ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> sta return mi; } -Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { +Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr); @@ -5171,7 +5164,7 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, return memnew(Node3D); } -Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { +Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->camera, state->cameras.size(), nullptr); @@ -5249,7 +5242,7 @@ void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref p_node->position = xform.origin; } -Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { +Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; Node3D *spatial = memnew(Node3D); @@ -5616,19 +5609,18 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent scene_parent = bone_attachment; } if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, scene_parent, node_index); + current_node = _generate_mesh_instance(state, node_index); } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, scene_parent, node_index); + current_node = _generate_camera(state, node_index); } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, scene_parent, node_index); + current_node = _generate_light(state, node_index); } // We still have not managed to make a node. if (!current_node) { - current_node = _generate_spatial(state, scene_parent, node_index); + current_node = _generate_spatial(state, node_index); } - - scene_parent->add_child(current_node, true); + scene_parent->add_child(current_node); if (current_node != scene_root) { current_node->set_owner(scene_root); } @@ -5699,11 +5691,11 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen // We still have not managed to make a node if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, scene_parent, node_index); + current_node = _generate_mesh_instance(state, node_index); } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, scene_parent, node_index); + current_node = _generate_camera(state, node_index); } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, scene_parent, node_index); + current_node = _generate_light(state, node_index); } scene_parent->add_child(current_node, true); @@ -6084,7 +6076,9 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { continue; } MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get()); - ERR_CONTINUE(!mi); + if (!mi) { + continue; + } Transform3D mi_xform = mi->get_transform(); node->scale = mi_xform.basis.get_scale(); node->rotation = mi_xform.basis.get_rotation_quaternion(); @@ -6282,39 +6276,8 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state ERR_CONTINUE(err != OK); p_track.rotation_track.values.write[key_i] = rotation; } - } else if (path.find(":transform") != -1) { - p_track.position_track.times = times; - p_track.position_track.interpolation = gltf_interpolation; - p_track.rotation_track.times = times; - p_track.rotation_track.interpolation = gltf_interpolation; - p_track.scale_track.times = times; - p_track.scale_track.interpolation = gltf_interpolation; - - p_track.scale_track.values.resize(key_count); - p_track.scale_track.interpolation = gltf_interpolation; - p_track.position_track.values.resize(key_count); - p_track.position_track.interpolation = gltf_interpolation; - p_track.rotation_track.values.resize(key_count); - p_track.rotation_track.interpolation = gltf_interpolation; - for (int32_t key_i = 0; key_i < key_count; key_i++) { - Transform3D xform = p_animation->track_get_key_value(p_track_i, key_i); - p_track.position_track.values.write[key_i] = xform.get_origin(); - p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion(); - p_track.scale_track.values.write[key_i] = xform.basis.get_scale(); - } } else if (track_type == Animation::TYPE_VALUE) { - if (path.find("/rotation_quat") != -1) { - p_track.rotation_track.times = times; - p_track.rotation_track.interpolation = gltf_interpolation; - - p_track.rotation_track.values.resize(key_count); - p_track.rotation_track.interpolation = gltf_interpolation; - - for (int32_t key_i = 0; key_i < key_count; key_i++) { - Quaternion rotation_track = p_animation->track_get_key_value(p_track_i, key_i); - p_track.rotation_track.values.write[key_i] = rotation_track; - } - } else if (path.find(":position") != -1) { + if (path.find(":position") != -1) { p_track.position_track.times = times; p_track.position_track.interpolation = gltf_interpolation; @@ -6589,142 +6552,57 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } -Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binary) { +Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps) { Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); if (!f) { - return err; + return FAILED; } + f->seek(0); uint32_t magic = f->get_32(); if (magic == 0x46546C67) { //binary file //text file - err = _parse_glb(p_path, state); - if (err) { - return FAILED; + f->seek(0); + err = _parse_glb(f, state); + if (err != OK) { + return err; } } else { - //text file - err = _parse_json(p_path, state); - if (err) { - return FAILED; + f->seek(0); + String text = f->get_as_utf8_string(); + JSON json; + err = json.parse(text); + if (err != OK) { + _err_print_error("", "", json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); } + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + state->json = json.get_data(); } f->close(); - // get file's name, use for scene name if none - state->filename = p_path.get_file().get_slice(".", 0); - - ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED); + if (!state->json.has("asset")) { + return ERR_PARSE_ERROR; + } Dictionary asset = state->json["asset"]; - ERR_FAIL_COND_V(!asset.has("version"), Error::FAILED); + if (!asset.has("version")) { + return ERR_PARSE_ERROR; + } String version = asset["version"]; state->major_version = version.get_slice(".", 0).to_int(); state->minor_version = version.get_slice(".", 1).to_int(); - /* STEP 0 PARSE SCENE */ - err = _parse_scenes(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 1 PARSE NODES */ - err = _parse_nodes(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 2 PARSE BUFFERS */ - err = _parse_buffers(state, p_path.get_base_dir()); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 3 PARSE BUFFER VIEWS */ - err = _parse_buffer_views(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 4 PARSE ACCESSORS */ - err = _parse_accessors(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 5 PARSE IMAGES */ - err = _parse_images(state, p_path.get_base_dir()); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 6 PARSE TEXTURES */ - err = _parse_textures(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 7 PARSE TEXTURES */ - err = _parse_materials(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 9 PARSE SKINS */ - err = _parse_skins(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 10 DETERMINE SKELETONS */ - err = _determine_skeletons(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 11 CREATE SKELETONS */ - err = _create_skeletons(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 12 CREATE SKINS */ - err = _create_skins(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 13 PARSE MESHES (we have enough info now) */ - err = _parse_meshes(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 14 PARSE LIGHTS */ - err = _parse_lights(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 15 PARSE CAMERAS */ - err = _parse_cameras(state); - if (err != OK) { - return Error::FAILED; - } - - /* STEP 16 PARSE ANIMATIONS */ - err = _parse_animations(state); - if (err != OK) { - return Error::FAILED; + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + err = ext->import_preflight(this); + ERR_FAIL_COND_V(err != OK, FAILED); } - - /* STEP 17 ASSIGN SCENE NAMES */ - _assign_scene_names(state); - + err = _parse_gltf_state(state, p_path, p_bake_fps); + ERR_FAIL_COND_V(err != OK, err); return OK; } @@ -6843,89 +6721,20 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { return err; } -Error GLTFDocument::save_scene(Node *p_node, const String &p_path, - const String &p_src_path, uint32_t p_flags, - float p_bake_fps, Ref<GLTFState> r_state) { - ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); - - Ref<GLTFDocument> gltf_document; - gltf_document.instantiate(); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - Error err = ext->export_preflight(this, p_node); - ERR_FAIL_COND_V(err != OK, err); - } - - if (r_state == Ref<GLTFState>()) { - r_state.instantiate(); - } - Error err = gltf_document->serialize(r_state, p_node, p_path); - ERR_FAIL_COND_V(err != OK, err); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - err = ext->export_post(this); - ERR_FAIL_COND_V(err != OK, err); - } - return OK; -} - -Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err) { - // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire - if (r_state == Ref<GLTFState>()) { - r_state.instantiate(); - } - r_state->use_named_skin_binds = - p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; - - Ref<GLTFDocument> gltf_document; - gltf_document.instantiate(); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - Error err = ext->import_preflight(this); - if (r_err) { - *r_err = err; - } - ERR_FAIL_COND_V(err != OK, nullptr); - } - Error err = gltf_document->parse(r_state, p_path); - if (r_err) { - *r_err = err; - } - ERR_FAIL_COND_V(err != Error::OK, nullptr); - - Node3D *root = memnew(Node3D); - for (int32_t root_i = 0; root_i < r_state->root_nodes.size(); root_i++) { - gltf_document->_generate_scene_node(r_state, root, root, r_state->root_nodes[root_i]); - } - gltf_document->_process_mesh_instances(r_state, root); - if (r_state->animations.size()) { - AnimationPlayer *ap = memnew(AnimationPlayer); - root->add_child(ap, true); - ap->set_owner(root); - for (int i = 0; i < r_state->animations.size(); i++) { - gltf_document->_import_animation(r_state, ap, i, p_bake_fps); - } - } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - err = ext->import_post(this, root); - if (r_err) { - *r_err = err; - } - ERR_FAIL_COND_V(err != OK, nullptr); - } - return root; -} - void GLTFDocument::_bind_methods() { - ClassDB::bind_method(D_METHOD("save_scene", "node", "path", "src_path", "flags", "bake_fps", "state"), - &GLTFDocument::save_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>())); - ClassDB::bind_method(D_METHOD("import_scene", "path", "flags", "bake_fps", "state"), - &GLTFDocument::import_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>())); + ClassDB::bind_method(D_METHOD("append_from_file", "path", "state", "flags", "bake_fps"), + &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(30)); + ClassDB::bind_method(D_METHOD("append_from_buffer", "bytes", "base_path", "state", "flags", "bake_fps"), + &GLTFDocument::append_from_buffer, DEFVAL(0), DEFVAL(30)); + ClassDB::bind_method(D_METHOD("append_from_scene", "node", "state", "flags", "bake_fps"), + &GLTFDocument::append_from_scene, DEFVAL(0), DEFVAL(30)); + ClassDB::bind_method(D_METHOD("generate_scene", "state", "bake_fps"), + &GLTFDocument::generate_scene, DEFVAL(30)); + ClassDB::bind_method(D_METHOD("generate_buffer", "state"), + &GLTFDocument::generate_buffer); + ClassDB::bind_method(D_METHOD("write_to_filesystem", "state", "path"), + &GLTFDocument::write_to_filesystem); + ClassDB::bind_method(D_METHOD("set_extensions", "extensions"), &GLTFDocument::set_extensions); ClassDB::bind_method(D_METHOD("get_extensions"), @@ -6950,16 +6759,6 @@ void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) { } } -Node *GLTFDocument::import_scene(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state) { - Error err = FAILED; - List<String> deps; - Node *node = import_scene_gltf(p_path, p_flags, p_bake_fps, r_state, &deps, &err); - if (err != OK) { - return nullptr; - } - return node; -} - void GLTFDocument::set_extensions(TypedArray<GLTFDocumentExtension> p_extensions) { document_extensions = p_extensions; } @@ -6977,3 +6776,243 @@ GLTFDocument::GLTFDocument() { extension_editor.instantiate(); document_extensions.push_back(extension_editor); } + +PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error *r_err) { + Error err = _encode_buffer_glb(state, ""); + if (r_err) { + *r_err = err; + } + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + String json = Variant(state->json).to_json_string(); + + const uint32_t magic = 0x46546C67; // GLTF + const int32_t header_size = 12; + const int32_t chunk_header_size = 8; + + for (int32_t pad_i = 0; pad_i < (chunk_header_size + json.utf8().length()) % 4; pad_i++) { + json += " "; + } + CharString cs = json.utf8(); + const uint32_t text_chunk_length = cs.length(); + + const uint32_t text_chunk_type = 0x4E4F534A; //JSON + int32_t binary_data_length = 0; + if (state->buffers.size()) { + binary_data_length = state->buffers[0].size(); + } + const int32_t binary_chunk_length = binary_data_length; + const int32_t binary_chunk_type = 0x004E4942; //BIN + + Ref<StreamPeerBuffer> buffer; + buffer.instantiate(); + buffer->put_32(magic); + buffer->put_32(state->major_version); // version + buffer->put_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_data_length); // length + buffer->put_32(text_chunk_length); + buffer->put_32(text_chunk_type); + buffer->put_data((uint8_t *)&cs[0], cs.length()); + if (binary_chunk_length) { + buffer->put_32(binary_chunk_length); + buffer->put_32(binary_chunk_type); + buffer->put_data(state->buffers[0].ptr(), binary_data_length); + } + return buffer->get_data_array(); +} + +PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> state) { + ERR_FAIL_NULL_V(state, PackedByteArray()); + Error err = _serialize(state, ""); + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + PackedByteArray bytes = _serialize_glb_buffer(state, &err); + return bytes; +} + +Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_path) { + ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); + + Error err = _serialize(state, p_path); + if (err != OK) { + return err; + } + + err = _serialize_file(state, p_path); + if (err != OK) { + return Error::FAILED; + } + return OK; +} + +Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { + ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr); + GLTFNodeIndex gltf_root = state->root_nodes.write[0]; + Node *gltf_root_node = state->get_scene_node(gltf_root); + Node *root = gltf_root_node->get_parent(); + ERR_FAIL_NULL_V(root, nullptr); + _process_mesh_instances(state, root); + if (state->animations.size()) { + AnimationPlayer *ap = memnew(AnimationPlayer); + root->add_child(ap, true); + ap->set_owner(root); + for (int i = 0; i < state->animations.size(); i++) { + _import_animation(state, ap, i, p_bake_fps); + } + } + + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + Error err = ext->import_post(this, root); + ERR_FAIL_COND_V(err != OK, nullptr); + } + ERR_FAIL_NULL_V(root, nullptr); + return root; +} + +Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { + ERR_FAIL_COND_V(state.is_null(), FAILED); + state->use_named_skin_binds = + p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; + + _convert_scene_node(state, p_node, -1, -1); + if (!state->buffers.size()) { + state->buffers.push_back(Vector<uint8_t>()); + } + + /* STEP 1 CONVERT MESH INSTANCES */ + _convert_mesh_instances(state); + + /* STEP 2 CREATE SKINS */ + Error err = _serialize_skins(state); + return err; +} + +Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { + ERR_FAIL_COND_V(state.is_null(), FAILED); + // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire + Error err = FAILED; + state->use_named_skin_binds = + p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; + FileAccessMemory *file_access = memnew(FileAccessMemory); + file_access->open_custom(p_bytes.ptr(), p_bytes.size()); + err = _parse(state, p_base_path.get_base_dir(), file_access, p_bake_fps); + ERR_FAIL_COND_V(err != OK, FAILED); + return OK; +} + +Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_search_path, float p_bake_fps) { + Error err; + + /* PARSE EXTENSIONS */ + err = _parse_gltf_extensions(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE SCENE */ + err = _parse_scenes(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE NODES */ + err = _parse_nodes(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE BUFFERS */ + err = _parse_buffers(state, p_search_path); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE BUFFER VIEWS */ + err = _parse_buffer_views(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE ACCESSORS */ + err = _parse_accessors(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE IMAGES */ + err = _parse_images(state, p_search_path); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE TEXTURES */ + err = _parse_textures(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE TEXTURES */ + err = _parse_materials(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE SKINS */ + err = _parse_skins(state); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* DETERMINE SKELETONS */ + err = _determine_skeletons(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* CREATE SKELETONS */ + err = _create_skeletons(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* CREATE SKINS */ + err = _create_skins(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE MESHES (we have enough info now) */ + err = _parse_meshes(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE LIGHTS */ + err = _parse_lights(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE CAMERAS */ + err = _parse_cameras(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE ANIMATIONS */ + err = _parse_animations(state); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* ASSIGN SCENE NAMES */ + _assign_scene_names(state); + + Node3D *root = memnew(Node3D); + for (int32_t root_i = 0; root_i < state->root_nodes.size(); root_i++) { + _generate_scene_node(state, root, root, state->root_nodes[root_i]); + } + return OK; +} + +Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags, int32_t p_bake_fps) { + // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire + if (r_state == Ref<GLTFState>()) { + r_state.instantiate(); + } + r_state->filename = p_path.get_file().get_basename(); + r_state->use_named_skin_binds = + p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; + Error err; + FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); + ERR_FAIL_NULL_V(f, ERR_FILE_CANT_OPEN); + + err = _parse(r_state, p_path.get_base_dir(), f, p_bake_fps); + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + return err; +} + +Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) { + ERR_FAIL_NULL_V(state, ERR_PARSE_ERROR); + if (state->json.has("extensionsRequired") && state->json["extensionsRequired"].get_type() == Variant::ARRAY) { + Array extensions_required = state->json["extensionsRequired"]; + if (extensions_required.find("KHR_draco_mesh_compression") != -1) { + ERR_PRINT("glTF2 extension KHR_draco_mesh_compression is not supported."); + return ERR_UNAVAILABLE; + } + } + return OK; +} diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 09cab2e160..c0649e0129 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -33,6 +33,7 @@ #include "gltf_animation.h" +#include "core/error/error_list.h" #include "core/variant/dictionary.h" #include "core/variant/variant.h" #include "gltf_document_extension_convert_importer_mesh.h" @@ -120,11 +121,6 @@ protected: static void _bind_methods(); public: - Node *import_scene(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state); - Node *import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err = nullptr); - Error save_scene(Node *p_node, const String &p_path, - const String &p_src_path, uint32_t p_flags, - float p_bake_fps, Ref<GLTFState> r_state); void set_extensions(TypedArray<GLTFDocumentExtension> p_extensions); TypedArray<GLTFDocumentExtension> get_extensions() const; @@ -200,7 +196,7 @@ private: Ref<Texture2D> _get_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture); Error _parse_json(const String &p_path, Ref<GLTFState> state); - Error _parse_glb(const String &p_path, Ref<GLTFState> state); + Error _parse_glb(FileAccess *f, Ref<GLTFState> state); void _compute_node_heights(Ref<GLTFState> state); Error _parse_buffers(Ref<GLTFState> state, const String &p_base_path); Error _parse_buffer_views(Ref<GLTFState> state); @@ -287,10 +283,10 @@ private: Skeleton3D *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index); - ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); - Camera3D *_generate_camera(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); - Node3D *_generate_light(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); - Node3D *_generate_spatial(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); + ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index); + Camera3D *_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index); + Node3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index); + Node3D *_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index); void _assign_scene_names(Ref<GLTFState> state); template <class T> T _interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values, @@ -361,6 +357,7 @@ private: GLTFNodeIndex p_node_i); Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path); Error _encode_buffer_glb(Ref<GLTFState> state, const String &p_path); + PackedByteArray _serialize_glb_buffer(Ref<GLTFState> state, Error *r_err); Dictionary _serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material); Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material); Error _serialize_version(Ref<GLTFState> state); @@ -384,6 +381,18 @@ private: static float get_max_component(const Color &p_color); public: + Error append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); + Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); + Error append_from_scene(Node *p_node, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); + +public: + Node *generate_scene(Ref<GLTFState> state, int32_t p_bake_fps = 30.0f); + PackedByteArray generate_buffer(Ref<GLTFState> state); + Error write_to_filesystem(Ref<GLTFState> state, const String &p_path); + +public: + Error _parse_gltf_state(Ref<GLTFState> state, const String &p_search_path, float p_bake_fps); + Error _parse_gltf_extensions(Ref<GLTFState> state); void _process_mesh_instances(Ref<GLTFState> state, Node *scene_root); void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, @@ -447,8 +456,8 @@ public: MeshInstance3D *p_mesh_instance); void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name); - Error serialize(Ref<GLTFState> state, Node *p_root, const String &p_path); - Error parse(Ref<GLTFState> state, String p_paths, bool p_read_binary = false); + Error _serialize(Ref<GLTFState> state, const String &p_path); + Error _parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps); }; #endif // GLTF_DOCUMENT_H diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 73315350ff..885817caf1 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -181,6 +181,9 @@ <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> The navigation layers the GridMap generates its navigable regions in. </member> + <member name="physics_material" type="PhysicsMaterial" setter="set_physics_material" getter="get_physics_material"> + Overrides the default friction and bounce physics properties for the whole [GridMap]. + </member> </members> <signals> <signal name="cell_size_changed"> diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 3383daefea..a861efcbf4 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -34,6 +34,7 @@ #include "core/object/message_queue.h" #include "scene/3d/light_3d.h" #include "scene/resources/mesh_library.h" +#include "scene/resources/physics_material.h" #include "scene/resources/surface_tool.h" #include "scene/scene_string_names.h" #include "servers/navigation_server_3d.h" @@ -181,6 +182,15 @@ void GridMap::set_collision_mask_value(int p_layer_number, bool p_value) { set_collision_mask(mask); } +void GridMap::set_physics_material(Ref<PhysicsMaterial> p_material) { + physics_material = p_material; + _recreate_octant_data(); +} + +Ref<PhysicsMaterial> GridMap::get_physics_material() const { + return physics_material; +} + bool GridMap::get_collision_mask_value(int p_layer_number) const { ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive."); ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive."); @@ -316,6 +326,10 @@ void GridMap::set_cell_item(const Vector3i &p_position, int p_item, int p_rot) { PhysicsServer3D::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id()); PhysicsServer3D::get_singleton()->body_set_collision_layer(g->static_body, collision_layer); PhysicsServer3D::get_singleton()->body_set_collision_mask(g->static_body, collision_mask); + if (physics_material.is_valid()) { + PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_FRICTION, physics_material->get_friction()); + PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material->get_bounce()); + } SceneTree *st = SceneTree::get_singleton(); if (st && st->is_debugging_collisions_hint()) { @@ -801,6 +815,9 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &GridMap::set_collision_layer_value); ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &GridMap::get_collision_layer_value); + ClassDB::bind_method(D_METHOD("set_physics_material", "material"), &GridMap::set_physics_material); + ClassDB::bind_method(D_METHOD("get_physics_material"), &GridMap::get_physics_material); + ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &GridMap::set_bake_navigation); ClassDB::bind_method(D_METHOD("is_baking_navigation"), &GridMap::is_baking_navigation); @@ -850,6 +867,7 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1)); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material", "get_physics_material"); ADD_GROUP("Cell", "cell_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size"), "set_cell_size", "get_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_octant_size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_octant_size", "get_octant_size"); diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index db3395b6fe..546b530148 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -38,6 +38,8 @@ //heh heh, godotsphir!! this shares no code and the design is completely different with previous projects i've done.. //should scale better with hardware that supports instancing +class PhysicsMaterial; + class GridMap : public Node3D { GDCLASS(GridMap, Node3D); @@ -134,6 +136,7 @@ class GridMap : public Node3D { uint32_t collision_layer = 1; uint32_t collision_mask = 1; + Ref<PhysicsMaterial> physics_material; bool bake_navigation = false; uint32_t navigation_layers = 1; @@ -223,6 +226,9 @@ public: void set_collision_mask_value(int p_layer_number, bool p_value); bool get_collision_mask_value(int p_layer_number) const; + void set_physics_material(Ref<PhysicsMaterial> p_material); + Ref<PhysicsMaterial> get_physics_material() const; + void set_bake_navigation(bool p_bake_navigation); bool is_baking_navigation(); diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 7abc8f7d7a..5ef48f8645 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -1028,6 +1028,13 @@ void GridMapEditor::_draw_grids(const Vector3 &cell_size) { } } +void GridMapEditor::_update_theme() { + options->set_icon(get_theme_icon(SNAME("GridMap"), SNAME("EditorIcons"))); + search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + mode_thumbnail->set_icon(get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons"))); + mode_list->set_icon(get_theme_icon(SNAME("FileList"), SNAME("EditorIcons"))); +} + void GridMapEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -1048,6 +1055,7 @@ void GridMapEditor::_notification(int p_what) { _update_selection_transform(); _update_paste_indicator(); + _update_theme(); } break; case NOTIFICATION_EXIT_TREE: { @@ -1088,8 +1096,7 @@ void GridMapEditor::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { - options->set_icon(get_theme_icon(SNAME("GridMap"), SNAME("EditorIcons"))); - search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + _update_theme(); } break; case NOTIFICATION_APPLICATION_FOCUS_OUT: { @@ -1250,7 +1257,6 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { mode_thumbnail->set_flat(true); mode_thumbnail->set_toggle_mode(true); mode_thumbnail->set_pressed(true); - mode_thumbnail->set_icon(p_editor->get_gui_base()->get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons"))); hb->add_child(mode_thumbnail); mode_thumbnail->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode), varray(DISPLAY_THUMBNAIL)); @@ -1258,7 +1264,6 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { mode_list->set_flat(true); mode_list->set_toggle_mode(true); mode_list->set_pressed(false); - mode_list->set_icon(p_editor->get_gui_base()->get_theme_icon(SNAME("FileList"), SNAME("EditorIcons"))); hb->add_child(mode_list); mode_list->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode), varray(DISPLAY_LIST)); diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 7e9510e227..37298a1d80 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -201,6 +201,7 @@ class GridMapEditor : public VBoxContainer { void _update_cursor_transform(); void _update_cursor_instance(); void _update_clip(); + void _update_theme(); void _text_changed(const String &p_text); void _sbox_input(const Ref<InputEvent> &p_ie); diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 5d5b2ed6cb..11715040c2 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -775,11 +775,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } else { panorama_tex.instantiate(); panorama_tex->create(8, 8, false, Image::FORMAT_RGBAF); - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 8; j++) { - panorama_tex->set_pixel(i, j, Color(0, 0, 0, 1)); - } - } + panorama_tex->fill(Color(0, 0, 0, 1)); } RD::TextureFormat tfp; diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub index 4fcbe8fb43..9133fdef35 100644 --- a/modules/mbedtls/SCsub +++ b/modules/mbedtls/SCsub @@ -29,6 +29,7 @@ if env["builtin_mbedtls"]: "cipher_wrap.c", "cmac.c", "ctr_drbg.c", + "constant_time.c", "debug.c", "des.c", "dhm.c", @@ -48,8 +49,9 @@ if env["builtin_mbedtls"]: "md4.c", "md5.c", "md.c", - "md_wrap.c", "memory_buffer_alloc.c", + "mps_reader.c", + "mps_trace.c", "net_sockets.c", "nist_kw.c", "oid.c", @@ -75,9 +77,11 @@ if env["builtin_mbedtls"]: "ssl_ciphersuites.c", "ssl_cli.c", "ssl_cookie.c", + "ssl_msg.c", "ssl_srv.c", "ssl_ticket.c", "ssl_tls.c", + "ssl_tls13_keys.c", "threading.c", "timing.c", "version.c", diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h index 9fcac3afe2..ac04763569 100644 --- a/modules/mobile_vr/mobile_vr_interface.h +++ b/modules/mobile_vr/mobile_vr_interface.h @@ -35,8 +35,6 @@ #include "servers/xr/xr_positional_tracker.h" /** - @author Bastiaan Olij <mux213@gmail.com> - The mobile interface is a native VR interface that can be used on Android and iOS phones. It contains a basic implementation supporting 3DOF tracking if a gyroscope and accelerometer are present and sets up the proper projection matrices based on the values provided. @@ -160,4 +158,4 @@ public: ~MobileVRInterface(); }; -#endif // !MOBILE_VR_INTERFACE_H +#endif // MOBILE_VR_INTERFACE_H diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 3d02f638ec..9d416dcfce 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -2995,6 +2995,7 @@ void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMon CRASH_COND(p_script->native == nullptr); p_script->valid = true; + p_script->reload_invalidated = false; update_script_class_info(p_script); @@ -3351,13 +3352,13 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const { } Error CSharpScript::reload(bool p_keep_state) { - bool has_instances; - { - MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex); - has_instances = instances.size(); + if (!reload_invalidated) { + return OK; } - ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE); + // In the case of C#, reload doesn't really do any script reloading. + // That's done separately via domain reloading. + reload_invalidated = false; GD_MONO_SCOPE_THREAD_ATTACH; @@ -3544,6 +3545,7 @@ void CSharpScript::_update_name() { void CSharpScript::_clear() { tool = false; valid = false; + reload_invalidated = true; base = nullptr; native = nullptr; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 221bba3af9..2be588cac4 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -101,6 +101,7 @@ private: bool tool = false; bool valid = false; + bool reload_invalidated = false; bool builtin; diff --git a/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs b/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs new file mode 100644 index 0000000000..00fdc9968e --- /dev/null +++ b/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs @@ -0,0 +1,67 @@ +// meta-description: Visual shader's node plugin template + +using _BINDINGS_NAMESPACE_; +using System; + +public partial class VisualShaderNode_CLASS_ : _BASE_ +{ + public override string _GetName() + { + return "_CLASS_"; + } + + public override string _GetCategory() + { + return ""; + } + + public override string _GetDescription() + { + return ""; + } + + public override int _GetReturnIconType() + { + return 0; + } + + public override int _GetInputPortCount() + { + return 0; + } + + public override string _GetInputPortName(int port) + { + return ""; + } + + public override int _GetInputPortType(int port) + { + return 0; + } + + public override int _GetOutputPortCount() + { + return 1; + } + + public override string _GetOutputPortName(int port) + { + return "result"; + } + + public override int _GetOutputPortType(int port) + { + return 0; + } + + public override string _GetGlobalCode(Shader.Mode mode) + { + return ""; + } + + public override string _GetCode(Godot.Collections.Array inputVars, Godot.Collections.Array outputVars, Shader.Mode mode, VisualShader.Type type) + { + return ""; + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index 75240b0c09..e80b6af68f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -320,6 +320,9 @@ namespace Godot.Collections internal static extern void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value); [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void godot_icall_Dictionary_KeyValuePairAt_Generic(IntPtr ptr, int index, out object key, out object value, int valueTypeEncoding, IntPtr valueTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] @@ -485,7 +488,7 @@ namespace Godot.Collections private KeyValuePair<TKey, TValue> GetKeyValuePair(int index) { - Dictionary.godot_icall_Dictionary_KeyValuePairAt(GetPtr(), index, out object key, out object value); + Dictionary.godot_icall_Dictionary_KeyValuePairAt_Generic(GetPtr(), index, out object key, out object value, valTypeEncoding, valTypeClass); return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value); } diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 56a08a0dd5..8a9f30459c 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -241,6 +241,12 @@ void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObjec *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index)); } +void godot_icall_Dictionary_KeyValuePairAt_Generic(Dictionary *ptr, int index, MonoObject **key, MonoObject **value, uint32_t value_type_encoding, GDMonoClass *value_type_class) { + ManagedType type(value_type_encoding, value_type_class); + *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index)); + *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index), type); +} + void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) { Variant varKey = GDMonoMarshal::mono_object_to_variant(key); Variant *ret = ptr->getptr(varKey); @@ -351,6 +357,7 @@ void godot_register_collections_icalls() { GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt); + GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt_Generic", godot_icall_Dictionary_KeyValuePairAt_Generic); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains); diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 02739f0480..c0cd18e29d 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -68,7 +68,14 @@ String _get_mono_user_dir() { } else { String settings_path; + // Self-contained mode if a `._sc_` or `_sc_` file is present in executable dir. String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir(); + + // On macOS, look outside .app bundle, since .app bundle is read-only. + if (OS::get_singleton()->has_feature("macos") && exe_dir.ends_with("MacOS") && exe_dir.plus_file("..").simplify_path().ends_with("Contents")) { + exe_dir = exe_dir.plus_file("../../..").simplify_path(); + } + DirAccessRef d = DirAccess::create_for_path(exe_dir); if (d->file_exists("._sc_") || d->file_exists("_sc_")) { diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 2b6ae5ef1e..f3da85063a 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -36,10 +36,6 @@ #include "navigation_mesh_generator.h" #endif -/** - @author AndreaCatania -*/ - /// Creates a struct for each function and a function that once called creates /// an instance of that struct with the submitted parameters. /// Then, that struct is stored in an array; the `sync` function consume that array. diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index 6cc226b086..c555a358db 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -40,10 +40,6 @@ #include "nav_region.h" #include "rvo_agent.h" -/** - @author AndreaCatania -*/ - /// The commands are functions executed during the `sync` phase. #define MERGE_INTERNAL(A, B) A##B diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index b33b7933a8..76c31a5f42 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -36,10 +36,6 @@ #include <algorithm> -/** - @author AndreaCatania -*/ - #define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a))) void NavMap::set_up(Vector3 p_up) { diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index cd730fe3ef..1802f4e907 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -36,11 +36,8 @@ #include "core/math/math_defs.h" #include "core/templates/map.h" #include "nav_utils.h" -#include <KdTree.h> -/** - @author AndreaCatania -*/ +#include <KdTree.h> class NavRegion; class RvoAgent; diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp index 7d94e22014..fea0ad519a 100644 --- a/modules/navigation/nav_region.cpp +++ b/modules/navigation/nav_region.cpp @@ -32,10 +32,6 @@ #include "nav_map.h" -/** - @author AndreaCatania -*/ - void NavRegion::set_map(NavMap *p_map) { map = p_map; polygons_dirty = true; diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h index c344414912..7a6da281c0 100644 --- a/modules/navigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -35,11 +35,8 @@ #include "nav_rid.h" #include "nav_utils.h" -#include <vector> -/** - @author AndreaCatania -*/ +#include <vector> class NavMap; class NavRegion; diff --git a/modules/navigation/nav_rid.h b/modules/navigation/nav_rid.h index 2283973cac..31e20440d2 100644 --- a/modules/navigation/nav_rid.h +++ b/modules/navigation/nav_rid.h @@ -33,10 +33,6 @@ #include "core/templates/rid.h" -/** - @author AndreaCatania -*/ - class NavRid { RID self; diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h index 2d725f214c..a6f51a4698 100644 --- a/modules/navigation/nav_utils.h +++ b/modules/navigation/nav_utils.h @@ -35,10 +35,6 @@ #include <vector> -/** - @author AndreaCatania -*/ - class NavRegion; namespace gd { diff --git a/modules/navigation/rvo_agent.cpp b/modules/navigation/rvo_agent.cpp index 6c38eaed0f..c967d0bf98 100644 --- a/modules/navigation/rvo_agent.cpp +++ b/modules/navigation/rvo_agent.cpp @@ -32,10 +32,6 @@ #include "nav_map.h" -/** - @author AndreaCatania -*/ - RvoAgent::RvoAgent() { callback.id = ObjectID(); } diff --git a/modules/navigation/rvo_agent.h b/modules/navigation/rvo_agent.h index 2bf824186b..54baab404e 100644 --- a/modules/navigation/rvo_agent.h +++ b/modules/navigation/rvo_agent.h @@ -36,10 +36,6 @@ #include <Agent.h> -/** - @author AndreaCatania -*/ - class NavMap; class RvoAgent : public NavRid { diff --git a/modules/pvr/SCsub b/modules/pvr/SCsub deleted file mode 100644 index 36052cffed..0000000000 --- a/modules/pvr/SCsub +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_pvr = env_modules.Clone() - -# Thirdparty source files - -thirdparty_obj = [] - -# Not unbundled so far since not widespread as shared library -thirdparty_dir = "#thirdparty/pvrtccompressor/" -thirdparty_sources = [ - "BitScale.cpp", - "MortonTable.cpp", - "PvrTcDecoder.cpp", - "PvrTcEncoder.cpp", - "PvrTcPacket.cpp", -] -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -env_pvr.Prepend(CPPPATH=[thirdparty_dir]) - -env_thirdparty = env_pvr.Clone() -env_thirdparty.disable_warnings() -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) -env.modules_sources += thirdparty_obj - -# Godot source files - -module_obj = [] - -env_pvr.add_source_files(module_obj, "*.cpp") -env.modules_sources += module_obj - -# Needed to force rebuilding the module files when the thirdparty library is updated. -env.Depends(module_obj, thirdparty_obj) diff --git a/modules/pvr/config.py b/modules/pvr/config.py deleted file mode 100644 index d22f9454ed..0000000000 --- a/modules/pvr/config.py +++ /dev/null @@ -1,6 +0,0 @@ -def can_build(env, platform): - return True - - -def configure(env): - pass diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp deleted file mode 100644 index b996d910d5..0000000000 --- a/modules/pvr/image_compress_pvrtc.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************/ -/* image_compress_pvrtc.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "image_compress_pvrtc.h" - -#include "core/io/image.h" -#include "core/object/ref_counted.h" - -#include <PvrTcEncoder.h> -#include <RgbaBitmap.h> - -static void _compress_pvrtc1_4bpp(Image *p_img) { - Ref<Image> img = p_img->duplicate(); - - bool make_mipmaps = false; - if (!img->is_size_po2() || img->get_width() != img->get_height()) { - make_mipmaps = img->has_mipmaps(); - img->resize_to_po2(true); - // Resizing can fail for some formats - if (!img->is_size_po2() || img->get_width() != img->get_height()) { - ERR_FAIL_MSG("Failed to resize the image for compression."); - } - } - img->convert(Image::FORMAT_RGBA8); - if (!img->has_mipmaps() && make_mipmaps) { - img->generate_mipmaps(); - } - - bool use_alpha = img->detect_alpha(); - - Ref<Image> new_img; - new_img.instantiate(); - new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4); - - Vector<uint8_t> data = new_img->get_data(); - { - uint8_t *wr = data.ptrw(); - const uint8_t *r = img->get_data().ptr(); - - for (int i = 0; i <= new_img->get_mipmap_count(); i++) { - int ofs, size, w, h; - img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); - Javelin::RgbaBitmap bm(w, h); - void *dst = (void *)bm.GetData(); - memcpy(dst, &r[ofs], size); - Javelin::ColorRgba<unsigned char> *dp = bm.GetData(); - for (int j = 0; j < size / 4; j++) { - // Red and blue colors are swapped. - SWAP(dp[j].r, dp[j].b); - } - new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); - Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm); - } - } - - p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data); -} - -void _register_pvrtc_compress_func() { - Image::_image_compress_pvrtc1_4bpp_func = _compress_pvrtc1_4bpp; -} diff --git a/modules/pvr/image_compress_pvrtc.h b/modules/pvr/image_compress_pvrtc.h deleted file mode 100644 index 80edb81363..0000000000 --- a/modules/pvr/image_compress_pvrtc.h +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************/ -/* image_compress_pvrtc.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#ifndef IMAGE_COMPRESS_PVRTC_H -#define IMAGE_COMPRESS_PVRTC_H - -void _register_pvrtc_compress_func(); - -#endif // IMAGE_COMPRESS_PVRTC_H diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp deleted file mode 100644 index dcc7f505a1..0000000000 --- a/modules/pvr/register_types.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "register_types.h" - -#include "image_compress_pvrtc.h" -#include "texture_loader_pvr.h" - -static Ref<ResourceFormatPVR> resource_loader_pvr; - -void register_pvr_types() { - resource_loader_pvr.instantiate(); - ResourceLoader::add_resource_format_loader(resource_loader_pvr); - - _register_pvrtc_compress_func(); -} - -void unregister_pvr_types() { - ResourceLoader::remove_resource_format_loader(resource_loader_pvr); - resource_loader_pvr.unref(); -} diff --git a/modules/pvr/register_types.h b/modules/pvr/register_types.h deleted file mode 100644 index faefb98678..0000000000 --- a/modules/pvr/register_types.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#ifndef PVR_REGISTER_TYPES_H -#define PVR_REGISTER_TYPES_H - -void register_pvr_types(); -void unregister_pvr_types(); - -#endif // PVR_REGISTER_TYPES_H diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp deleted file mode 100644 index ff66a101ab..0000000000 --- a/modules/pvr/texture_loader_pvr.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/*************************************************************************/ -/* texture_loader_pvr.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "texture_loader_pvr.h" - -#include "core/io/file_access.h" - -static void _pvrtc_decompress(Image *p_img); - -enum PVRFLags { - PVR_HAS_MIPMAPS = 0x00000100, - PVR_TWIDDLED = 0x00000200, - PVR_NORMAL_MAP = 0x00000400, - PVR_BORDER = 0x00000800, - PVR_CUBE_MAP = 0x00001000, - PVR_FALSE_MIPMAPS = 0x00002000, - PVR_VOLUME_TEXTURES = 0x00004000, - PVR_HAS_ALPHA = 0x00008000, - PVR_VFLIP = 0x00010000 -}; - -RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - if (r_error) { - *r_error = ERR_CANT_OPEN; - } - - Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { - return RES(); - } - - FileAccessRef faref(f); - - ERR_FAIL_COND_V(err, RES()); - - if (r_error) { - *r_error = ERR_FILE_CORRUPT; - } - - uint32_t hsize = f->get_32(); - - ERR_FAIL_COND_V(hsize != 52, RES()); - uint32_t height = f->get_32(); - uint32_t width = f->get_32(); - uint32_t mipmaps = f->get_32(); - uint32_t flags = f->get_32(); - uint32_t surfsize = f->get_32(); - f->seek(f->get_position() + 20); // bpp, rmask, gmask, bmask, amask - uint8_t pvrid[5] = { 0, 0, 0, 0, 0 }; - f->get_buffer(pvrid, 4); - ERR_FAIL_COND_V(String((char *)pvrid) != "PVR!", RES()); - f->get_32(); // surfcount - - /* - print_line("height: "+itos(height)); - print_line("width: "+itos(width)); - print_line("mipmaps: "+itos(mipmaps)); - print_line("flags: "+itos(flags)); - print_line("surfsize: "+itos(surfsize)); - print_line("bpp: "+itos(bpp)); - print_line("rmask: "+itos(rmask)); - print_line("gmask: "+itos(gmask)); - print_line("bmask: "+itos(bmask)); - print_line("amask: "+itos(amask)); - print_line("surfcount: "+itos(surfcount)); - */ - - Vector<uint8_t> data; - data.resize(surfsize); - - ERR_FAIL_COND_V(data.size() == 0, RES()); - - uint8_t *w = data.ptrw(); - f->get_buffer(&w[0], surfsize); - err = f->get_error(); - ERR_FAIL_COND_V(err != OK, RES()); - - Image::Format format = Image::FORMAT_MAX; - - switch (flags & 0xFF) { - case 0x18: - case 0xC: - format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_2A : Image::FORMAT_PVRTC1_2; - break; - case 0x19: - case 0xD: - format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4; - break; - case 0x16: - format = Image::FORMAT_L8; - break; - case 0x17: - format = Image::FORMAT_LA8; - break; - case 0x20: - case 0x80: - case 0x81: - format = Image::FORMAT_DXT1; - break; - case 0x21: - case 0x22: - case 0x82: - case 0x83: - format = Image::FORMAT_DXT3; - break; - case 0x23: - case 0x24: - case 0x84: - case 0x85: - format = Image::FORMAT_DXT5; - break; - case 0x4: - case 0x15: - format = Image::FORMAT_RGB8; - break; - case 0x5: - case 0x12: - format = Image::FORMAT_RGBA8; - break; - case 0x36: - format = Image::FORMAT_ETC; - break; - default: - ERR_FAIL_V_MSG(RES(), "Unsupported format in PVR texture: " + itos(flags & 0xFF) + "."); - } - - Ref<Image> image = memnew(Image(width, height, mipmaps, format, data)); - ERR_FAIL_COND_V(image->is_empty(), RES()); - - Ref<ImageTexture> texture = memnew(ImageTexture); - texture->create_from_image(image); - - if (r_error) { - *r_error = OK; - } - - return texture; -} - -void ResourceFormatPVR::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("pvr"); -} - -bool ResourceFormatPVR::handles_type(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "Texture2D"); -} - -String ResourceFormatPVR::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "pvr") { - return "Texture2D"; - } - return ""; -} - -ResourceFormatPVR::ResourceFormatPVR() { - Image::_image_decompress_pvrtc = _pvrtc_decompress; -} - -///////////////////////////////////////////////////////// - -//PVRTC decompressor, Based on PVRTC decompressor by IMGTEC. - -///////////////////////////////////////////////////////// - -#define PT_INDEX 2 -#define BLK_Y_SIZE 4 -#define BLK_X_MAX 8 -#define BLK_X_2BPP 8 -#define BLK_X_4BPP 4 - -#define WRAP_COORD(Val, Size) ((Val) & ((Size)-1)) - -/* - Define an expression to either wrap or clamp large or small vals to the - legal coordinate range -*/ -#define LIMIT_COORD(Val, Size, p_tiled) \ - ((p_tiled) ? WRAP_COORD((Val), (Size)) : CLAMP((Val), 0, (Size)-1)) - -struct PVRTCBlock { - //blocks are 64 bits - uint32_t data[2] = {}; -}; - -_FORCE_INLINE_ bool is_po2(uint32_t p_input) { - if (p_input == 0) { - return false; - } - uint32_t minus1 = p_input - 1; - return ((p_input | minus1) == (p_input ^ minus1)) ? true : false; -} - -static void unpack_5554(const PVRTCBlock *p_block, int p_ab_colors[2][4]) { - uint32_t raw_bits[2]; - raw_bits[0] = p_block->data[1] & (0xFFFE); - raw_bits[1] = p_block->data[1] >> 16; - - for (int i = 0; i < 2; i++) { - if (raw_bits[i] & (1 << 15)) { - p_ab_colors[i][0] = (raw_bits[i] >> 10) & 0x1F; - p_ab_colors[i][1] = (raw_bits[i] >> 5) & 0x1F; - p_ab_colors[i][2] = raw_bits[i] & 0x1F; - if (i == 0) { - p_ab_colors[0][2] |= p_ab_colors[0][2] >> 4; - } - p_ab_colors[i][3] = 0xF; - } else { - p_ab_colors[i][0] = (raw_bits[i] >> (8 - 1)) & 0x1E; - p_ab_colors[i][1] = (raw_bits[i] >> (4 - 1)) & 0x1E; - - p_ab_colors[i][0] |= p_ab_colors[i][0] >> 4; - p_ab_colors[i][1] |= p_ab_colors[i][1] >> 4; - - p_ab_colors[i][2] = (raw_bits[i] & 0xF) << 1; - - if (i == 0) { - p_ab_colors[0][2] |= p_ab_colors[0][2] >> 3; - } else { - p_ab_colors[0][2] |= p_ab_colors[0][2] >> 4; - } - - p_ab_colors[i][3] = (raw_bits[i] >> 11) & 0xE; - } - } -} - -static void unpack_modulations(const PVRTCBlock *p_block, const int p_2bit, int p_modulation[8][16], int p_modulation_modes[8][16], int p_x, int p_y) { - int block_mod_mode = p_block->data[1] & 1; - uint32_t modulation_bits = p_block->data[0]; - - if (p_2bit && block_mod_mode) { - for (int y = 0; y < BLK_Y_SIZE; y++) { - for (int x = 0; x < BLK_X_2BPP; x++) { - p_modulation_modes[y + p_y][x + p_x] = block_mod_mode; - - if (((x ^ y) & 1) == 0) { - p_modulation[y + p_y][x + p_x] = modulation_bits & 3; - modulation_bits >>= 2; - } - } - } - - } else if (p_2bit) { - for (int y = 0; y < BLK_Y_SIZE; y++) { - for (int x = 0; x < BLK_X_2BPP; x++) { - p_modulation_modes[y + p_y][x + p_x] = block_mod_mode; - - if (modulation_bits & 1) { - p_modulation[y + p_y][x + p_x] = 0x3; - } else { - p_modulation[y + p_y][x + p_x] = 0x0; - } - - modulation_bits >>= 1; - } - } - } else { - for (int y = 0; y < BLK_Y_SIZE; y++) { - for (int x = 0; x < BLK_X_4BPP; x++) { - p_modulation_modes[y + p_y][x + p_x] = block_mod_mode; - p_modulation[y + p_y][x + p_x] = modulation_bits & 3; - modulation_bits >>= 2; - } - } - } - - ERR_FAIL_COND(modulation_bits != 0); -} - -static void interpolate_colors(const int p_colorp[4], const int p_colorq[4], const int p_colorr[4], const int p_colors[4], bool p_2bit, const int x, const int y, int r_result[4]) { - int u, v, uscale; - int k; - - int tmp1, tmp2; - - int P[4], Q[4], R[4], S[4]; - - for (k = 0; k < 4; k++) { - P[k] = p_colorp[k]; - Q[k] = p_colorq[k]; - R[k] = p_colorr[k]; - S[k] = p_colors[k]; - } - - v = (y & 0x3) | ((~y & 0x2) << 1); - - if (p_2bit) { - u = (x & 0x7) | ((~x & 0x4) << 1); - } else { - u = (x & 0x3) | ((~x & 0x2) << 1); - } - - v = v - BLK_Y_SIZE / 2; - - if (p_2bit) { - u = u - BLK_X_2BPP / 2; - uscale = 8; - } else { - u = u - BLK_X_4BPP / 2; - uscale = 4; - } - - for (k = 0; k < 4; k++) { - tmp1 = P[k] * uscale + u * (Q[k] - P[k]); - tmp2 = R[k] * uscale + u * (S[k] - R[k]); - - tmp1 = tmp1 * 4 + v * (tmp2 - tmp1); - - r_result[k] = tmp1; - } - - if (p_2bit) { - for (k = 0; k < 3; k++) { - r_result[k] >>= 2; - } - - r_result[3] >>= 1; - } else { - for (k = 0; k < 3; k++) { - r_result[k] >>= 1; - } - } - - for (k = 0; k < 4; k++) { - ERR_FAIL_COND(r_result[k] >= 256); - } - - for (k = 0; k < 3; k++) { - r_result[k] += r_result[k] >> 5; - } - - r_result[3] += r_result[3] >> 4; - - for (k = 0; k < 4; k++) { - ERR_FAIL_COND(r_result[k] >= 256); - } -} - -static void get_modulation_value(int x, int y, const int p_2bit, const int p_modulation[8][16], const int p_modulation_modes[8][16], int *r_mod, int *p_dopt) { - static const int rep_vals0[4] = { 0, 3, 5, 8 }; - static const int rep_vals1[4] = { 0, 4, 4, 8 }; - - int mod_val; - - y = (y & 0x3) | ((~y & 0x2) << 1); - - if (p_2bit) { - x = (x & 0x7) | ((~x & 0x4) << 1); - } else { - x = (x & 0x3) | ((~x & 0x2) << 1); - } - - *p_dopt = 0; - - if (p_modulation_modes[y][x] == 0) { - mod_val = rep_vals0[p_modulation[y][x]]; - } else if (p_2bit) { - if (((x ^ y) & 1) == 0) { - mod_val = rep_vals0[p_modulation[y][x]]; - } else if (p_modulation_modes[y][x] == 1) { - mod_val = (rep_vals0[p_modulation[y - 1][x]] + - rep_vals0[p_modulation[y + 1][x]] + - rep_vals0[p_modulation[y][x - 1]] + - rep_vals0[p_modulation[y][x + 1]] + 2) / - 4; - } else if (p_modulation_modes[y][x] == 2) { - mod_val = (rep_vals0[p_modulation[y][x - 1]] + - rep_vals0[p_modulation[y][x + 1]] + 1) / - 2; - } else { - mod_val = (rep_vals0[p_modulation[y - 1][x]] + - rep_vals0[p_modulation[y + 1][x]] + 1) / - 2; - } - } else { - mod_val = rep_vals1[p_modulation[y][x]]; - - *p_dopt = p_modulation[y][x] == PT_INDEX; - } - - *r_mod = mod_val; -} - -static int disable_twiddling = 0; - -static uint32_t twiddle_uv(uint32_t p_height, uint32_t p_width, uint32_t p_y, uint32_t p_x) { - uint32_t twiddled; - - uint32_t min_dimension; - uint32_t max_value; - - uint32_t scr_bit_pos; - uint32_t dst_bit_pos; - - int shift_count; - - ERR_FAIL_COND_V(p_y >= p_height, 0); - ERR_FAIL_COND_V(p_x >= p_width, 0); - - ERR_FAIL_COND_V(!is_po2(p_height), 0); - ERR_FAIL_COND_V(!is_po2(p_width), 0); - - if (p_height < p_width) { - min_dimension = p_height; - max_value = p_x; - } else { - min_dimension = p_width; - max_value = p_y; - } - - if (disable_twiddling) { - return (p_y * p_width + p_x); - } - - scr_bit_pos = 1; - dst_bit_pos = 1; - twiddled = 0; - shift_count = 0; - - while (scr_bit_pos < min_dimension) { - if (p_y & scr_bit_pos) { - twiddled |= dst_bit_pos; - } - - if (p_x & scr_bit_pos) { - twiddled |= (dst_bit_pos << 1); - } - - scr_bit_pos <<= 1; - dst_bit_pos <<= 2; - shift_count += 1; - } - - max_value >>= shift_count; - - twiddled |= (max_value << (2 * shift_count)); - - return twiddled; -} - -static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int p_width, const int p_height, const int p_tiled, unsigned char *p_dst) { - int x, y; - int i, j; - - int block_x, blk_y; - int block_xp1, blk_yp1; - int x_block_size; - int block_width, block_height; - - int p_x, p_y; - - int p_modulation[8][16] = { { 0 } }; - int p_modulation_modes[8][16] = { { 0 } }; - - int Mod, DoPT; - - unsigned int u_pos; - - // local neighbourhood of blocks - PVRTCBlock *p_blocks[2][2]; - - PVRTCBlock *prev[2][2] = { { nullptr, nullptr }, { nullptr, nullptr } }; - - struct - { - int Reps[2][4]; - } colors5554[2][2]; - - int ASig[4], BSig[4]; - - int r_result[4]; - - if (p_2bit) { - x_block_size = BLK_X_2BPP; - } else { - x_block_size = BLK_X_4BPP; - } - - block_width = MAX(2, p_width / x_block_size); - block_height = MAX(2, p_height / BLK_Y_SIZE); - - for (y = 0; y < p_height; y++) { - for (x = 0; x < p_width; x++) { - block_x = (x - x_block_size / 2); - blk_y = (y - BLK_Y_SIZE / 2); - - block_x = LIMIT_COORD(block_x, p_width, p_tiled); - blk_y = LIMIT_COORD(blk_y, p_height, p_tiled); - - block_x /= x_block_size; - blk_y /= BLK_Y_SIZE; - - block_xp1 = LIMIT_COORD(block_x + 1, block_width, p_tiled); - blk_yp1 = LIMIT_COORD(blk_y + 1, block_height, p_tiled); - - p_blocks[0][0] = p_comp_img + twiddle_uv(block_height, block_width, blk_y, block_x); - p_blocks[0][1] = p_comp_img + twiddle_uv(block_height, block_width, blk_y, block_xp1); - p_blocks[1][0] = p_comp_img + twiddle_uv(block_height, block_width, blk_yp1, block_x); - p_blocks[1][1] = p_comp_img + twiddle_uv(block_height, block_width, blk_yp1, block_xp1); - - if (memcmp(prev, p_blocks, 4 * sizeof(void *)) != 0) { - p_y = 0; - for (i = 0; i < 2; i++) { - p_x = 0; - for (j = 0; j < 2; j++) { - unpack_5554(p_blocks[i][j], colors5554[i][j].Reps); - - unpack_modulations( - p_blocks[i][j], - p_2bit, - p_modulation, - p_modulation_modes, - p_x, p_y); - - p_x += x_block_size; - } - - p_y += BLK_Y_SIZE; - } - - memcpy(prev, p_blocks, 4 * sizeof(void *)); - } - - interpolate_colors( - colors5554[0][0].Reps[0], - colors5554[0][1].Reps[0], - colors5554[1][0].Reps[0], - colors5554[1][1].Reps[0], - p_2bit, x, y, - ASig); - - interpolate_colors( - colors5554[0][0].Reps[1], - colors5554[0][1].Reps[1], - colors5554[1][0].Reps[1], - colors5554[1][1].Reps[1], - p_2bit, x, y, - BSig); - - get_modulation_value(x, y, p_2bit, (const int(*)[16])p_modulation, (const int(*)[16])p_modulation_modes, - &Mod, &DoPT); - - for (i = 0; i < 4; i++) { - r_result[i] = ASig[i] * 8 + Mod * (BSig[i] - ASig[i]); - r_result[i] >>= 3; - } - - if (DoPT) { - r_result[3] = 0; - } - - u_pos = (x + y * p_width) << 2; - p_dst[u_pos + 0] = (uint8_t)r_result[0]; - p_dst[u_pos + 1] = (uint8_t)r_result[1]; - p_dst[u_pos + 2] = (uint8_t)r_result[2]; - p_dst[u_pos + 3] = (uint8_t)r_result[3]; - } - } -} - -static void _pvrtc_decompress(Image *p_img) { - ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC1_2 && p_img->get_format() != Image::FORMAT_PVRTC1_2A && p_img->get_format() != Image::FORMAT_PVRTC1_4 && p_img->get_format() != Image::FORMAT_PVRTC1_4A); - - bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC1_2 || p_img->get_format() == Image::FORMAT_PVRTC1_2A); - - Vector<uint8_t> data = p_img->get_data(); - const uint8_t *r = data.ptr(); - - Vector<uint8_t> newdata; - newdata.resize(p_img->get_width() * p_img->get_height() * 4); - uint8_t *w = newdata.ptrw(); - - decompress_pvrtc((PVRTCBlock *)r, _2bit, p_img->get_width(), p_img->get_height(), 0, (unsigned char *)w); - - bool make_mipmaps = p_img->has_mipmaps(); - p_img->create(p_img->get_width(), p_img->get_height(), false, Image::FORMAT_RGBA8, newdata); - if (make_mipmaps) { - p_img->generate_mipmaps(); - } -} diff --git a/modules/pvr/texture_loader_pvr.h b/modules/pvr/texture_loader_pvr.h deleted file mode 100644 index 06e8e91ba2..0000000000 --- a/modules/pvr/texture_loader_pvr.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* texture_loader_pvr.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#ifndef TEXTURE_LOADER_PVR_H -#define TEXTURE_LOADER_PVR_H - -#include "core/io/resource_loader.h" -#include "scene/resources/texture.h" - -class ResourceFormatPVR : public ResourceFormatLoader { -public: - virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; - - ResourceFormatPVR(); - virtual ~ResourceFormatPVR() {} -}; - -#endif // TEXTURE_LOADER_PVR_H diff --git a/modules/svg/SCsub b/modules/svg/SCsub index c7228a8d0b..bb03147731 100644 --- a/modules/svg/SCsub +++ b/modules/svg/SCsub @@ -9,16 +9,66 @@ env_svg = env_modules.Clone() thirdparty_obj = [] -thirdparty_dir = "#thirdparty/nanosvg/" +thirdparty_dir = "#thirdparty/thorvg/" thirdparty_sources = [ - "nanosvg.cc", + "src/lib/tvgBezier.cpp", + "src/lib/tvgCanvas.cpp", + "src/lib/tvgFill.cpp", + "src/lib/tvgGlCanvas.cpp", + "src/lib/tvgInitializer.cpp", + "src/lib/tvgLinearGradient.cpp", + "src/lib/tvgLoader.cpp", + "src/lib/tvgLzw.cpp", + "src/lib/tvgPaint.cpp", + "src/lib/tvgPicture.cpp", + "src/lib/tvgRadialGradient.cpp", + "src/lib/tvgRender.cpp", + "src/lib/tvgSaver.cpp", + "src/lib/tvgScene.cpp", + "src/lib/tvgShape.cpp", + "src/lib/tvgSwCanvas.cpp", + "src/lib/tvgTaskScheduler.cpp", + "src/loaders/raw/tvgRawLoader.cpp", + "src/loaders/svg/tvgXmlParser.cpp", + "src/loaders/svg/tvgSvgUtil.cpp", + "src/loaders/svg/tvgSvgSceneBuilder.cpp", + "src/loaders/svg/tvgSvgPath.cpp", + "src/loaders/svg/tvgSvgLoader.cpp", + "src/loaders/tvg/tvgTvgBinInterpreter.cpp", + "src/loaders/tvg/tvgTvgLoader.cpp", + "src/loaders/jpg/tvgJpgLoader.cpp", + "src/loaders/jpg/tvgJpgd.cpp", + "src/loaders/external_png/tvgPngLoader.cpp", + "src/lib/sw_engine/tvgSwFill.cpp", + "src/lib/sw_engine/tvgSwImage.cpp", + "src/lib/sw_engine/tvgSwMath.cpp", + "src/lib/sw_engine/tvgSwMemPool.cpp", + "src/lib/sw_engine/tvgSwRaster.cpp", + "src/lib/sw_engine/tvgSwRenderer.cpp", + "src/lib/sw_engine/tvgSwRle.cpp", + "src/lib/sw_engine/tvgSwShape.cpp", + "src/lib/sw_engine/tvgSwStroke.cpp", + "src/savers/tvg/tvgTvgSaver.cpp", ] + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env_svg.Prepend(CPPPATH=[thirdparty_dir]) +env_svg.Prepend(CPPPATH=[thirdparty_dir + "inc"]) env_thirdparty = env_svg.Clone() env_thirdparty.disable_warnings() +env_thirdparty.Prepend( + CPPPATH=[ + thirdparty_dir + "src/lib", + thirdparty_dir + "src/lib/sw_engine", + thirdparty_dir + "src/loaders/raw", + thirdparty_dir + "src/loaders/svg", + thirdparty_dir + "src/loaders/jpg", + thirdparty_dir + "src/loaders/png", + thirdparty_dir + "src/loaders/tvg", + thirdparty_dir + "src/savers/tvg", + ] +) env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) env.modules_sources += thirdparty_obj diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index bf43d7a4ad..96b83bf25a 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -30,132 +30,118 @@ #include "image_loader_svg.h" -#include <nanosvg.h> -#include <nanosvgrast.h> - -void SVGRasterizer::rasterize(NSVGimage *p_image, float p_tx, float p_ty, float p_scale, unsigned char *p_dst, int p_w, int p_h, int p_stride) { - nsvgRasterize(rasterizer, p_image, p_tx, p_ty, p_scale, p_dst, p_w, p_h, p_stride); -} - -SVGRasterizer::SVGRasterizer() { - rasterizer = nsvgCreateRasterizer(); -} - -SVGRasterizer::~SVGRasterizer() { - nsvgDeleteRasterizer(rasterizer); -} - -SVGRasterizer ImageLoaderSVG::rasterizer; - -inline void change_nsvg_paint_color(NSVGpaint *p_paint, const uint32_t p_old, const uint32_t p_new) { - if (p_paint->type == NSVG_PAINT_COLOR) { - if (p_paint->color << 8 == p_old << 8) { - p_paint->color = (p_paint->color & 0xFF000000) | (p_new & 0x00FFFFFF); - } - } - - if (p_paint->type == NSVG_PAINT_LINEAR_GRADIENT || p_paint->type == NSVG_PAINT_RADIAL_GRADIENT) { - for (int stop_index = 0; stop_index < p_paint->gradient->nstops; stop_index++) { - if (p_paint->gradient->stops[stop_index].color << 8 == p_old << 8) { - p_paint->gradient->stops[stop_index].color = p_new; +#include "core/os/memory.h" +#include "core/variant/variant.h" + +#include <thorvg.h> + +void ImageLoaderSVG::_replace_color_property(const String &p_prefix, String &r_string) { + // Replace colors in the SVG based on what is configured in `replace_colors`. + // Used to change the colors of editor icons based on the used theme. + // The strings being replaced are typically of the form: + // fill="#5abbef" + // But can also be 3-letter codes, include alpha, be "none" or a named color + // string ("blue"). So we convert to Godot Color to compare with `replace_colors`. + + const int prefix_len = p_prefix.length(); + int pos = r_string.find(p_prefix); + while (pos != -1) { + pos += prefix_len; // Skip prefix. + int end_pos = r_string.find("\"", pos); + ERR_FAIL_COND_MSG(end_pos == -1, vformat("Malformed SVG string after property \"%s\".", p_prefix)); + const String color_code = r_string.substr(pos, end_pos - pos); + if (color_code != "none" && !color_code.begins_with("url(")) { + const Color color = Color(color_code); // Handles both HTML codes and named colors. + if (replace_colors.has(color)) { + r_string = r_string.left(pos) + "#" + replace_colors[color].operator Color().to_html(false) + r_string.substr(end_pos); } } + // Search for other occurrences. + pos = r_string.find(p_prefix, pos); } } -void ImageLoaderSVG::_convert_colors(NSVGimage *p_svg_image) { - for (NSVGshape *shape = p_svg_image->shapes; shape != nullptr; shape = shape->next) { - for (int i = 0; i < replace_colors.old_colors.size(); i++) { - change_nsvg_paint_color(&(shape->stroke), replace_colors.old_colors[i], replace_colors.new_colors[i]); - change_nsvg_paint_color(&(shape->fill), replace_colors.old_colors[i], replace_colors.new_colors[i]); - } - } -} +void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color) { + ERR_FAIL_COND(Math::is_zero_approx(p_scale)); -void ImageLoaderSVG::set_convert_colors(Dictionary *p_replace_color) { - if (p_replace_color) { - Dictionary replace_color = *p_replace_color; - for (int i = 0; i < replace_color.keys().size(); i++) { - Variant o_c = replace_color.keys()[i]; - Variant n_c = replace_color[replace_color.keys()[i]]; - if (o_c.get_type() == Variant::COLOR && n_c.get_type() == Variant::COLOR) { - Color old_color = o_c; - Color new_color = n_c; - replace_colors.old_colors.push_back(old_color.to_abgr32()); - replace_colors.new_colors.push_back(new_color.to_abgr32()); - } - } - } else { - replace_colors.old_colors.clear(); - replace_colors.new_colors.clear(); + if (p_convert_color) { + _replace_color_property("stop-color=\"", p_string); + _replace_color_property("fill=\"", p_string); + _replace_color_property("stroke=\"", p_string); } -} -Error ImageLoaderSVG::_create_image(Ref<Image> p_image, const Vector<uint8_t> *p_data, float p_scale, bool upsample, bool convert_colors) { - NSVGimage *svg_image; - const uint8_t *src_r = p_data->ptr(); - svg_image = nsvgParse((char *)src_r, "px", 96); - if (svg_image == nullptr) { - ERR_PRINT("SVG Corrupted"); - return ERR_FILE_CORRUPT; - } + std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen(); + PackedByteArray bytes = p_string.to_utf8_buffer(); - if (convert_colors) { - _convert_colors(svg_image); + tvg::Result result = picture->load((const char *)bytes.ptr(), bytes.size(), "svg", true); + if (result != tvg::Result::Success) { + return; } + float fw, fh; + picture->viewbox(nullptr, nullptr, &fw, &fh); - const float upscale = upsample ? 2.0 : 1.0; - - const int w = (int)(svg_image->width * p_scale * upscale); - ERR_FAIL_COND_V_MSG(w > Image::MAX_WIDTH, ERR_PARAMETER_RANGE_ERROR, vformat("Can't create image from SVG with scale %s, the resulting image size exceeds max width.", rtos(p_scale))); - - const int h = (int)(svg_image->height * p_scale * upscale); - ERR_FAIL_COND_V_MSG(h > Image::MAX_HEIGHT, ERR_PARAMETER_RANGE_ERROR, vformat("Can't create image from SVG with scale %s, the resulting image size exceeds max height.", rtos(p_scale))); - - Vector<uint8_t> dst_image; - dst_image.resize(w * h * 4); + uint32_t width = MIN(fw * p_scale, 16 * 1024); + uint32_t height = MIN(fh * p_scale, 16 * 1024); + picture->size(width, height); - uint8_t *dw = dst_image.ptrw(); + std::unique_ptr<tvg::SwCanvas> sw_canvas = tvg::SwCanvas::gen(); + // Note: memalloc here, be sure to memfree before any return. + uint32_t *buffer = (uint32_t *)memalloc(sizeof(uint32_t) * width * height); - rasterizer.rasterize(svg_image, 0, 0, p_scale * upscale, (unsigned char *)dw, w, h, w * 4); - - p_image->create(w, h, false, Image::FORMAT_RGBA8, dst_image); - if (upsample) { - p_image->shrink_x2(); + tvg::Result res = sw_canvas->target(buffer, width, width, height, tvg::SwCanvas::ARGB8888_STRAIGHT); + if (res != tvg::Result::Success) { + memfree(buffer); + ERR_FAIL_MSG("ImageLoaderSVG can't create image."); } - nsvgDelete(svg_image); + res = sw_canvas->push(move(picture)); + if (res != tvg::Result::Success) { + memfree(buffer); + ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + } - return OK; -} + res = sw_canvas->draw(); + if (res != tvg::Result::Success) { + memfree(buffer); + ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + } -Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, const char *p_svg_str, float p_scale, bool upsample, bool convert_colors) { - size_t str_len = strlen(p_svg_str); - Vector<uint8_t> src_data; - src_data.resize(str_len + 1); - uint8_t *src_w = src_data.ptrw(); - memcpy(src_w, p_svg_str, str_len + 1); + res = sw_canvas->sync(); + if (res != tvg::Result::Success) { + memfree(buffer); + ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + } - return _create_image(p_image, &src_data, p_scale, upsample, convert_colors); -} + Vector<uint8_t> image; + image.resize(width * height * sizeof(uint32_t)); + + for (uint32_t y = 0; y < height; y++) { + for (uint32_t x = 0; x < width; x++) { + uint32_t n = buffer[y * width + x]; + const size_t offset = sizeof(uint32_t) * width * y + sizeof(uint32_t) * x; + image.write[offset + 0] = (n >> 16) & 0xff; + image.write[offset + 1] = (n >> 8) & 0xff; + image.write[offset + 2] = n & 0xff; + image.write[offset + 3] = (n >> 24) & 0xff; + } + } -Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { - uint64_t size = f->get_length(); - Vector<uint8_t> src_image; - src_image.resize(size + 1); - uint8_t *src_w = src_image.ptrw(); - f->get_buffer(src_w, size); - src_w[size] = '\0'; + res = sw_canvas->clear(true); + memfree(buffer); - return _create_image(p_image, &src_image, p_scale, 1.0); + p_image->create(width, height, false, Image::FORMAT_RGBA8, image); } void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("svg"); - p_extensions->push_back("svgz"); } -ImageLoaderSVG::ImageLoaderSVG() { +Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) { + String svg = p_fileaccess->get_as_utf8_string(); + create_image_from_string(p_image, svg, p_scale, false, false); + ERR_FAIL_COND_V(p_image->is_empty(), FAILED); + if (p_force_linear) { + p_image->srgb_to_linear(); + } + return OK; } - -ImageLoaderSVG::ReplaceColors ImageLoaderSVG::replace_colors; diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h index 6052bf9831..d0bd71d92d 100644 --- a/modules/svg/image_loader_svg.h +++ b/modules/svg/image_loader_svg.h @@ -32,42 +32,18 @@ #define IMAGE_LOADER_SVG_H #include "core/io/image_loader.h" -#include "core/string/ustring.h" - -/** - @author Daniel Ramirez <djrmuv@gmail.com> -*/ - -// Forward declare and include thirdparty headers in .cpp. -struct NSVGrasterizer; -struct NSVGimage; - -class SVGRasterizer { - NSVGrasterizer *rasterizer; - -public: - void rasterize(NSVGimage *p_image, float p_tx, float p_ty, float p_scale, unsigned char *p_dst, int p_w, int p_h, int p_stride); - - SVGRasterizer(); - ~SVGRasterizer(); -}; class ImageLoaderSVG : public ImageFormatLoader { - static struct ReplaceColors { - List<uint32_t> old_colors; - List<uint32_t> new_colors; - } replace_colors; - static SVGRasterizer rasterizer; - static void _convert_colors(NSVGimage *p_svg_image); - static Error _create_image(Ref<Image> p_image, const Vector<uint8_t> *p_data, float p_scale, bool upsample, bool convert_colors = false); + Dictionary replace_colors; + void _replace_color_property(const String &p_prefix, String &r_string); public: - static void set_convert_colors(Dictionary *p_replace_color = nullptr); - static Error create_image_from_string(Ref<Image> p_image, const char *p_svg_str, float p_scale, bool upsample, bool convert_colors = false); + // Called by the editor to handle theme icon colors. + void set_replace_colors(Dictionary p_replace_colors) { replace_colors = p_replace_colors; } + void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color); - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - ImageLoaderSVG(); + virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; }; -#endif +#endif // IMAGE_LOADER_SVG_H diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp index 1560af95c3..a4341c6f1e 100644 --- a/modules/svg/register_types.cpp +++ b/modules/svg/register_types.cpp @@ -32,13 +32,23 @@ #include "image_loader_svg.h" +#include <thorvg.h> + static ImageLoaderSVG *image_loader_svg = nullptr; void register_svg_types() { + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; + if (tvg::Initializer::init(tvgEngine, 0) != tvg::Result::Success) { + return; + } image_loader_svg = memnew(ImageLoaderSVG); ImageLoader::add_image_format_loader(image_loader_svg); } void unregister_svg_types() { + if (!image_loader_svg) { + return; + } memdelete(image_loader_svg); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index f1945f62cb..e0ee809331 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -322,7 +322,7 @@ _FORCE_INLINE_ bool is_underscore(char32_t p_char) { /*************************************************************************/ String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite"; -uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE; +uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION; bool TextServerAdvanced::has_feature(Feature p_feature) const { return (interface_features & p_feature) == p_feature; @@ -2573,7 +2573,7 @@ int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, cha return FT_Get_Char_Index(fd->cache[size]->face, p_char); } } else { - return 0; + return (int32_t)p_char; } #else return (int32_t)p_char; @@ -2841,6 +2841,24 @@ Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font_ return out; } +void TextServerAdvanced::font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->feature_overrides = p_overrides; +} + +Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(RID p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Dictionary()); + + MutexLock lock(fd->mutex); + return fd->feature_overrides; +} + Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -3011,6 +3029,14 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped return sd->direction; } +TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR); + + MutexLock lock(sd->mutex); + return sd->para_direction; +} + void TextServerAdvanced::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); @@ -3564,7 +3590,11 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, float justification_width; if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) { if (sd->overrun_trim_data.trim_pos >= 0) { - start_pos = sd->overrun_trim_data.trim_pos; + if (sd->para_direction == DIRECTION_RTL) { + start_pos = sd->overrun_trim_data.trim_pos; + } else { + end_pos = sd->overrun_trim_data.trim_pos; + } justification_width = sd->width_trimmed; } else { return sd->width; @@ -3574,6 +3604,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, } if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == JUSTIFICATION_TRIM_EDGE_SPACES) { + // Trim spaces. while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat; sd->glyphs.write[start_pos].advance = 0; @@ -3584,6 +3615,14 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, sd->glyphs.write[end_pos].advance = 0; end_pos -= sd->glyphs[end_pos].count; } + } else { + // Skip breaks, but do not reset size. + while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { + start_pos += sd->glyphs[start_pos].count; + } + while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { + end_pos -= sd->glyphs[end_pos].count; + } } int space_count = 0; @@ -3592,7 +3631,10 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, const Glyph &gl = sd->glyphs[i]; if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) { - elongation_count++; + if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) { + // Expand once per elongation sequence. + elongation_count++; + } } if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { space_count++; @@ -3606,12 +3648,17 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, Glyph &gl = sd->glyphs.write[i]; if (gl.count > 0) { if (((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) && (gl.advance > 0)) { - int count = delta_width_per_kashida / gl.advance; - int prev_count = gl.repeat; - if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { - gl.repeat = MAX(count, 0); + if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) { + // Expand once per elongation sequence. + int count = delta_width_per_kashida / gl.advance; + int prev_count = gl.repeat; + if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + gl.repeat = MAX(count, 0); + } else { + gl.repeat = MAX(count + 1, 1); + } + justification_width += (gl.repeat - prev_count) * gl.advance; } - justification_width += (gl.repeat - prev_count) * gl.advance; } } } @@ -3653,7 +3700,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, sd->width = justification_width; } - return sd->width; + return justification_width; } float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) { @@ -3668,6 +3715,12 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat3 const_cast<TextServerAdvanced *>(this)->shaped_text_update_breaks(p_shaped); } + for (int i = 0; i < p_tab_stops.size(); i++) { + if (p_tab_stops[i] <= 0) { + return 0.f; + } + } + int tab_index = 0; float off = 0.f; @@ -3735,23 +3788,56 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl return; } + Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans; + if (sd->parent != RID()) { + ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent); + ERR_FAIL_COND(!parent_sd->valid); + spans = parent_sd->spans; + } + + if (spans.size() == 0) { + return; + } + int sd_size = sd->glyphs.size(); - RID last_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; int last_gl_font_size = sd_glyphs[sd_size - 1].font_size; - int32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, last_gl_font_size, '.'); - Vector2 dot_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, dot_gl_idx); - int32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, last_gl_font_size, ' '); - Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, whitespace_gl_idx); + + // Find usable fonts, if fonts from the last glyph do not have required chars. + RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!font_has_char(dot_gl_font_rid, '.')) { + const Vector<RID> &fonts = spans[spans.size() - 1].fonts; + for (const RID &font : fonts) { + if (font_has_char(font, '.')) { + dot_gl_font_rid = font; + break; + } + } + } + RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!font_has_char(whitespace_gl_font_rid, '.')) { + const Vector<RID> &fonts = spans[spans.size() - 1].fonts; + for (const RID &font : fonts) { + if (font_has_char(font, ' ')) { + whitespace_gl_font_rid = font; + break; + } + } + } + + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.') : -10; + Vector2 dot_adv = dot_gl_font_rid.is_valid() ? font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ') : -10; + Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; - if (add_ellipsis) { - ellipsis_width = 3 * dot_adv.x + font_get_spacing(last_gl_font_rid, last_gl_font_size, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); + if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { + ellipsis_width = 3 * dot_adv.x + font_get_spacing(whitespace_gl_font_rid, last_gl_font_size, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); } int ell_min_characters = 6; float width = sd->width; - bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL); + bool is_rtl = sd->para_direction == DIRECTION_RTL; int trim_pos = (is_rtl) ? sd_size : 0; int ellipsis_pos = (enforce_ellipsis) ? 0 : -1; @@ -3809,23 +3895,25 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl gl.count = 1; gl.advance = whitespace_adv.x; gl.index = whitespace_gl_idx; - gl.font_rid = last_gl_font_rid; + gl.font_rid = whitespace_gl_font_rid; gl.font_size = last_gl_font_size; gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); } // Add ellipsis dots. - Glyph gl; - gl.count = 1; - gl.repeat = 3; - gl.advance = dot_adv.x; - gl.index = dot_gl_idx; - gl.font_rid = last_gl_font_rid; - gl.font_size = last_gl_font_size; - gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); - - sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); + if (dot_gl_idx != 0) { + Glyph gl; + gl.count = 1; + gl.repeat = 3; + gl.advance = dot_adv.x; + gl.index = dot_gl_idx; + gl.font_rid = dot_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); + + sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); + } } sd->text_trimmed = true; @@ -3896,21 +3984,19 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { for (int j = r_start; j < r_end; j++) { char32_t c = sd->text[j - sd->start]; if (is_whitespace(c)) { - breaks[j] = false; + breaks[j + 1] = false; } if (is_linebreak(c)) { - breaks[j] = true; + breaks[j + 1] = true; } } } else { while (ubrk_next(bi) != UBRK_DONE) { - int pos = _convert_pos(sd, ubrk_current(bi)) + r_start - 1; - if (pos != r_end) { - if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_HARD) && (ubrk_getRuleStatus(bi) < UBRK_LINE_HARD_LIMIT)) { - breaks[pos] = true; - } else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) { - breaks[pos] = false; - } + int pos = _convert_pos(sd, ubrk_current(bi)) + r_start; + if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_HARD) && (ubrk_getRuleStatus(bi) < UBRK_LINE_HARD_LIMIT)) { + breaks[pos] = true; + } else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) { + breaks[pos] = false; } } } @@ -3954,34 +4040,46 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { if (is_underscore(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_UNDERSCORE; } - if (breaks.has(sd->glyphs[i].start)) { - if (breaks[sd->glyphs[i].start]) { + if (breaks.has(sd_glyphs[i].end)) { + if (breaks[sd_glyphs[i].end] && (is_linebreak(c))) { sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; + } else if (is_whitespace(c)) { + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; } else { - if (is_whitespace(c)) { - sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; + int count = sd_glyphs[i].count; + // Do not add extra space at the end of the line. + if (sd_glyphs[i].end == sd->end) { + continue; + } + // Do not add extra space after existing space. + if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { + if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + continue; + } } else { - Glyph gl; - gl.start = sd_glyphs[i].start; - gl.end = sd_glyphs[i].end; - gl.count = 1; - gl.font_rid = sd_glyphs[i].font_rid; - gl.font_size = sd_glyphs[i].font_size; - gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL; - if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) { - gl.flags |= GRAPHEME_IS_RTL; - sd->glyphs.insert(i, gl); // Insert before. - } else { - sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after. + if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + continue; } - - // Update write pointer and size. - sd_size = sd->glyphs.size(); - sd_glyphs = sd->glyphs.ptrw(); - - i += sd_glyphs[i].count; - continue; } + Glyph gl; + gl.start = sd_glyphs[i].start; + gl.end = sd_glyphs[i].end; + gl.count = 1; + gl.font_rid = sd_glyphs[i].font_rid; + gl.font_size = sd_glyphs[i].font_size; + gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | GRAPHEME_IS_SPACE; + if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { + gl.flags |= GRAPHEME_IS_RTL; + sd->glyphs.insert(i, gl); // Insert before. + } else { + sd->glyphs.insert(i + count, gl); // Insert after. + } + i += count; + + // Update write pointer and size. + sd_size = sd->glyphs.size(); + sd_glyphs = sd->glyphs.ptrw(); + continue; } } @@ -4127,53 +4225,80 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { sd->sort_valid = false; sd->glyphs_logical.clear(); - int sd_size = sd->glyphs.size(); + Glyph *sd_glyphs = sd->glyphs.ptrw(); + int sd_size = sd->glyphs.size(); if (jstops.size() > 0) { for (int i = 0; i < sd_size; i++) { - if (sd->glyphs[i].count > 0) { - if (jstops.has(sd->glyphs[i].start)) { - char32_t c = sd->text[sd->glyphs[i].start - sd->start]; + if (sd_glyphs[i].count > 0) { + char32_t c = sd->text[sd_glyphs[i].start - sd->start]; + if (c == 0x0640) { + sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION; + } + if (jstops.has(sd_glyphs[i].start)) { if (c == 0xfffc) { continue; } - if (jstops[sd->glyphs[i].start]) { - if (c == 0x0640) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_ELONGATION; - } else { - if (sd->glyphs[i].font_rid != RID()) { + if (jstops[sd_glyphs[i].start]) { + if (c != 0x0640) { + if (sd_glyphs[i].font_rid != RID()) { Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size); - if ((gl.flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) { - gl.start = sd->glyphs[i].start; - gl.end = sd->glyphs[i].end; + if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) { + gl.start = sd_glyphs[i].start; + gl.end = sd_glyphs[i].end; gl.repeat = 0; gl.count = 1; if (sd->orientation == ORIENTATION_HORIZONTAL) { - gl.y_off = sd->glyphs[i].y_off; + gl.y_off = sd_glyphs[i].y_off; } else { - gl.x_off = sd->glyphs[i].x_off; + gl.x_off = sd_glyphs[i].x_off; } gl.flags |= GRAPHEME_IS_ELONGATION | GRAPHEME_IS_VIRTUAL; sd->glyphs.insert(i, gl); i++; + + // Update write pointer and size. + sd_size = sd->glyphs.size(); + sd_glyphs = sd->glyphs.ptrw(); + continue; } } } - } else if (!is_whitespace(c)) { + } else if ((sd_glyphs[i].flags & GRAPHEME_IS_SPACE) != GRAPHEME_IS_SPACE) { + int count = sd_glyphs[i].count; + // Do not add extra spaces at the end of the line. + if (sd_glyphs[i].end == sd->end) { + continue; + } + // Do not add extra space after existing space. + if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { + if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + continue; + } + } else { + if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + continue; + } + } + // Inject virtual space for alignment. Glyph gl; - gl.start = sd->glyphs[i].start; - gl.end = sd->glyphs[i].end; + gl.start = sd_glyphs[i].start; + gl.end = sd_glyphs[i].end; gl.count = 1; - gl.font_rid = sd->glyphs[i].font_rid; - gl.font_size = sd->glyphs[i].font_size; + gl.font_rid = sd_glyphs[i].font_rid; + gl.font_size = sd_glyphs[i].font_size; gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL; - if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) { + if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { gl.flags |= GRAPHEME_IS_RTL; sd->glyphs.insert(i, gl); // Insert before. } else { - sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after. + sd->glyphs.insert(i + count, gl); // Insert after. } - i += sd->glyphs[i].count; + i += count; + + // Update write pointer and size. + sd_size = sd->glyphs.size(); + sd_glyphs = sd->glyphs.ptrw(); continue; } } @@ -4231,6 +4356,24 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char return gl; } +_FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs) { + for (const Variant *ftr = p_source.next(nullptr); ftr != nullptr; ftr = p_source.next(ftr)) { + int32_t values = p_source[*ftr]; + if (values >= 0) { + hb_feature_t feature; + if (ftr->get_type() == Variant::STRING) { + feature.tag = name_to_tag(*ftr); + } else { + feature.tag = *ftr; + } + feature.value = values; + feature.start = 0; + feature.end = -1; + r_ftrs.push_back(feature); + } + } +} + void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index) { int fs = p_sd->spans[p_span].font_size; if (p_fb_index >= p_fonts.size()) { @@ -4287,17 +4430,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start); Vector<hb_feature_t> ftrs; - for (const Variant *ftr = p_sd->spans[p_span].features.next(nullptr); ftr != nullptr; ftr = p_sd->spans[p_span].features.next(ftr)) { - double values = p_sd->spans[p_span].features[*ftr]; - if (values >= 0) { - hb_feature_t feature; - feature.tag = *ftr; - feature.value = values; - feature.start = 0; - feature.end = -1; - ftrs.push_back(feature); - } - } + _add_featuers(font_get_opentype_feature_overrides(f), ftrs); + _add_featuers(p_sd->spans[p_span].features, ftrs); + hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size()); unsigned int glyph_count = 0; @@ -5094,6 +5229,40 @@ String TextServerAdvanced::strip_diacritics(const String &p_string) const { return result; } +String TextServerAdvanced::string_to_upper(const String &p_string, const String &p_language) const { + // Convert to UTF-16. + Char16String utf16 = p_string.utf16(); + + Char16String upper; + UErrorCode err = U_ZERO_ERROR; + int32_t len = u_strToUpper(nullptr, 0, utf16.ptr(), -1, p_language.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err)); + upper.resize(len); + err = U_ZERO_ERROR; + u_strToUpper(upper.ptrw(), len, utf16.ptr(), -1, p_language.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err)); + + // Convert back to UTF-32. + return String::utf16(upper.ptr(), len); +} + +String TextServerAdvanced::string_to_lower(const String &p_string, const String &p_language) const { + // Convert to UTF-16. + Char16String utf16 = p_string.utf16(); + + Char16String lower; + UErrorCode err = U_ZERO_ERROR; + int32_t len = u_strToLower(nullptr, 0, utf16.ptr(), -1, p_language.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err)); + lower.resize(len); + err = U_ZERO_ERROR; + u_strToLower(lower.ptrw(), len, utf16.ptr(), -1, p_language.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err)); + + // Convert back to UTF-32. + return String::utf16(lower.ptr(), len); +} + TextServerAdvanced::TextServerAdvanced() { _insert_num_systems_lang(); _insert_feature_sets(); diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index fb9446da9f..f2ae24cae6 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -187,6 +187,7 @@ class TextServerAdvanced : public TextServer { Set<uint32_t> supported_scripts; Dictionary supported_features; Dictionary supported_varaitions; + Dictionary feature_overrides; // Language/script support override. Map<String, bool> language_support_overrides; @@ -272,6 +273,7 @@ class TextServerAdvanced : public TextServer { bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const; void _shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index); Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size); + _FORCE_INLINE_ void _add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs); // HarfBuzz bitmap font interface. @@ -447,6 +449,9 @@ public: virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override; virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override; + virtual void font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) override; + virtual Dictionary font_get_opentype_feature_overrides(RID p_font_rid) const override; + virtual Dictionary font_supported_feature_list(RID p_font_rid) const override; virtual Dictionary font_supported_variation_list(RID p_font_rid) const override; @@ -461,6 +466,7 @@ public: virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override; virtual Direction shaped_text_get_direction(RID p_shaped) const override; + virtual Direction shaped_text_get_inferred_direction(RID p_shaped) const override; virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; @@ -521,6 +527,9 @@ public: virtual String strip_diacritics(const String &p_string) const override; + virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; + virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + TextServerAdvanced(); ~TextServerAdvanced(); }; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 1f7c5427be..ffbd2da22d 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -32,6 +32,7 @@ #include "core/error/error_macros.h" #include "core/string/print_string.h" +#include "core/string/ucaps.h" #include "modules/modules_enabled.gen.h" // For freetype, msdfgen. @@ -1995,6 +1996,24 @@ Vector<String> TextServerFallback::font_get_script_support_overrides(RID p_font_ return out; } +void TextServerFallback::font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->feature_overrides = p_overrides; +} + +Dictionary TextServerFallback::font_get_opentype_feature_overrides(RID p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Dictionary()); + + MutexLock lock(fd->mutex); + return fd->feature_overrides; +} + Dictionary TextServerFallback::font_supported_feature_list(RID p_font_rid) const { return Dictionary(); } @@ -2110,6 +2129,10 @@ TextServer::Direction TextServerFallback::shaped_text_get_direction(RID p_shaped return TextServer::DIRECTION_LTR; } +TextServer::Direction TextServerFallback::shaped_text_get_inferred_direction(RID p_shaped) const { + return TextServer::DIRECTION_LTR; +} + void TextServerFallback::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { _THREAD_SAFE_METHOD_ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); @@ -2613,17 +2636,38 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, } } + float justification_width; + if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) { + if (sd->overrun_trim_data.trim_pos >= 0) { + end_pos = sd->overrun_trim_data.trim_pos; + justification_width = sd->width_trimmed; + } else { + return sd->width; + } + } else { + justification_width = sd->width; + } + if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == JUSTIFICATION_TRIM_EDGE_SPACES) { + // Trim spaces. while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { - sd->width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat; + justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat; sd->glyphs.write[start_pos].advance = 0; start_pos += sd->glyphs[start_pos].count; } while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { - sd->width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat; + justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat; sd->glyphs.write[end_pos].advance = 0; end_pos -= sd->glyphs[end_pos].count; } + } else { + // Skip breaks, but do not reset size. + while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD)) { + start_pos += sd->glyphs[start_pos].count; + } + while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD)) { + end_pos -= sd->glyphs[end_pos].count; + } } int space_count = 0; @@ -2637,20 +2681,28 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, } if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) { - float delta_width_per_space = (p_width - sd->width) / space_count; + float delta_width_per_space = (p_width - justification_width) / space_count; for (int i = start_pos; i <= end_pos; i++) { Glyph &gl = sd->glyphs.write[i]; if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { float old_adv = gl.advance; gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size)); - sd->width += (gl.advance - old_adv); + justification_width += (gl.advance - old_adv); } } } } - return sd->width; + if (Math::floor(p_width) < Math::floor(justification_width)) { + sd->fit_width_minimum_reached = true; + } + + if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) != JUSTIFICATION_CONSTRAIN_ELLIPSIS) { + sd->width = justification_width; + } + + return justification_width; } float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) { @@ -2665,6 +2717,12 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3 const_cast<TextServerFallback *>(this)->shaped_text_update_breaks(p_shaped); } + for (int i = 0; i < p_tab_stops.size(); i++) { + if (p_tab_stops[i] <= 0) { + return 0.f; + } + } + int tab_index = 0; float off = 0.f; @@ -2745,6 +2803,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; } if (is_linebreak(c)) { + sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; } if (c == 0x0009 || c == 0x000b) { @@ -2803,17 +2862,50 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl return; } + Vector<ShapedTextData::Span> &spans = sd->spans; + if (sd->parent != RID()) { + ShapedTextData *parent_sd = shaped_owner.get_or_null(sd->parent); + ERR_FAIL_COND(!parent_sd->valid); + spans = parent_sd->spans; + } + + if (spans.size() == 0) { + return; + } + int sd_size = sd->glyphs.size(); - RID last_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; int last_gl_font_size = sd_glyphs[sd_size - 1].font_size; - int32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, '.', 0); - Vector2 dot_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, dot_gl_idx); - int32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' ', 0); - Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, whitespace_gl_idx); + + // Find usable fonts, if fonts from the last glyph do not have required chars. + RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!font_has_char(dot_gl_font_rid, '.')) { + const Vector<RID> &fonts = spans[spans.size() - 1].fonts; + for (const RID &font : fonts) { + if (font_has_char(font, '.')) { + dot_gl_font_rid = font; + break; + } + } + } + RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; + if (!font_has_char(whitespace_gl_font_rid, '.')) { + const Vector<RID> &fonts = spans[spans.size() - 1].fonts; + for (const RID &font : fonts) { + if (font_has_char(font, ' ')) { + whitespace_gl_font_rid = font; + break; + } + } + } + + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.') : -10; + Vector2 dot_adv = dot_gl_font_rid.is_valid() ? font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ') : -10; + Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; - if (add_ellipsis) { - ellipsis_width = 3 * dot_adv.x + font_get_spacing(last_gl_font_rid, last_gl_font_size, TextServer::SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); + if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { + ellipsis_width = 3 * dot_adv.x + font_get_spacing(whitespace_gl_font_rid, last_gl_font_size, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0); } int ell_min_characters = 6; @@ -2867,23 +2959,25 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl gl.count = 1; gl.advance = whitespace_adv.x; gl.index = whitespace_gl_idx; - gl.font_rid = last_gl_font_rid; + gl.font_rid = whitespace_gl_font_rid; gl.font_size = last_gl_font_size; gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL; sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); } // Add ellipsis dots. - Glyph gl; - gl.count = 1; - gl.repeat = 3; - gl.advance = dot_adv.x; - gl.index = dot_gl_idx; - gl.font_rid = last_gl_font_rid; - gl.font_size = last_gl_font_size; - gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL; + if (dot_gl_idx != 0) { + Glyph gl; + gl.count = 1; + gl.repeat = 3; + gl.advance = dot_adv.x; + gl.index = dot_gl_idx; + gl.font_rid = dot_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL; - sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); + sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); + } } sd->text_trimmed = true; @@ -2999,13 +3093,13 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { if (gl.font_rid.is_valid()) { if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x; + gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x); gl.x_off = 0; gl.y_off = 0; sd->ascent = MAX(sd->ascent, font_get_ascent(gl.font_rid, gl.font_size)); sd->descent = MAX(sd->descent, font_get_descent(gl.font_rid, gl.font_size)); } else { - gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y; + gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y); gl.x_off = -Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5); gl.y_off = font_get_ascent(gl.font_rid, gl.font_size); sd->ascent = MAX(sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); @@ -3263,6 +3357,34 @@ float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) cons return sd->uthk; } +String TextServerFallback::string_to_upper(const String &p_string, const String &p_language) const { + String upper = p_string; + + for (int i = 0; i < upper.size(); i++) { + const char32_t s = upper[i]; + const char32_t t = _find_upper(s); + if (s != t) { // avoid copy on write + upper[i] = t; + } + } + + return upper; +} + +String TextServerFallback::string_to_lower(const String &p_string, const String &p_language) const { + String lower = p_string; + + for (int i = 0; i < lower.size(); i++) { + const char32_t s = lower[i]; + const char32_t t = _find_lower(s); + if (s != t) { // avoid copy on write + lower[i] = t; + } + } + + return lower; +} + TextServerFallback::TextServerFallback() { _insert_feature_sets(); }; diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index d47fa44f8f..b356b90d2c 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -150,6 +150,7 @@ class TextServerFallback : public TextServer { bool face_init = false; Dictionary supported_varaitions; + Dictionary feature_overrides; // Language/script support override. Map<String, bool> language_support_overrides; @@ -357,6 +358,9 @@ public: virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override; virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override; + virtual void font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) override; + virtual Dictionary font_get_opentype_feature_overrides(RID p_font_rid) const override; + virtual Dictionary font_supported_feature_list(RID p_font_rid) const override; virtual Dictionary font_supported_variation_list(RID p_font_rid) const override; @@ -371,6 +375,7 @@ public: virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override; virtual Direction shaped_text_get_direction(RID p_shaped) const override; + virtual Direction shaped_text_get_inferred_direction(RID p_shaped) const override; virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; @@ -425,6 +430,9 @@ public: virtual float shaped_text_get_underline_position(RID p_shaped) const override; virtual float shaped_text_get_underline_thickness(RID p_shaped) const override; + virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; + virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + TextServerFallback(); ~TextServerFallback(); }; diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index feaff5925f..282a2a1662 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -33,9 +33,6 @@ #include "core/io/image_loader.h" -/** - @author SaracenOne -*/ class ImageLoaderTGA : public ImageFormatLoader { enum tga_type_e { TGA_TYPE_NO_DATA = 0, @@ -81,4 +78,4 @@ public: ImageLoaderTGA(); }; -#endif +#endif // IMAGE_LOADER_TGA_H diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index bc40f4f9b4..ec1a8a6b42 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -1973,7 +1973,7 @@ void VisualScriptEditor::input(const Ref<InputEvent> &p_event) { // GUI input for VS Editor Plugin Ref<InputEventMouseButton> key = p_event; - if (key.is_valid() && !key->is_pressed()) { + if (key.is_valid() && key->is_pressed()) { mouse_up_position = get_screen_position() + get_local_mouse_position(); } } @@ -1982,10 +1982,28 @@ void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> key = p_event; if (key.is_valid() && key->is_pressed() && key->get_button_mask() == MouseButton::RIGHT) { - saved_position = graph->get_local_mouse_position(); + bool is_empty_selection = true; - Point2 gpos = get_screen_position() + get_local_mouse_position(); - _generic_search(script->get_instance_base_type(), gpos); + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); + if (gn && gn->is_selected()) { + is_empty_selection = false; + break; + } + } + if (is_empty_selection && clipboard->nodes.is_empty()) { + _generic_search(script->get_instance_base_type(), mouse_up_position); + } else { + popup_menu->set_item_disabled(int(EDIT_CUT_NODES), is_empty_selection); + popup_menu->set_item_disabled(int(EDIT_COPY_NODES), is_empty_selection); + popup_menu->set_item_disabled(int(EDIT_PASTE_NODES), clipboard->nodes.is_empty()); + popup_menu->set_item_disabled(int(EDIT_DELETE_NODES), is_empty_selection); + popup_menu->set_item_disabled(int(EDIT_DUPLICATE_NODES), is_empty_selection); + popup_menu->set_item_disabled(int(EDIT_CLEAR_COPY_BUFFER), clipboard->nodes.is_empty()); + + popup_menu->set_position(mouse_up_position); + popup_menu->popup(); + } } } @@ -2637,6 +2655,15 @@ String VisualScriptEditor::get_name() { } Ref<Texture2D> VisualScriptEditor::get_theme_icon() { + String icon_name = "VisualScript"; + if (script->is_built_in()) { + icon_name += "Internal"; + } + + if (Control::has_theme_icon(icon_name, "EditorIcons")) { + return Control::get_theme_icon(icon_name, SNAME("EditorIcons")); + } + return Control::get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons")); } @@ -3753,6 +3780,11 @@ void VisualScriptEditor::_toggle_scripts_pressed() { void VisualScriptEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + graph->set_panning_scheme((GraphEdit::PanningScheme)EDITOR_GET("interface/editors/sub_editor_panning_scheme").operator int()); + } break; + case NOTIFICATION_READY: { variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members)); variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED); @@ -3868,6 +3900,9 @@ void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_ void VisualScriptEditor::_menu_option(int p_what) { switch (p_what) { + case EDIT_ADD_NODE: { + _generic_search(script->get_instance_base_type(), mouse_up_position); + } break; case EDIT_DELETE_NODES: { _on_nodes_delete(); } break; @@ -3908,6 +3943,9 @@ void VisualScriptEditor::_menu_option(int p_what) { case EDIT_PASTE_NODES: { _on_nodes_paste(); } break; + case EDIT_DUPLICATE_NODES: { + _on_nodes_duplicate(); + } break; case EDIT_CREATE_FUNCTION: { // Create Function. Map<int, Ref<VisualScriptNode>> nodes; @@ -4135,6 +4173,12 @@ void VisualScriptEditor::_menu_option(int p_what) { case REFRESH_GRAPH: { _update_graph(); } break; + case EDIT_CLEAR_COPY_BUFFER: { + clipboard->nodes.clear(); + clipboard->nodes_positions.clear(); + clipboard->data_connections.clear(); + clipboard->sequence_connections.clear(); + } break; } } @@ -4322,9 +4366,6 @@ VisualScriptEditor::VisualScriptEditor() { if (!clipboard) { clipboard = memnew(Clipboard); } - updating_graph = false; - saved_pos_dirty = false; - saved_position = Vector2(0, 0); edit_menu = memnew(MenuButton); edit_menu->set_shortcut_context(this); @@ -4556,6 +4597,18 @@ VisualScriptEditor::VisualScriptEditor() { new_virtual_method_select = memnew(VisualScriptPropertySelector); add_child(new_virtual_method_select); new_virtual_method_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_new_virtual_method)); + + popup_menu = memnew(PopupMenu); + add_child(popup_menu); + popup_menu->add_item(TTR("Add Node"), EDIT_ADD_NODE); + popup_menu->add_separator(); + popup_menu->add_item(TTR("Cut"), EDIT_CUT_NODES); + popup_menu->add_item(TTR("Copy"), EDIT_COPY_NODES); + popup_menu->add_item(TTR("Paste"), EDIT_PASTE_NODES); + popup_menu->add_item(TTR("Delete"), EDIT_DELETE_NODES); + popup_menu->add_item(TTR("Duplicate"), EDIT_DUPLICATE_NODES); + popup_menu->add_item(TTR("Clear Copy Buffer"), EDIT_CLEAR_COPY_BUFFER); + popup_menu->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option)); } VisualScriptEditor::~VisualScriptEditor() { diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h index b232b05391..90e4fb9d56 100644 --- a/modules/visual_script/editor/visual_script_editor.h +++ b/modules/visual_script/editor/visual_script_editor.h @@ -54,13 +54,18 @@ class VisualScriptEditor : public ScriptEditorBase { }; enum { - EDIT_DELETE_NODES, - EDIT_TOGGLE_BREAKPOINT, - EDIT_FIND_NODE_TYPE, - EDIT_COPY_NODES, + EDIT_ADD_NODE, + EDIT_SEPARATOR, // popup menu separator - ignored EDIT_CUT_NODES, + EDIT_COPY_NODES, EDIT_PASTE_NODES, + EDIT_DELETE_NODES, + EDIT_DUPLICATE_NODES, + EDIT_CLEAR_COPY_BUFFER, + EDIT_CREATE_FUNCTION, + EDIT_TOGGLE_BREAKPOINT, + EDIT_FIND_NODE_TYPE, REFRESH_GRAPH, }; @@ -123,7 +128,7 @@ class VisualScriptEditor : public ScriptEditorBase { Label *select_func_text; - bool updating_graph; + bool updating_graph = false; void _show_hint(const String &p_hint); void _hide_timer(); @@ -162,7 +167,8 @@ class VisualScriptEditor : public ScriptEditorBase { static Clipboard *clipboard; - PopupMenu *member_popup; + PopupMenu *popup_menu = nullptr; + PopupMenu *member_popup = nullptr; MemberType member_type; String member_name; @@ -172,8 +178,7 @@ class VisualScriptEditor : public ScriptEditorBase { Vector2 port_action_pos; int port_action_new_node; - bool saved_pos_dirty; - Vector2 saved_position; + bool saved_pos_dirty = false; Vector2 mouse_up_position; diff --git a/modules/visual_script/icons/VisualScriptInternal.svg b/modules/visual_script/icons/VisualScriptInternal.svg new file mode 100644 index 0000000000..ea83047a29 --- /dev/null +++ b/modules/visual_script/icons/VisualScriptInternal.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="3" cy="3.000024" fill="#6e6e6e" r="0"/><path d="m11 10a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0"/><path d="m3 10v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z" fill="#e0e0e0"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2z" fill="none" stroke="#e0e0e0"/></svg> diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index b39f984a80..2abbd19e12 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -176,7 +176,7 @@ PropertyInfo VisualScriptExpression::get_output_value_port_info(int p_idx) const } String VisualScriptExpression::get_caption() const { - return "Expression"; + return TTR("Expression"); } String VisualScriptExpression::get_text() const { diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index f8b03f2eea..fd1861abc4 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -70,7 +70,7 @@ PropertyInfo VisualScriptReturn::get_output_value_port_info(int p_idx) const { } String VisualScriptReturn::get_caption() const { - return "Return"; + return TTR("Return"); } String VisualScriptReturn::get_text() const { @@ -201,11 +201,11 @@ PropertyInfo VisualScriptCondition::get_output_value_port_info(int p_idx) const } String VisualScriptCondition::get_caption() const { - return "Condition"; + return TTR("Condition"); } String VisualScriptCondition::get_text() const { - return "if (cond) is: "; + return TTR("if (cond) is:"); } void VisualScriptCondition::_bind_methods() { @@ -281,11 +281,11 @@ PropertyInfo VisualScriptWhile::get_output_value_port_info(int p_idx) const { } String VisualScriptWhile::get_caption() const { - return "While"; + return TTR("While"); } String VisualScriptWhile::get_text() const { - return "while (cond): "; + return TTR("while (cond):"); } void VisualScriptWhile::_bind_methods() { @@ -364,11 +364,11 @@ PropertyInfo VisualScriptIterator::get_output_value_port_info(int p_idx) const { } String VisualScriptIterator::get_caption() const { - return "Iterator"; + return TTR("Iterator"); } String VisualScriptIterator::get_text() const { - return "for (elem) in (input): "; + return TTR("for (elem) in (input):"); } void VisualScriptIterator::_bind_methods() { @@ -478,11 +478,11 @@ PropertyInfo VisualScriptSequence::get_output_value_port_info(int p_idx) const { } String VisualScriptSequence::get_caption() const { - return "Sequence"; + return TTR("Sequence"); } String VisualScriptSequence::get_text() const { - return "in order: "; + return TTR("in order:"); } void VisualScriptSequence::set_steps(int p_steps) { @@ -587,11 +587,11 @@ PropertyInfo VisualScriptSwitch::get_output_value_port_info(int p_idx) const { } String VisualScriptSwitch::get_caption() const { - return "Switch"; + return TTR("Switch"); } String VisualScriptSwitch::get_text() const { - return "'input' is:"; + return TTR("'input' is:"); } class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance { @@ -720,14 +720,14 @@ PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const { } String VisualScriptTypeCast::get_caption() const { - return "Type Cast"; + return TTR("Type Cast"); } String VisualScriptTypeCast::get_text() const { if (!script.is_empty()) { - return "Is " + script.get_file() + "?"; + return vformat(TTR("Is %s?"), script.get_file()); } else { - return "Is " + base_type + "?"; + return vformat(TTR("Is %s?"), base_type); } } diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 27d23a142e..cc18d48dd8 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -261,13 +261,13 @@ String VisualScriptFunctionCall::get_text() const { String text; if (call_mode == CALL_MODE_BASIC_TYPE) { - text = String("On ") + Variant::get_type_name(basic_type); + text = vformat(TTR("On %s"), Variant::get_type_name(basic_type)); } else if (call_mode == CALL_MODE_INSTANCE) { - text = String("On ") + base_type; + text = vformat(TTR("On %s"), base_type); } else if (call_mode == CALL_MODE_NODE_PATH) { text = "[" + String(base_path.simplified()) + "]"; } else if (call_mode == CALL_MODE_SELF) { - text = "On Self"; + text = TTR("On Self"); } else if (call_mode == CALL_MODE_SINGLETON) { text = String(singleton) + ":" + String(function) + "()"; } @@ -1033,15 +1033,25 @@ PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) cons String VisualScriptPropertySet::get_caption() const { static const char *opname[ASSIGN_OP_MAX] = { - "Set", "Add", "Subtract", "Multiply", "Divide", "Mod", "ShiftLeft", "ShiftRight", "BitAnd", "BitOr", "BitXor" + TTRC("Set %s"), + TTRC("Add %s"), + TTRC("Subtract %s"), + TTRC("Multiply %s"), + TTRC("Divide %s"), + TTRC("Mod %s"), + TTRC("ShiftLeft %s"), + TTRC("ShiftRight %s"), + TTRC("BitAnd %s"), + TTRC("BitOr %s"), + TTRC("BitXor %s") }; - String prop = String(opname[assign_op]) + " " + property; + String prop = property; if (index != StringName()) { prop += "." + String(index); } - return prop; + return vformat(TTRGET(opname[assign_op]), prop); } String VisualScriptPropertySet::get_text() const { @@ -1049,13 +1059,13 @@ String VisualScriptPropertySet::get_text() const { return ""; } if (call_mode == CALL_MODE_BASIC_TYPE) { - return String("On ") + Variant::get_type_name(basic_type); + return vformat(TTR("On %s"), Variant::get_type_name(basic_type)); } else if (call_mode == CALL_MODE_INSTANCE) { - return String("On ") + base_type; + return vformat(TTR("On %s"), base_type); } else if (call_mode == CALL_MODE_NODE_PATH) { return " [" + String(base_path.simplified()) + "]"; } else { - return "On Self"; + return TTR("On Self"); } } @@ -1761,23 +1771,23 @@ PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) cons } String VisualScriptPropertyGet::get_caption() const { - String prop = String("Get ") + property; + String prop = property; if (index != StringName()) { prop += "." + String(index); } - return prop; + return vformat(TTR("Get %s"), prop); } String VisualScriptPropertyGet::get_text() const { if (call_mode == CALL_MODE_BASIC_TYPE) { - return String("On ") + Variant::get_type_name(basic_type); + return vformat(TTR("On %s"), Variant::get_type_name(basic_type)); } else if (call_mode == CALL_MODE_INSTANCE) { - return String("On ") + base_type; + return vformat(TTR("On %s"), base_type); } else if (call_mode == CALL_MODE_NODE_PATH) { return " [" + String(base_path.simplified()) + "]"; } else { - return "On Self"; + return TTR("On Self"); } } @@ -2293,7 +2303,7 @@ PropertyInfo VisualScriptEmitSignal::get_output_value_port_info(int p_idx) const } String VisualScriptEmitSignal::get_caption() const { - return "Emit " + String(name); + return vformat(TTR("Emit %s"), name); } void VisualScriptEmitSignal::set_signal(const StringName &p_type) { @@ -2316,10 +2326,12 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { property.hint = PROPERTY_HINT_ENUM; List<StringName> sigs; + List<MethodInfo> base_sigs; Ref<VisualScript> vs = get_visual_script(); if (vs.is_valid()) { vs->get_custom_signal_list(&sigs); + ClassDB::get_signal_list(vs->get_instance_base_type(), &base_sigs); } String ml; @@ -2329,6 +2341,12 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { } ml += E; } + for (const MethodInfo &E : base_sigs) { + if (!ml.is_empty()) { + ml += ","; + } + ml += E.name; + } property.hint_string = ml; } diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index fccdab1a64..f3594e5164 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -204,7 +204,7 @@ PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const { } String VisualScriptFunction::get_caption() const { - return "Function"; + return TTR("Function"); } String VisualScriptFunction::get_text() const { @@ -767,7 +767,7 @@ PropertyInfo VisualScriptComposeArray::get_output_value_port_info(int p_idx) con } String VisualScriptComposeArray::get_caption() const { - return "Compose Array"; + return TTR("Compose Array"); } String VisualScriptComposeArray::get_text() const { @@ -1186,11 +1186,11 @@ PropertyInfo VisualScriptSelect::get_output_value_port_info(int p_idx) const { } String VisualScriptSelect::get_caption() const { - return "Select"; + return TTR("Select"); } String VisualScriptSelect::get_text() const { - return "a if cond, else b"; + return TTR("a if cond, else b"); } void VisualScriptSelect::set_typed(Variant::Type p_op) { @@ -1284,7 +1284,7 @@ PropertyInfo VisualScriptVariableGet::get_output_value_port_info(int p_idx) cons } String VisualScriptVariableGet::get_caption() const { - return "Get " + variable; + return vformat(TTR("Get %s"), variable); } void VisualScriptVariableGet::set_variable(StringName p_variable) { @@ -1394,7 +1394,7 @@ PropertyInfo VisualScriptVariableSet::get_output_value_port_info(int p_idx) cons } String VisualScriptVariableSet::get_caption() const { - return "Set " + variable; + return vformat(TTR("Set %s"), variable); } void VisualScriptVariableSet::set_variable(StringName p_variable) { @@ -1501,7 +1501,7 @@ PropertyInfo VisualScriptConstant::get_output_value_port_info(int p_idx) const { } String VisualScriptConstant::get_caption() const { - return "Constant"; + return TTR("Constant"); } void VisualScriptConstant::set_constant_type(Variant::Type p_type) { @@ -1628,7 +1628,7 @@ PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const { } String VisualScriptPreload::get_caption() const { - return "Preload"; + return TTR("Preload"); } void VisualScriptPreload::set_preload(const Ref<Resource> &p_preload) { @@ -1708,7 +1708,7 @@ PropertyInfo VisualScriptIndexGet::get_output_value_port_info(int p_idx) const { } String VisualScriptIndexGet::get_caption() const { - return "Get Index"; + return TTR("Get Index"); } class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance { @@ -1775,7 +1775,7 @@ PropertyInfo VisualScriptIndexSet::get_output_value_port_info(int p_idx) const { } String VisualScriptIndexSet::get_caption() const { - return "Set Index"; + return TTR("Set Index"); } class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance { @@ -1839,7 +1839,7 @@ PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) c } String VisualScriptGlobalConstant::get_caption() const { - return "Global Constant"; + return TTR("Global Constant"); } void VisualScriptGlobalConstant::set_global_constant(int p_which) { @@ -1925,7 +1925,7 @@ PropertyInfo VisualScriptClassConstant::get_output_value_port_info(int p_idx) co } String VisualScriptClassConstant::get_caption() const { - return "Class Constant"; + return TTR("Class Constant"); } void VisualScriptClassConstant::set_class_constant(const StringName &p_which) { @@ -2050,7 +2050,7 @@ PropertyInfo VisualScriptBasicTypeConstant::get_output_value_port_info(int p_idx } String VisualScriptBasicTypeConstant::get_caption() const { - return "Basic Constant"; + return TTR("Basic Constant"); } String VisualScriptBasicTypeConstant::get_text() const { @@ -2215,7 +2215,7 @@ PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) con } String VisualScriptMathConstant::get_caption() const { - return "Math Constant"; + return TTR("Math Constant"); } void VisualScriptMathConstant::set_math_constant(MathConstant p_which) { @@ -2307,7 +2307,7 @@ PropertyInfo VisualScriptEngineSingleton::get_output_value_port_info(int p_idx) } String VisualScriptEngineSingleton::get_caption() const { - return "Get Engine Singleton"; + return TTR("Get Engine Singleton"); } void VisualScriptEngineSingleton::set_singleton(const String &p_string) { @@ -2417,7 +2417,7 @@ PropertyInfo VisualScriptSceneNode::get_output_value_port_info(int p_idx) const } String VisualScriptSceneNode::get_caption() const { - return "Get Scene Node"; + return TTR("Get Scene Node"); } void VisualScriptSceneNode::set_node_path(const NodePath &p_path) { @@ -2608,7 +2608,7 @@ PropertyInfo VisualScriptSceneTree::get_output_value_port_info(int p_idx) const } String VisualScriptSceneTree::get_caption() const { - return "Get Scene Tree"; + return TTR("Get Scene Tree"); } class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance { @@ -2695,7 +2695,7 @@ PropertyInfo VisualScriptResourcePath::get_output_value_port_info(int p_idx) con } String VisualScriptResourcePath::get_caption() const { - return "Resource Path"; + return TTR("Resource Path"); } void VisualScriptResourcePath::set_resource_path(const String &p_path) { @@ -2777,7 +2777,7 @@ PropertyInfo VisualScriptSelf::get_output_value_port_info(int p_idx) const { } String VisualScriptSelf::get_caption() const { - return "Get Self"; + return TTR("Get Self"); } class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance { @@ -2947,7 +2947,7 @@ String VisualScriptCustomNode::get_caption() const { if (GDVIRTUAL_CALL(_get_caption, ret)) { return ret; } - return "CustomNode"; + return TTR("CustomNode"); } String VisualScriptCustomNode::get_text() const { @@ -3141,7 +3141,7 @@ PropertyInfo VisualScriptSubCall::get_output_value_port_info(int p_idx) const { } String VisualScriptSubCall::get_caption() const { - return "SubCall"; + return TTR("SubCall"); } String VisualScriptSubCall::get_text() const { @@ -3352,7 +3352,7 @@ PropertyInfo VisualScriptConstructor::get_output_value_port_info(int p_idx) cons } String VisualScriptConstructor::get_caption() const { - return "Construct " + Variant::get_type_name(type); + return vformat(TTR("Construct %s"), Variant::get_type_name(type)); } String VisualScriptConstructor::get_category() const { @@ -3469,7 +3469,7 @@ PropertyInfo VisualScriptLocalVar::get_output_value_port_info(int p_idx) const { } String VisualScriptLocalVar::get_caption() const { - return "Get Local Var"; + return TTR("Get Local Var"); } String VisualScriptLocalVar::get_category() const { @@ -3572,7 +3572,7 @@ PropertyInfo VisualScriptLocalVarSet::get_output_value_port_info(int p_idx) cons } String VisualScriptLocalVarSet::get_caption() const { - return "Set Local Var"; + return TTR("Set Local Var"); } String VisualScriptLocalVarSet::get_text() const { @@ -3696,7 +3696,7 @@ PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) cons } String VisualScriptInputAction::get_caption() const { - return "Action " + name; + return vformat(TTR("Action %s"), name); } String VisualScriptInputAction::get_category() const { @@ -3850,7 +3850,7 @@ PropertyInfo VisualScriptDeconstruct::get_output_value_port_info(int p_idx) cons } String VisualScriptDeconstruct::get_caption() const { - return "Deconstruct " + Variant::get_type_name(type); + return vformat(TTR("Deconstruct %s"), Variant::get_type_name(type)); } String VisualScriptDeconstruct::get_category() const { diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index d4f3fdd082..fbd5ad35ab 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -68,7 +68,7 @@ PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const { } String VisualScriptYield::get_caption() const { - return yield_mode == YIELD_RETURN ? "Yield" : "Wait"; + return yield_mode == YIELD_RETURN ? TTR("Yield") : TTR("Wait"); } String VisualScriptYield::get_text() const { @@ -77,13 +77,13 @@ String VisualScriptYield::get_text() const { return ""; break; case YIELD_FRAME: - return "Next Frame"; + return TTR("Next Frame"); break; case YIELD_PHYSICS_FRAME: - return "Next Physics Frame"; + return TTR("Next Physics Frame"); break; case YIELD_WAIT: - return rtos(wait_time) + " sec(s)"; + return vformat(TTR("%s sec(s)"), rtos(wait_time)); break; } @@ -336,12 +336,12 @@ PropertyInfo VisualScriptYieldSignal::get_output_value_port_info(int p_idx) cons String VisualScriptYieldSignal::get_caption() const { static const char *cname[3] = { - "WaitSignal", - "WaitNodeSignal", - "WaitInstanceSigna;", + TTRC("WaitSignal"), + TTRC("WaitNodeSignal"), + TTRC("WaitInstanceSignal"), }; - return cname[call_mode]; + return TTRGET(cname[call_mode]); } String VisualScriptYieldSignal::get_text() const { diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 50d5952637..049d816a5a 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -110,7 +110,7 @@ int AudioStreamPlaybackOGGVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p if (info.channels > 1) { for (int frame = 0; frame < frames; frame++) { p_buffer[frame].l = pcm[0][frame]; - p_buffer[frame].r = pcm[0][frame]; + p_buffer[frame].r = pcm[1][frame]; } } else { for (int frame = 0; frame < frames; frame++) { diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp index b7249e4243..b3f0140b80 100644 --- a/modules/websocket/websocket_server.cpp +++ b/modules/websocket/websocket_server.cpp @@ -67,7 +67,7 @@ void WebSocketServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_handshake_timeout"), &WebSocketServer::get_handshake_timeout); ClassDB::bind_method(D_METHOD("set_handshake_timeout", "timeout"), &WebSocketServer::set_handshake_timeout); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handshake_timeout"), "set_handshake_timeout", "get_handshake_timeout"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "handshake_timeout"), "set_handshake_timeout", "get_handshake_timeout"); ADD_SIGNAL(MethodInfo("client_close_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason"))); ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::BOOL, "was_clean_close"))); diff --git a/modules/webxr/webxr_interface.h b/modules/webxr/webxr_interface.h index 291d53044f..801643bfa6 100644 --- a/modules/webxr/webxr_interface.h +++ b/modules/webxr/webxr_interface.h @@ -35,8 +35,6 @@ #include "servers/xr/xr_positional_tracker.h" /** - @author David Snopek <david.snopek@snopekgames.com> - The WebXR interface is a VR/AR interface that can be used on the web. */ diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h index 3eec451d50..8eddfbe484 100644 --- a/modules/webxr/webxr_interface_js.h +++ b/modules/webxr/webxr_interface_js.h @@ -36,8 +36,6 @@ #include "webxr_interface.h" /** - @author David Snopek <david.snopek@snopekgames.com> - The WebXR interface is a VR/AR interface that can be used on the web. */ |