diff options
Diffstat (limited to 'servers')
31 files changed, 383 insertions, 177 deletions
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 51b9d5a4a2..1a6430c499 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -83,8 +83,8 @@ void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale, _mix_internal(internal_buffer + 4, INTERNAL_BUFFER_LEN); } else { //fill with silence, not playing - for (int i = 0; i < INTERNAL_BUFFER_LEN; ++i) { - internal_buffer[i + 4] = AudioFrame(0, 0); + for (int j = 0; j < INTERNAL_BUFFER_LEN; ++j) { + internal_buffer[j + 4] = AudioFrame(0, 0); } } mix_offset -= (INTERNAL_BUFFER_LEN << FP_BITS); @@ -138,7 +138,7 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer(); unsigned int input_size = AudioDriver::get_singleton()->get_input_size(); int mix_rate = AudioDriver::get_singleton()->get_mix_rate(); - int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1); + unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1); #ifdef DEBUG_ENABLED unsigned int input_position = AudioDriver::get_singleton()->get_input_position(); #endif @@ -150,13 +150,13 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr input_ofs = 0; } else { for (int i = 0; i < p_frames; i++) { - if (input_size > input_ofs) { + if (input_size > input_ofs && (int)input_ofs < buf.size()) { float l = (buf[input_ofs++] >> 16) / 32768.f; - if (input_ofs >= buf.size()) { + if ((int)input_ofs >= buf.size()) { input_ofs = 0; } float r = (buf[input_ofs++] >> 16) / 32768.f; - if (input_ofs >= buf.size()) { + if ((int)input_ofs >= buf.size()) { input_ofs = 0; } @@ -168,7 +168,7 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr } #ifdef DEBUG_ENABLED - if (input_ofs > input_position && (input_ofs - input_position) < (p_frames * 2)) { + if (input_ofs > input_position && (int)(input_ofs - input_position) < (p_frames * 2)) { print_verbose(String(get_class_name()) + " buffer underrun: input_position=" + itos(input_position) + " input_ofs=" + itos(input_ofs) + " input_size=" + itos(input_size)); } #endif @@ -186,6 +186,10 @@ float AudioStreamPlaybackMicrophone::get_stream_sampling_rate() { void AudioStreamPlaybackMicrophone::start(float p_from_pos) { + if (active) { + return; + } + if (!GLOBAL_GET("audio/enable_audio_input")) { WARN_PRINTS("Need to enable Project settings > Audio > Enable Audio Input option to use capturing."); return; @@ -193,15 +197,17 @@ void AudioStreamPlaybackMicrophone::start(float p_from_pos) { input_ofs = 0; - AudioDriver::get_singleton()->capture_start(); - - active = true; - _begin_resample(); + if (AudioDriver::get_singleton()->capture_start() == OK) { + active = true; + _begin_resample(); + } } void AudioStreamPlaybackMicrophone::stop() { - AudioDriver::get_singleton()->capture_stop(); - active = false; + if (active) { + AudioDriver::get_singleton()->capture_stop(); + active = false; + } } bool AudioStreamPlaybackMicrophone::is_playing() const { diff --git a/servers/audio/reverb_sw.cpp b/servers/audio/reverb_sw.cpp index 8adc21b406..63bf1a7eaa 100644 --- a/servers/audio/reverb_sw.cpp +++ b/servers/audio/reverb_sw.cpp @@ -39,9 +39,6 @@ #define rangeloop(c, min, max) \ for ((c) = (min); (c) < (max); (c)++) -#define ABSDIFF(x, y) \ - (((x) < (y)) ? ((y) - (x)) : ((x) - (y))) - #define MULSHIFT_S32(Factor1, Factor2, Bits) \ ((int)(((int64_t)(Factor1) * (Factor2)) >> (Bits))) diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index a2e5813a4f..8c092a02a2 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -90,12 +90,16 @@ void AudioDriver::input_buffer_init(int driver_buffer_frames) { void AudioDriver::input_buffer_write(int32_t sample) { - input_buffer.write[input_position++] = sample; - if (input_position >= input_buffer.size()) { - input_position = 0; - } - if (input_size < input_buffer.size()) { - input_size++; + if ((int)input_position < input_buffer.size()) { + input_buffer.write[input_position++] = sample; + if ((int)input_position >= input_buffer.size()) { + input_position = 0; + } + if ((int)input_size < input_buffer.size()) { + input_size++; + } + } else { + WARN_PRINTS("input_buffer_write: Invalid input_position=" + itos(input_position) + " input_buffer.size()=" + itos(input_buffer.size())); } } @@ -145,6 +149,8 @@ AudioDriver::AudioDriver() { _last_mix_time = 0; _mix_amount = 0; + input_position = 0; + input_size = 0; #ifdef DEBUG_ENABLED prof_time = 0; @@ -253,11 +259,13 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) { float l = CLAMP(buf[from + j].l, -1.0, 1.0); int32_t vl = l * ((1 << 20) - 1); - p_buffer[(from_buf + j) * (cs * 2) + k * 2 + 0] = vl << 11; + int32_t vl2 = (vl < 0 ? -1 : 1) * (ABS(vl) << 11); + p_buffer[(from_buf + j) * (cs * 2) + k * 2 + 0] = vl2; float r = CLAMP(buf[from + j].r, -1.0, 1.0); int32_t vr = r * ((1 << 20) - 1); - p_buffer[(from_buf + j) * (cs * 2) + k * 2 + 1] = vr << 11; + int32_t vr2 = (vr < 0 ? -1 : 1) * (ABS(vr) << 11); + p_buffer[(from_buf + j) * (cs * 2) + k * 2 + 1] = vr2; } } else { diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h index 6e6b66dac2..5c14d5aaf9 100644 --- a/servers/physics/collision_object_sw.h +++ b/servers/physics/collision_object_sw.h @@ -130,7 +130,7 @@ public: _FORCE_INLINE_ const Transform &get_shape_transform(int p_index) const { return shapes[p_index].xform; } _FORCE_INLINE_ const Transform &get_shape_inv_transform(int p_index) const { return shapes[p_index].xform_inv; } _FORCE_INLINE_ const AABB &get_shape_aabb(int p_index) const { return shapes[p_index].aabb_cache; } - _FORCE_INLINE_ const real_t get_shape_area(int p_index) const { return shapes[p_index].area_cache; } + _FORCE_INLINE_ real_t get_shape_area(int p_index) const { return shapes[p_index].area_cache; } _FORCE_INLINE_ Transform get_transform() const { return transform; } _FORCE_INLINE_ Transform get_inv_transform() const { return inv_transform; } diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp index e2d7c8c44e..baf7431e28 100644 --- a/servers/physics/collision_solver_sat.cpp +++ b/servers/physics/collision_solver_sat.cpp @@ -821,9 +821,9 @@ static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transf // test edges of A - for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { - Vector3 axis = point_axis.cross(p_transform_a.basis.get_axis(i)).cross(p_transform_a.basis.get_axis(i)).normalized(); + Vector3 axis = point_axis.cross(p_transform_a.basis.get_axis(j)).cross(p_transform_a.basis.get_axis(j)).normalized(); if (!separator.test_axis(axis)) return; diff --git a/servers/physics/joints/cone_twist_joint_sw.cpp b/servers/physics/joints/cone_twist_joint_sw.cpp index 05778ee9b0..268b9eefeb 100644 --- a/servers/physics/joints/cone_twist_joint_sw.cpp +++ b/servers/physics/joints/cone_twist_joint_sw.cpp @@ -205,9 +205,9 @@ bool ConeTwistJointSW::setup(real_t p_timestep) { // Twist limits if (m_twistSpan >= real_t(0.)) { - Vector3 b2Axis2 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(1)); + Vector3 b2Axis22 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(1)); Quat rotationArc = Quat(b2Axis1, b1Axis1); - Vector3 TwistRef = rotationArc.xform(b2Axis2); + Vector3 TwistRef = rotationArc.xform(b2Axis22); real_t twist = atan2fast(TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2)); real_t lockedFreeFactor = (m_twistSpan > real_t(0.05f)) ? m_limitSoftness : real_t(0.); diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 2975ae9453..36d18e8901 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -40,10 +40,10 @@ #include "joints/pin_joint_sw.h" #include "joints/slider_joint_sw.h" -#define FLUSH_QUERY_CHECK \ - if (flushing_queries) { \ - ERR_EXPLAIN("Can't change this state while flushing queries. Use call_deferred()/set_deferred() to change monitoring state instead"); \ - ERR_FAIL(); \ +#define FLUSH_QUERY_CHECK(m_object) \ + if (m_object->get_space() && flushing_queries) { \ + ERR_EXPLAIN("Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead"); \ + ERR_FAIL(); \ } RID PhysicsServerSW::shape_create(ShapeType p_shape) { @@ -358,11 +358,10 @@ void PhysicsServerSW::area_clear_shapes(RID p_area) { void PhysicsServerSW::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) { - FLUSH_QUERY_CHECK - AreaSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); ERR_FAIL_INDEX(p_shape_idx, area->get_shape_count()); + FLUSH_QUERY_CHECK(area); area->set_shape_as_disabled(p_shape_idx, p_disabled); } @@ -443,10 +442,9 @@ void PhysicsServerSW::area_set_collision_mask(RID p_area, uint32_t p_mask) { void PhysicsServerSW::area_set_monitorable(RID p_area, bool p_monitorable) { - FLUSH_QUERY_CHECK - AreaSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); + FLUSH_QUERY_CHECK(area); area->set_monitorable(p_monitorable); } @@ -592,11 +590,11 @@ RID PhysicsServerSW::body_get_shape(RID p_body, int p_shape_idx) const { void PhysicsServerSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { - FLUSH_QUERY_CHECK - BodySW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); + FLUSH_QUERY_CHECK(body); + body->set_shape_as_disabled(p_shape_idx, p_disabled); } diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp index 1087cd2483..4ab92715f4 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -277,7 +277,7 @@ bool PhysicsDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transform real_t hi = 1; Vector3 mnormal = p_motion.normalized(); - for (int i = 0; i < 8; i++) { //steps should be customizable.. + for (int j = 0; j < 8; j++) { //steps should be customizable.. real_t ofs = (low + hi) * 0.5; @@ -387,6 +387,7 @@ struct _RestCallbackData { Vector3 best_contact; Vector3 best_normal; real_t best_len; + real_t min_allowed_depth; }; static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) { @@ -395,6 +396,8 @@ static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, Vector3 contact_rel = p_point_B - p_point_A; real_t len = contact_rel.length(); + if (len < rd->min_allowed_depth) + return; if (len <= rd->best_len) return; @@ -418,6 +421,7 @@ bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform &p_shape_ rcd.best_len = 0; rcd.best_object = NULL; rcd.best_shape = 0; + rcd.min_allowed_depth = space->test_motion_min_contact_depth; for (int i = 0; i < amount; i++) { @@ -593,7 +597,6 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo bool collided = false; int amount = _cull_aabb_for_body(p_body, body_aabb); - int ray_index = 0; for (int j = 0; j < p_body->get_shape_count(); j++) { if (p_body->is_shape_set_as_disabled(j)) @@ -627,7 +630,19 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo collided = true; } - if (ray_index < p_result_max) { + int ray_index = -1; //reuse shape + for (int k = 0; k < rays_found; k++) { + if (r_results[ray_index].collision_local_shape == j) { + ray_index = k; + } + } + + if (ray_index == -1 && rays_found < p_result_max) { + ray_index = rays_found; + rays_found++; + } + + if (ray_index != -1) { PhysicsServer::SeparationResult &result = r_results[ray_index]; for (int k = 0; k < cbk.amount; k++) { @@ -642,9 +657,10 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo result.collision_depth = depth; result.collision_point = b; result.collision_normal = (b - a).normalized(); - result.collision_local_shape = shape_idx; + result.collision_local_shape = j; result.collider = col_obj->get_self(); result.collider_id = col_obj->get_instance_id(); + result.collider_shape = shape_idx; //result.collider_metadata = col_obj->get_shape_metadata(shape_idx); if (col_obj->get_type() == CollisionObjectSW::TYPE_BODY) { BodySW *body = (BodySW *)col_obj; @@ -658,12 +674,8 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo } } } - - ray_index++; } - rays_found = MAX(ray_index, rays_found); - if (!collided || recover_motion == Vector3()) { break; } @@ -717,6 +729,11 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve } if (!shapes_found) { + if (r_result) { + *r_result = PhysicsServer::MotionResult(); + r_result->motion = p_motion; + } + return false; } @@ -855,7 +872,7 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve real_t hi = 1; Vector3 mnormal = p_motion.normalized(); - for (int i = 0; i < 8; i++) { //steps should be customizable.. + for (int k = 0; k < 8; k++) { //steps should be customizable.. real_t ofs = (low + hi) * 0.5; @@ -924,6 +941,7 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve rcd.best_len = 0; rcd.best_object = NULL; rcd.best_shape = 0; + rcd.min_allowed_depth = test_motion_min_contact_depth; Transform body_shape_xform = ugt * p_body->get_shape_transform(best_shape); ShapeSW *body_shape = p_body->get_shape(best_shape); @@ -1148,6 +1166,7 @@ void SpaceSW::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) { case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep = p_value; break; case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: body_angular_velocity_damp_ratio = p_value; break; case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; + case PhysicsServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: test_motion_min_contact_depth = p_value; break; } } @@ -1163,6 +1182,7 @@ real_t SpaceSW::get_param(PhysicsServer::SpaceParameter p_param) const { case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep; case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: return body_angular_velocity_damp_ratio; case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias; + case PhysicsServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: return test_motion_min_contact_depth; } return 0; } @@ -1198,6 +1218,7 @@ SpaceSW::SpaceSW() { contact_recycle_radius = 0.01; contact_max_separation = 0.05; contact_max_allowed_penetration = 0.01; + test_motion_min_contact_depth = 0.00001; constraint_bias = 0.01; body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1); diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h index ae6f349e51..3aaa552845 100644 --- a/servers/physics/space_sw.h +++ b/servers/physics/space_sw.h @@ -96,6 +96,7 @@ private: real_t contact_max_separation; real_t contact_max_allowed_penetration; real_t constraint_bias; + real_t test_motion_min_contact_depth; enum { diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp index 5c2242c4c5..954b0fa3ea 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/joints_2d_sw.cpp @@ -299,9 +299,7 @@ bool GrooveJoint2DSW::setup(real_t p_step) { Vector2 delta = (B->get_transform().get_origin() + rB) - (A->get_transform().get_origin() + rA); - // FIXME: We used to do this assignment and then override it with 0.001 right after. Investigate why. - //real_t _b = get_bias(); - real_t _b = 0.001; + real_t _b = get_bias(); gbias = (delta * -(_b == 0 ? space->get_constraint_bias() : _b) * (1.0 / p_step)).clamped(get_max_bias()); // apply accumulated impulse diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 4d1c56b843..283d20876d 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -36,8 +36,8 @@ #include "core/project_settings.h" #include "core/script_language.h" -#define FLUSH_QUERY_CHECK \ - if (flushing_queries) { \ +#define FLUSH_QUERY_CHECK(m_object) \ + if (m_object->get_space() && flushing_queries) { \ ERR_EXPLAIN("Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead"); \ ERR_FAIL(); \ } @@ -410,12 +410,11 @@ void Physics2DServerSW::area_set_shape_transform(RID p_area, int p_shape_idx, co void Physics2DServerSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) { - FLUSH_QUERY_CHECK - Area2DSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); - ERR_FAIL_INDEX(p_shape, area->get_shape_count()); + FLUSH_QUERY_CHECK(area); + area->set_shape_as_disabled(p_shape, p_disabled); } @@ -550,10 +549,9 @@ void Physics2DServerSW::area_set_pickable(RID p_area, bool p_pickable) { void Physics2DServerSW::area_set_monitorable(RID p_area, bool p_monitorable) { - FLUSH_QUERY_CHECK - Area2DSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); + FLUSH_QUERY_CHECK(area); area->set_monitorable(p_monitorable); } @@ -630,10 +628,9 @@ RID Physics2DServerSW::body_get_space(RID p_body) const { void Physics2DServerSW::body_set_mode(RID p_body, BodyMode p_mode) { - FLUSH_QUERY_CHECK - Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); + FLUSH_QUERY_CHECK(body); body->set_mode(p_mode); }; @@ -734,12 +731,10 @@ void Physics2DServerSW::body_clear_shapes(RID p_body) { void Physics2DServerSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { - FLUSH_QUERY_CHECK - Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); - ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); + FLUSH_QUERY_CHECK(body); body->set_shape_as_disabled(p_shape_idx, p_disabled); } @@ -747,8 +742,8 @@ void Physics2DServerSW::body_set_shape_as_one_way_collision(RID p_body, int p_sh Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); - ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); + FLUSH_QUERY_CHECK(body); body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin); } diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index b622550ec9..56b87f620c 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -369,8 +369,11 @@ void RectangleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_suppor } bool RectangleShape2DSW::contains_point(const Vector2 &p_point) const { - - return Math::abs(p_point.x) < half_extents.x && Math::abs(p_point.y) < half_extents.y; + float x = p_point.x; + float y = p_point.y; + float edge_x = half_extents.x; + float edge_y = half_extents.y; + return (x >= -edge_x) && (x < edge_x) && (y >= -edge_y) && (y < edge_y); } bool RectangleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { @@ -775,22 +778,22 @@ bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Ve while (true) { uint32_t node = stack[level] & NODE_IDX_MASK; - const BVH &b = bvhptr[node]; + const BVH &bvh = bvhptr[node]; bool done = false; switch (stack[level] >> VISITED_BIT_SHIFT) { case TEST_AABB_BIT: { - bool valid = b.aabb.intersects_segment(p_begin, p_end); + bool valid = bvh.aabb.intersects_segment(p_begin, p_end); if (!valid) { stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; } else { - if (b.left < 0) { + if (bvh.left < 0) { - const Segment &s = segmentptr[b.right]; + const Segment &s = segmentptr[bvh.right]; Vector2 a = pointptr[s.points[0]]; Vector2 b = pointptr[s.points[1]]; @@ -820,14 +823,14 @@ bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Ve case VISIT_LEFT_BIT: { stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node; - stack[level + 1] = b.left | TEST_AABB_BIT; + stack[level + 1] = bvh.left | TEST_AABB_BIT; level++; } continue; case VISIT_RIGHT_BIT: { stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - stack[level + 1] = b.right | TEST_AABB_BIT; + stack[level + 1] = bvh.right | TEST_AABB_BIT; level++; } continue; @@ -1025,21 +1028,21 @@ void ConcavePolygonShape2DSW::cull(const Rect2 &p_local_aabb, Callback p_callbac while (true) { uint32_t node = stack[level] & NODE_IDX_MASK; - const BVH &b = bvhptr[node]; + const BVH &bvh = bvhptr[node]; switch (stack[level] >> VISITED_BIT_SHIFT) { case TEST_AABB_BIT: { - bool valid = p_local_aabb.intersects(b.aabb); + bool valid = p_local_aabb.intersects(bvh.aabb); if (!valid) { stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; } else { - if (b.left < 0) { + if (bvh.left < 0) { - const Segment &s = segmentptr[b.right]; + const Segment &s = segmentptr[bvh.right]; Vector2 a = pointptr[s.points[0]]; Vector2 b = pointptr[s.points[1]]; @@ -1058,14 +1061,14 @@ void ConcavePolygonShape2DSW::cull(const Rect2 &p_local_aabb, Callback p_callbac case VISIT_LEFT_BIT: { stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node; - stack[level + 1] = b.left | TEST_AABB_BIT; + stack[level + 1] = bvh.left | TEST_AABB_BIT; level++; } continue; case VISIT_RIGHT_BIT: { stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - stack[level + 1] = b.right | TEST_AABB_BIT; + stack[level + 1] = bvh.right | TEST_AABB_BIT; level++; } continue; diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 5ed70803ed..831764b40c 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -280,7 +280,7 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor real_t hi = 1; Vector2 mnormal = p_motion.normalized(); - for (int i = 0; i < 8; i++) { //steps should be customizable.. + for (int j = 0; j < 8; j++) { //steps should be customizable.. real_t ofs = (low + hi) * 0.5; @@ -375,6 +375,7 @@ struct _RestCallbackData2D { real_t best_len; Vector2 valid_dir; real_t valid_depth; + real_t min_allowed_depth; }; static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) { @@ -390,6 +391,10 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, Vector2 contact_rel = p_point_B - p_point_A; real_t len = contact_rel.length(); + + if (len < rd->min_allowed_depth) + return; + if (len <= rd->best_len) return; @@ -416,6 +421,7 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh rcd.best_len = 0; rcd.best_object = NULL; rcd.best_shape = 0; + rcd.min_allowed_depth = space->test_motion_min_contact_depth; for (int i = 0; i < amount; i++) { @@ -512,6 +518,9 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t if (p_body->is_shape_set_as_disabled(i)) continue; + if (p_body->get_shape(i)->get_type() != Physics2DServer::SHAPE_RAY) + continue; + if (!shapes_found) { body_aabb = p_body->get_shape_aabb(i); shapes_found = true; @@ -555,7 +564,6 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t bool collided = false; int amount = _cull_aabb_for_body(p_body, body_aabb); - int ray_index = 0; for (int j = 0; j < p_body->get_shape_count(); j++) { if (p_body->is_shape_set_as_disabled(j)) @@ -587,6 +595,10 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + /* + * There is no point in supporting one way collisions with ray shapes, as they will always collide in the desired + * direction. Use a short ray shape if you want to achieve a similar effect. + * if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); @@ -594,10 +606,15 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t cbk.invalid_by_dir = 0; } else { - cbk.valid_dir = Vector2(); - cbk.valid_depth = 0; - cbk.invalid_by_dir = 0; +*/ + + cbk.valid_dir = Vector2(); + cbk.valid_depth = 0; + cbk.invalid_by_dir = 0; + + /* } + */ Shape2DSW *against_shape = col_obj->get_shape(shape_idx); if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, NULL, p_margin)) { @@ -605,7 +622,20 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t collided = true; } - if (ray_index < p_result_max) { + int ray_index = -1; //reuse shape + for (int k = 0; k < rays_found; k++) { + if (r_results[ray_index].collision_local_shape == j) { + ray_index = k; + } + } + + if (ray_index == -1 && rays_found < p_result_max) { + ray_index = rays_found; + rays_found++; + } + + if (ray_index != -1) { + Physics2DServer::SeparationResult &result = r_results[ray_index]; for (int k = 0; k < cbk.amount; k++) { @@ -620,7 +650,8 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t result.collision_depth = depth; result.collision_point = b; result.collision_normal = (b - a).normalized(); - result.collision_local_shape = shape_idx; + result.collision_local_shape = j; + result.collider_shape = shape_idx; result.collider = col_obj->get_self(); result.collider_id = col_obj->get_instance_id(); result.collider_metadata = col_obj->get_shape_metadata(shape_idx); @@ -635,12 +666,8 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t } } } - - ray_index++; } - rays_found = MAX(ray_index, rays_found); - if (!collided || recover_motion == Vector2()) { break; } @@ -686,6 +713,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (p_body->is_shape_set_as_disabled(i)) continue; + if (p_exclude_raycast_shapes && p_body->get_shape(i)->get_type() == Physics2DServer::SHAPE_RAY) + continue; + if (!shapes_found) { body_aabb = p_body->get_shape_aabb(i); shapes_found = true; @@ -695,6 +725,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } if (!shapes_found) { + if (r_result) { + *r_result = Physics2DServer::MotionResult(); + r_result->motion = p_motion; + } return false; } @@ -990,15 +1024,24 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co rcd.best_len = 0; rcd.best_object = NULL; rcd.best_shape = 0; + rcd.min_allowed_depth = test_motion_min_contact_depth; //optimization int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); for (int j = from_shape; j < to_shape; j++) { + + if (p_body->is_shape_set_as_disabled(j)) + continue; + Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j); Shape2DSW *body_shape = p_body->get_shape(j); + if (p_exclude_raycast_shapes && body_shape->get_type() == Physics2DServer::SHAPE_RAY) { + continue; + } + body_aabb.position += p_motion * unsafe; int amount = _cull_aabb_for_body(p_body, body_aabb); @@ -1249,6 +1292,7 @@ void Space2DSW::set_param(Physics2DServer::SpaceParameter p_param, real_t p_valu case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: body_angular_velocity_sleep_threshold = p_value; break; case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep = p_value; break; case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; + case Physics2DServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: test_motion_min_contact_depth = p_value; break; } } @@ -1263,6 +1307,7 @@ real_t Space2DSW::get_param(Physics2DServer::SpaceParameter p_param) const { case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: return body_angular_velocity_sleep_threshold; case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep; case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias; + case Physics2DServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: return test_motion_min_contact_depth; } return 0; } @@ -1299,6 +1344,7 @@ Space2DSW::Space2DSW() { contact_recycle_radius = 1.0; contact_max_separation = 1.5; contact_max_allowed_penetration = 0.3; + test_motion_min_contact_depth = 0.005; constraint_bias = 0.2; body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0); diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 64f8c9e156..14c24959b7 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -104,6 +104,7 @@ private: real_t contact_max_separation; real_t contact_max_allowed_penetration; real_t constraint_bias; + real_t test_motion_min_contact_depth; enum { diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index ca914b67e0..3a05791f17 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -693,6 +693,7 @@ void Physics2DServer::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); + BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); BIND_ENUM_CONSTANT(SHAPE_LINE); BIND_ENUM_CONSTANT(SHAPE_RAY); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index df7fe46f76..1de9c7df93 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -289,6 +289,7 @@ public: SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD, SPACE_PARAM_BODY_TIME_TO_SLEEP, SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS, + SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH, }; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0; @@ -504,6 +505,12 @@ public: RID collider; int collider_shape; Variant collider_metadata; + + MotionResult() { + collision_local_shape = 0; + collider_shape = 0; + collider_id = 0; + } }; virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.001, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true) = 0; diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index 967e74d322..0629af663e 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -709,6 +709,8 @@ void PhysicsServer::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); + BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); + BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_X); BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Y); BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Z); @@ -737,11 +739,11 @@ const String PhysicsServerManager::setting_property_name("physics/3d/physics_eng void PhysicsServerManager::on_servers_changed() { - String physics_servers("DEFAULT"); + String physics_servers2("DEFAULT"); for (int i = get_servers_count() - 1; 0 <= i; --i) { - physics_servers += "," + get_server_name(i); + physics_servers2 += "," + get_server_name(i); } - ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers)); + ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers2)); } void PhysicsServerManager::register_server(const String &p_name, CreatePhysicsServerCallback p_creat_callback) { diff --git a/servers/physics_server.h b/servers/physics_server.h index 4ba096a994..c71bb01943 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -274,6 +274,7 @@ public: SPACE_PARAM_BODY_TIME_TO_SLEEP, SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO, SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS, + SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH }; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0; @@ -492,6 +493,11 @@ public: RID collider; int collider_shape; Variant collider_metadata; + MotionResult() { + collision_local_shape = 0; + collider_id = 0; + collider_shape = 0; + } }; virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true) = 0; diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 4e167be300..0cc1cc119c 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -73,7 +73,11 @@ static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsag usage.vram = E->get().bytes; usage.id = E->get().texture; usage.type = "Texture"; - usage.format = itos(E->get().width) + "x" + itos(E->get().height) + " " + Image::get_format_name(E->get().format); + if (E->get().depth == 0) { + usage.format = itos(E->get().width) + "x" + itos(E->get().height) + " " + Image::get_format_name(E->get().format); + } else { + usage.format = itos(E->get().width) + "x" + itos(E->get().height) + "x" + itos(E->get().depth) + " " + Image::get_format_name(E->get().format); + } r_usage->push_back(usage); } } @@ -88,8 +92,21 @@ Physics2DServer *_createGodotPhysics2DCallback() { return Physics2DServerWrapMT::init_server<Physics2DServerSW>(); } +static bool has_server_feature_callback(const String &p_feature) { + + if (VisualServer::get_singleton()) { + if (VisualServer::get_singleton()->has_os_feature(p_feature)) { + return true; + } + } + + return false; +} + void register_server_types() { + OS::get_singleton()->set_has_server_feature_callback(has_server_feature_callback); + ClassDB::register_virtual_class<VisualServer>(); ClassDB::register_class<AudioServer>(); ClassDB::register_virtual_class<PhysicsServer>(); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 33081dcd0c..dd54698471 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -355,6 +355,7 @@ public: virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; + virtual void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform) = 0; /* Light API */ @@ -870,7 +871,7 @@ public: Rect2 global_rect_cache; const Rect2 &get_rect() const { - if (custom_rect || !rect_dirty) + if (custom_rect || (!rect_dirty && !update_when_visible)) return rect; //must update rect @@ -940,9 +941,8 @@ public: const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); r.position = primitive->points[0]; - for (int i = 1; i < primitive->points.size(); i++) { - - r.expand_to(primitive->points[i]); + for (int j = 1; j < primitive->points.size(); j++) { + r.expand_to(primitive->points[j]); } } break; case Item::Command::TYPE_POLYGON: { @@ -951,9 +951,8 @@ public: int l = polygon->points.size(); const Point2 *pp = &polygon->points[0]; r.position = pp[0]; - for (int i = 1; i < l; i++) { - - r.expand_to(pp[i]); + for (int j = 1; j < l; j++) { + r.expand_to(pp[j]); } } break; case Item::Command::TYPE_MESH: { diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 404686a31c..1f9d263354 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2075,7 +2075,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p for (int i = 0; i < argcount; i++) { if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), builtin_func_defs[idx].args[i])) { - //all good + //all good, but needs implicit conversion later } else if (args[i] != builtin_func_defs[idx].args[i]) { fail = true; break; @@ -2121,6 +2121,24 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p outarg_idx++; } + //implicitly convert values if possible + for (int i = 0; i < argcount; i++) { + + if (get_scalar_type(args[i]) != args[i] || args[i] == builtin_func_defs[idx].args[i] || p_func->arguments[i + 1]->type != Node::TYPE_CONSTANT) { + //can't do implicit conversion here + continue; + } + + //this is an implicit conversion + ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[i + 1]); + ConstantNode *conversion = alloc_node<ConstantNode>(); + + conversion->datatype = builtin_func_defs[idx].args[i]; + conversion->values.resize(1); + + convert_constant(constant, builtin_func_defs[idx].args[i], conversion->values.ptrw()); + p_func->arguments.write[i + 1] = conversion; + } if (r_ret_type) *r_ret_type = builtin_func_defs[idx].rettype; @@ -2184,17 +2202,37 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p bool fail = false; - for (int i = 0; i < args.size(); i++) { + for (int j = 0; j < args.size(); j++) { - if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), pfunc->arguments[i].type)) { - //all good - } else if (args[i] != pfunc->arguments[i].type) { + if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) { + //all good, but it needs implicit conversion later + } else if (args[j] != pfunc->arguments[j].type) { fail = true; break; } } if (!fail) { + + //implicitly convert values if possible + for (int k = 0; k < args.size(); k++) { + + if (get_scalar_type(args[k]) != args[k] || args[k] == pfunc->arguments[k].type || p_func->arguments[k + 1]->type != Node::TYPE_CONSTANT) { + //can't do implicit conversion here + continue; + } + + //this is an implicit conversion + ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[k + 1]); + ConstantNode *conversion = alloc_node<ConstantNode>(); + + conversion->datatype = pfunc->arguments[k].type; + conversion->values.resize(1); + + convert_constant(constant, pfunc->arguments[k].type, conversion->values.ptrw()); + p_func->arguments.write[k + 1] = conversion; + } + if (r_ret_type) *r_ret_type = pfunc->return_type; return true; @@ -2897,7 +2935,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons /* OK now see what's NEXT to the operator.. */ while (true) { - TkPos pos = _get_tkpos(); + TkPos pos2 = _get_tkpos(); tk = _get_token(); if (tk.type == TK_CURSOR) { @@ -3181,7 +3219,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expr = op; } else { - _set_tkpos(pos); + _set_tkpos(pos2); break; } } @@ -3374,10 +3412,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (!_validate_operator(op, &op->return_cache)) { String at; - for (int i = 0; i < op->arguments.size(); i++) { - if (i > 0) + for (int j = 0; j < op->arguments.size(); j++) { + if (j > 0) at += " and "; - at += get_datatype_name(op->arguments[i]->get_datatype()); + at += get_datatype_name(op->arguments[j]->get_datatype()); } _set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at); return NULL; @@ -4103,17 +4141,17 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (uniform) { - ShaderNode::Uniform uniform; + ShaderNode::Uniform uniform2; if (is_sampler_type(type)) { - uniform.texture_order = texture_uniforms++; - uniform.order = -1; + uniform2.texture_order = texture_uniforms++; + uniform2.order = -1; } else { - uniform.texture_order = -1; - uniform.order = uniforms++; + uniform2.texture_order = -1; + uniform2.order = uniforms++; } - uniform.type = type; - uniform.precision = precision; + uniform2.type = type; + uniform2.precision = precision; //todo parse default value @@ -4124,26 +4162,26 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type == TK_HINT_WHITE_TEXTURE) { - uniform.hint = ShaderNode::Uniform::HINT_WHITE; + uniform2.hint = ShaderNode::Uniform::HINT_WHITE; } else if (tk.type == TK_HINT_BLACK_TEXTURE) { - uniform.hint = ShaderNode::Uniform::HINT_BLACK; + uniform2.hint = ShaderNode::Uniform::HINT_BLACK; } else if (tk.type == TK_HINT_NORMAL_TEXTURE) { - uniform.hint = ShaderNode::Uniform::HINT_NORMAL; + uniform2.hint = ShaderNode::Uniform::HINT_NORMAL; } else if (tk.type == TK_HINT_ANISO_TEXTURE) { - uniform.hint = ShaderNode::Uniform::HINT_ANISO; + uniform2.hint = ShaderNode::Uniform::HINT_ANISO; } else if (tk.type == TK_HINT_ALBEDO_TEXTURE) { - uniform.hint = ShaderNode::Uniform::HINT_ALBEDO; + uniform2.hint = ShaderNode::Uniform::HINT_ALBEDO; } else if (tk.type == TK_HINT_BLACK_ALBEDO_TEXTURE) { - uniform.hint = ShaderNode::Uniform::HINT_BLACK_ALBEDO; + uniform2.hint = ShaderNode::Uniform::HINT_BLACK_ALBEDO; } else if (tk.type == TK_HINT_COLOR) { if (type != TYPE_VEC4) { _set_error("Color hint is for vec4 only"); return ERR_PARSE_ERROR; } - uniform.hint = ShaderNode::Uniform::HINT_COLOR; + uniform2.hint = ShaderNode::Uniform::HINT_COLOR; } else if (tk.type == TK_HINT_RANGE) { - uniform.hint = ShaderNode::Uniform::HINT_RANGE; + uniform2.hint = ShaderNode::Uniform::HINT_RANGE; if (type != TYPE_FLOAT && type != TYPE_INT) { _set_error("Range hint is for float and int only"); return ERR_PARSE_ERROR; @@ -4169,8 +4207,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - uniform.hint_range[0] = tk.constant; - uniform.hint_range[0] *= sign; + uniform2.hint_range[0] = tk.constant; + uniform2.hint_range[0] *= sign; tk = _get_token(); @@ -4193,8 +4231,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - uniform.hint_range[1] = tk.constant; - uniform.hint_range[1] *= sign; + uniform2.hint_range[1] = tk.constant; + uniform2.hint_range[1] *= sign; tk = _get_token(); @@ -4206,13 +4244,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - uniform.hint_range[2] = tk.constant; + uniform2.hint_range[2] = tk.constant; tk = _get_token(); } else { if (type == TYPE_INT) { - uniform.hint_range[2] = 1; + uniform2.hint_range[2] = 1; } else { - uniform.hint_range[2] = 0.001; + uniform2.hint_range[2] = 0.001; } } @@ -4225,7 +4263,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _set_error("Expected valid type hint after ':'."); } - if (uniform.hint != ShaderNode::Uniform::HINT_RANGE && uniform.hint != ShaderNode::Uniform::HINT_NONE && uniform.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) { + if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) { _set_error("This hint is only for sampler types"); return ERR_PARSE_ERROR; } @@ -4245,16 +4283,16 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct ConstantNode *cn = static_cast<ConstantNode *>(expr); - uniform.default_value.resize(cn->values.size()); + uniform2.default_value.resize(cn->values.size()); - if (!convert_constant(cn, uniform.type, uniform.default_value.ptrw())) { - _set_error("Can't convert constant to " + get_datatype_name(uniform.type)); + if (!convert_constant(cn, uniform2.type, uniform2.default_value.ptrw())) { + _set_error("Can't convert constant to " + get_datatype_name(uniform2.type)); return ERR_PARSE_ERROR; } tk = _get_token(); } - shader->uniforms[name] = uniform; + shader->uniforms[name] = uniform2; if (tk.type != TK_SEMICOLON) { _set_error("Expected ';'"); diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index e1ecba6334..af6e3db149 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -267,24 +267,24 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr for (int i = 0; i < l; i++) { - const Canvas::ChildItem &ci = p_canvas->child_items[i]; - _render_canvas_item_tree(ci.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); + const Canvas::ChildItem &ci2 = p_canvas->child_items[i]; + _render_canvas_item_tree(ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); //mirroring (useful for scrolling backgrounds) - if (ci.mirror.x != 0) { + if (ci2.mirror.x != 0) { - Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci.mirror.x, 0)); - _render_canvas_item_tree(ci.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0)); + _render_canvas_item_tree(ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } - if (ci.mirror.y != 0) { + if (ci2.mirror.y != 0) { - Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci.mirror.y)); - _render_canvas_item_tree(ci.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y)); + _render_canvas_item_tree(ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } - if (ci.mirror.y != 0 && ci.mirror.x != 0) { + if (ci2.mirror.y != 0 && ci2.mirror.x != 0) { - Transform2D xform2 = p_transform * Transform2D(0, ci.mirror); - _render_canvas_item_tree(ci.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror); + _render_canvas_item_tree(ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } } } @@ -319,6 +319,19 @@ void VisualServerCanvas::canvas_set_modulate(RID p_canvas, const Color &p_color) canvas->modulate = p_color; } +void VisualServerCanvas::canvas_set_disable_scale(bool p_disable) { + disable_scale = p_disable; +} + +void VisualServerCanvas::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) { + + Canvas *canvas = canvas_owner.get(p_canvas); + ERR_FAIL_COND(!canvas); + + canvas->parent = p_parent; + canvas->parent_scale = p_scale; +} + RID VisualServerCanvas::canvas_item_create() { Item *canvas_item = memnew(Item); @@ -758,11 +771,12 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - int ps = p_points.size(); - ERR_FAIL_COND(!p_colors.empty() && p_colors.size() != ps && p_colors.size() != 1); - ERR_FAIL_COND(!p_uvs.empty() && p_uvs.size() != ps); - ERR_FAIL_COND(!p_bones.empty() && p_bones.size() != ps * 4); - ERR_FAIL_COND(!p_weights.empty() && p_weights.size() != ps * 4); + int vertex_count = p_points.size(); + ERR_FAIL_COND(vertex_count == 0); + ERR_FAIL_COND(!p_colors.empty() && p_colors.size() != vertex_count && p_colors.size() != 1); + ERR_FAIL_COND(!p_uvs.empty() && p_uvs.size() != vertex_count); + ERR_FAIL_COND(!p_bones.empty() && p_bones.size() != vertex_count * 4); + ERR_FAIL_COND(!p_weights.empty() && p_weights.size() != vertex_count * 4); Vector<int> indices = p_indices; @@ -770,9 +784,9 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector if (indices.empty()) { - ERR_FAIL_COND(ps % 3 != 0); + ERR_FAIL_COND(vertex_count % 3 != 0); if (p_count == -1) - count = ps; + count = vertex_count; } else { ERR_FAIL_COND(indices.size() % 3 != 0); @@ -1433,4 +1447,5 @@ bool VisualServerCanvas::free(RID p_rid) { } VisualServerCanvas::VisualServerCanvas() { + disable_scale = false; } diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 7d788cbe14..8162085ced 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -126,6 +126,8 @@ public: bool children_order_dirty; Vector<ChildItem> child_items; Color modulate; + RID parent; + float parent_scale; int find_item(Item *p_item) { for (int i = 0; i < child_items.size(); i++) { @@ -143,13 +145,16 @@ public: Canvas() { modulate = Color(1, 1, 1, 1); children_order_dirty = true; + parent_scale = 1.0; } }; - RID_Owner<Canvas> canvas_owner; + mutable RID_Owner<Canvas> canvas_owner; RID_Owner<Item> canvas_item_owner; RID_Owner<RasterizerCanvas::Light> canvas_light_owner; + bool disable_scale; + private: void _render_canvas_item_tree(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights); void _render_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); @@ -161,6 +166,8 @@ public: RID canvas_create(); void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); void canvas_set_modulate(RID p_canvas, const Color &p_color); + void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale); + void canvas_set_disable_scale(bool p_disable); RID canvas_item_create(); void canvas_item_set_parent(RID p_item, RID p_parent); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 6622433b17..a9ca920178 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -123,7 +123,6 @@ void VisualServerRaster::draw(bool p_swap_buffers, double frame_step) { frame_drawn_callbacks.pop_front(); } - VS::get_singleton()->emit_signal("frame_post_draw"); } void VisualServerRaster::sync() { diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 89a759b963..8ce25ba906 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -296,6 +296,7 @@ public: BIND3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &) BIND2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int) BIND2(skeleton_set_base_transform_2d, RID, const Transform2D &) + BIND3(skeleton_set_world_transform, RID, bool, const Transform &) /* Light API */ @@ -568,6 +569,8 @@ public: BIND0R(RID, canvas_create) BIND3(canvas_set_item_mirroring, RID, RID, const Point2 &) BIND2(canvas_set_modulate, RID, const Color &) + BIND3(canvas_set_parent, RID, RID, float) + BIND1(canvas_set_disable_scale, bool) BIND0R(RID, canvas_item_create) BIND2(canvas_item_set_parent, RID, RID) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 5d0456686a..2590e29aef 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -445,6 +445,9 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { InstanceGeometryData *geom = memnew(InstanceGeometryData); instance->base_data = geom; + if (instance->base_type == VS::INSTANCE_MESH) { + instance->blend_values.resize(VSG::storage->mesh_get_blend_shape_count(p_base)); + } } break; case VS::INSTANCE_REFLECTION_PROBE: { @@ -2480,7 +2483,7 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { uint32_t a = uint32_t(alpha_block[x][y]) - min_alpha; //convert range to 3 bits a = int((a * 7.0 / (max_alpha - min_alpha)) + 0.5); - a = CLAMP(a, 0, 7); //just to be sure + a = MIN(a, 7); //just to be sure a = 7 - a; //because range is inverted in this mode if (a == 0) { //do none, remain @@ -2916,7 +2919,7 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { uint32_t idx = level_cells[j]; - uint32_t r = (uint32_t(local_data[idx].energy[0]) / probe_data->dynamic.bake_dynamic_range) >> 2; + uint32_t r2 = (uint32_t(local_data[idx].energy[0]) / probe_data->dynamic.bake_dynamic_range) >> 2; uint32_t g = (uint32_t(local_data[idx].energy[1]) / probe_data->dynamic.bake_dynamic_range) >> 2; uint32_t b = (uint32_t(local_data[idx].energy[2]) / probe_data->dynamic.bake_dynamic_range) >> 2; uint32_t a = (cells[idx].level_alpha >> 8) & 0xFF; @@ -2924,10 +2927,10 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { uint32_t mm_ofs = sizes[0] * sizes[1] * (local_data[idx].pos[2]) + sizes[0] * (local_data[idx].pos[1]) + (local_data[idx].pos[0]); mm_ofs *= 4; //for RGBA (4 bytes) - mipmapw[mm_ofs + 0] = uint8_t(CLAMP(r, 0, 255)); - mipmapw[mm_ofs + 1] = uint8_t(CLAMP(g, 0, 255)); - mipmapw[mm_ofs + 2] = uint8_t(CLAMP(b, 0, 255)); - mipmapw[mm_ofs + 3] = uint8_t(CLAMP(a, 0, 255)); + mipmapw[mm_ofs + 0] = uint8_t(MIN(r2, 255)); + mipmapw[mm_ofs + 1] = uint8_t(MIN(g, 255)); + mipmapw[mm_ofs + 2] = uint8_t(MIN(b, 255)); + mipmapw[mm_ofs + 3] = uint8_t(MIN(a, 255)); } } } else if (probe_data->dynamic.compression == RasterizerStorage::GI_PROBE_S3TC) { diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index d6e43b0f00..79fdefe5c1 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -35,6 +35,33 @@ #include "visual_server_globals.h" #include "visual_server_scene.h" +static Transform2D _canvas_get_transform(VisualServerViewport::Viewport *p_viewport, VisualServerCanvas::Canvas *p_canvas, VisualServerViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) { + + Transform2D xf = p_viewport->global_transform; + + float scale = 1.0; + if (p_viewport->canvas_map.has(p_canvas->parent)) { + xf = xf * p_viewport->canvas_map[p_canvas->parent].transform; + scale = p_canvas->parent_scale; + } + + xf = xf * p_canvas_data->transform; + + if (scale != 1.0 && !VSG::canvas->disable_scale) { + Vector2 pivot = p_vp_size * 0.5; + Transform2D xfpivot; + xfpivot.set_origin(pivot); + Transform2D xfscale; + xfscale.scale(Vector2(scale, scale)); + + xf = xfpivot.affine_inverse() * xf; + xf = xfscale * xf; + xf = xfpivot * xf; + } + + return xf; +} + void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye) { /* Camera should always be BEFORE any other 3D */ @@ -86,10 +113,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - Transform2D xf = p_viewport->global_transform * E->get().transform; - VisualServerCanvas::Canvas *canvas = static_cast<VisualServerCanvas::Canvas *>(E->get().canvas); + Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); + //find lights in canvas for (Set<RasterizerCanvas::Light *>::Element *F = canvas->lights.front(); F; F = F->next()) { @@ -167,7 +194,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E RasterizerCanvas::Light *light = lights_with_shadow; while (light) { - VSG::canvas_render->canvas_light_shadow_buffer_update(light->shadow_buffer, light->xform_cache.affine_inverse(), light->item_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders, &light->shadow_matrix_cache); + VSG::canvas_render->canvas_light_shadow_buffer_update(light->shadow_buffer, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders, &light->shadow_matrix_cache); light = light->shadows_next_ptr; } @@ -193,7 +220,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E VisualServerCanvas::Canvas *canvas = static_cast<VisualServerCanvas::Canvas *>(E->get()->canvas); - Transform2D xform = p_viewport->global_transform * E->get()->transform; + Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size); RasterizerCanvas::Light *canvas_lights = NULL; diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index 4e3015c020..5176551540 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -90,7 +90,8 @@ public: } CanvasKey(const RID &p_canvas, int p_layer, int p_sublayer) { canvas = p_canvas; - stacking = ((int64_t)p_layer << 32) + p_sublayer; + int64_t sign = p_layer < 0 ? -1 : 1; + stacking = sign * (((int64_t)ABS(p_layer)) << 32) + p_sublayer; } int get_layer() const { return stacking >> 32; } }; diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index a6f0bd9d16..efe251e9de 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -232,6 +232,7 @@ public: FUNC3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &) FUNC2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int) FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &) + FUNC3(skeleton_set_world_transform, RID, bool, const Transform &) /* Light API */ @@ -486,6 +487,8 @@ public: FUNCRID(canvas) FUNC3(canvas_set_item_mirroring, RID, RID, const Point2 &) FUNC2(canvas_set_modulate, RID, const Color &) + FUNC3(canvas_set_parent, RID, RID, float) + FUNC1(canvas_set_disable_scale, bool) FUNCRID(canvas_item) FUNC2(canvas_item_set_parent, RID, RID) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 14c9a29ae5..19c6106502 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -776,7 +776,7 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ continue; //break; ERR_FAIL_INDEX_V(idx, total_bones, ERR_INVALID_DATA); - if (bptr->size.x < 0) { + if (bptr[idx].size.x < 0) { //first bptr[idx] = AABB(v, SMALL_VEC3); any_valid = true; @@ -1163,11 +1163,11 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim PoolVector<uint8_t> noindex; AABB laabb; - Error err = _surface_set_data(p_blend_shapes[i], format & ~ARRAY_FORMAT_INDEX, offsets, total_elem_size, vertex_array_shape, array_len, noindex, 0, laabb, bone_aabb); + Error err2 = _surface_set_data(p_blend_shapes[i], format & ~ARRAY_FORMAT_INDEX, offsets, total_elem_size, vertex_array_shape, array_len, noindex, 0, laabb, bone_aabb); aabb.merge_with(laabb); - if (err) { + if (err2) { ERR_EXPLAIN("Invalid blend shape array format for surface"); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND(err2 != OK); } blend_shape_data.push_back(vertex_array_shape); @@ -2368,11 +2368,11 @@ VisualServer::VisualServer() { //ERR_FAIL_COND(singleton); singleton = this; - GLOBAL_DEF("rendering/vram_compression/import_bptc", false); - GLOBAL_DEF("rendering/vram_compression/import_s3tc", true); - GLOBAL_DEF("rendering/vram_compression/import_etc", false); - GLOBAL_DEF("rendering/vram_compression/import_etc2", true); - GLOBAL_DEF("rendering/vram_compression/import_pvrtc", false); + GLOBAL_DEF_RST("rendering/vram_compression/import_bptc", false); + GLOBAL_DEF_RST("rendering/vram_compression/import_s3tc", true); + GLOBAL_DEF_RST("rendering/vram_compression/import_etc", false); + GLOBAL_DEF_RST("rendering/vram_compression/import_etc2", true); + GLOBAL_DEF_RST("rendering/vram_compression/import_pvrtc", false); GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096); GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048); diff --git a/servers/visual_server.h b/servers/visual_server.h index 96a5d19efd..596b893b69 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -393,6 +393,7 @@ public: virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; + virtual void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_base_transform) = 0; /* Light API */ @@ -859,6 +860,9 @@ public: virtual RID canvas_create() = 0; virtual void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) = 0; virtual void canvas_set_modulate(RID p_canvas, const Color &p_color) = 0; + virtual void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) = 0; + + virtual void canvas_set_disable_scale(bool p_disable) = 0; virtual RID canvas_item_create() = 0; virtual void canvas_item_set_parent(RID p_item, RID p_parent) = 0; |