diff options
Diffstat (limited to 'scene/2d/camera_2d.cpp')
-rw-r--r-- | scene/2d/camera_2d.cpp | 107 |
1 files changed, 91 insertions, 16 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 722858b674..e9bab274c6 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -54,7 +54,12 @@ void Camera2D::_update_scroll() { if (is_current()) { ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)); - Transform2D xform = get_camera_transform(); + Transform2D xform; + if (is_physics_interpolated_and_enabled()) { + xform = _interpolation_data.xform_prev.interpolate_with(_interpolation_data.xform_curr, Engine::get_singleton()->get_physics_interpolation_fraction()); + } else { + xform = get_camera_transform(); + } viewport->set_canvas_transform(xform); @@ -68,15 +73,26 @@ void Camera2D::_update_scroll() { } void Camera2D::_update_process_callback() { - if (_is_editing_in_editor()) { + if (is_physics_interpolated_and_enabled()) { + set_process_internal(is_current()); + set_physics_process_internal(is_current()); + +#ifdef TOOLS_ENABLED + if (process_callback == CAMERA2D_PROCESS_IDLE) { + WARN_PRINT_ONCE("Camera2D overridden to physics process mode due to use of physics interpolation."); + } +#endif + } else if (_is_editing_in_editor()) { set_process_internal(false); set_physics_process_internal(false); - } else if (process_callback == CAMERA2D_PROCESS_IDLE) { - set_process_internal(true); - set_physics_process_internal(false); } else { - set_process_internal(false); - set_physics_process_internal(true); + if (process_callback == CAMERA2D_PROCESS_IDLE) { + set_process_internal(true); + set_physics_process_internal(false); + } else { + set_process_internal(false); + set_physics_process_internal(true); + } } } @@ -161,8 +177,15 @@ Transform2D Camera2D::get_camera_transform() { } } + // FIXME: There is a bug here, introduced before physics interpolation. + // Smoothing occurs rather confusingly during the call to get_camera_transform(). + // It may be called MULTIPLE TIMES on certain frames, + // therefore smoothing is not currently applied only once per frame / tick, + // which will result in some haphazard results. if (position_smoothing_enabled && !_is_editing_in_editor()) { - real_t c = position_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time()); + bool physics_process = (process_callback == CAMERA2D_PROCESS_PHYSICS) || is_physics_interpolated_and_enabled(); + real_t delta = physics_process ? get_physics_process_delta_time() : get_process_delta_time(); + real_t c = position_smoothing_speed * delta; smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos; ret_camera_pos = smoothed_camera_pos; //camera_pos=camera_pos*(1.0-position_smoothing_speed)+new_camera_pos*position_smoothing_speed; @@ -223,17 +246,52 @@ Transform2D Camera2D::get_camera_transform() { return xform.affine_inverse(); } +void Camera2D::_ensure_update_interpolation_data() { + // The "curr -> previous" update can either occur + // on NOTIFICATION_INTERNAL_PHYSICS_PROCESS, OR + // on NOTIFICATION_TRANSFORM_CHANGED, + // if NOTIFICATION_TRANSFORM_CHANGED takes place earlier than + // NOTIFICATION_INTERNAL_PHYSICS_PROCESS on a tick. + // This is to ensure that the data keeps flowing, but the new data + // doesn't overwrite before prev has been set. + + // Keep the data flowing. + uint64_t tick = Engine::get_singleton()->get_physics_frames(); + if (_interpolation_data.last_update_physics_tick != tick) { + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + _interpolation_data.last_update_physics_tick = tick; + } +} + void Camera2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_INTERNAL_PROCESS: - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + case NOTIFICATION_INTERNAL_PROCESS: { _update_scroll(); } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (is_physics_interpolated_and_enabled()) { + _ensure_update_interpolation_data(); + _interpolation_data.xform_curr = get_camera_transform(); + } else { + _update_scroll(); + } + } break; + + case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: { + // Force the limits etc. to update. + _interpolation_data.xform_curr = get_camera_transform(); + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { - if (!position_smoothing_enabled || _is_editing_in_editor()) { + if ((!position_smoothing_enabled && !is_physics_interpolated_and_enabled()) || _is_editing_in_editor()) { _update_scroll(); } + if (is_physics_interpolated_and_enabled()) { + _ensure_update_interpolation_data(); + _interpolation_data.xform_curr = get_camera_transform(); + } } break; case NOTIFICATION_ENTER_TREE: { @@ -260,6 +318,15 @@ void Camera2D::_notification(int p_what) { _update_process_callback(); first = true; _update_scroll(); + + // Note that NOTIFICATION_RESET_PHYSICS_INTERPOLATION + // is automatically called before this because Camera2D is inherited + // from CanvasItem. However, the camera transform is not up to date + // until this point, so we do an extra manual reset. + if (is_physics_interpolated_and_enabled()) { + _interpolation_data.xform_curr = get_camera_transform(); + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + } } break; case NOTIFICATION_EXIT_TREE: { @@ -431,12 +498,17 @@ void Camera2D::_make_current(Object *p_which) { queue_redraw(); - if (p_which == this) { + bool was_current = viewport->get_camera_2d() == this; + bool is_current = p_which == this; + + if (is_current) { viewport->_camera_2d_set(this); - } else { - if (viewport->get_camera_2d() == this) { - viewport->_camera_2d_set(nullptr); - } + } else if (was_current) { + viewport->_camera_2d_set(nullptr); + } + + if (is_current != was_current) { + _update_process_callback(); } } @@ -456,6 +528,7 @@ void Camera2D::make_current() { _make_current(this); } _update_scroll(); + _update_process_callback(); } void Camera2D::clear_current() { @@ -468,6 +541,8 @@ void Camera2D::clear_current() { if (!custom_viewport || ObjectDB::get_instance(custom_viewport_id)) { viewport->assign_next_enabled_camera_2d(group_name); } + + _update_process_callback(); } bool Camera2D::is_current() const { |