You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-07 12:30:27 +00:00
Refactor VisibilityNotifier
* Works from RenderinServer * Accurately tells when on or off-scren, its no longer approximate. * VisibilityEnabler also simplified to use the process mode instead.
This commit is contained in:
@@ -1616,9 +1616,6 @@
|
|||||||
<member name="rendering/xr/enabled" type="bool" setter="" getter="" default="false">
|
<member name="rendering/xr/enabled" type="bool" setter="" getter="" default="false">
|
||||||
If [code]true[/code], XR support is enabled in Godot, this ensures required shaders are compiled.
|
If [code]true[/code], XR support is enabled in Godot, this ensures required shaders are compiled.
|
||||||
</member>
|
</member>
|
||||||
<member name="world/2d/cell_size" type="int" setter="" getter="" default="100">
|
|
||||||
Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses (in pixels).
|
|
||||||
</member>
|
|
||||||
</members>
|
</members>
|
||||||
<constants>
|
<constants>
|
||||||
</constants>
|
</constants>
|
||||||
|
|||||||
@@ -1,79 +1,25 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<class name="VisibilityEnabler2D" inherits="VisibilityNotifier2D" version="4.0">
|
<class name="VisibilityEnabler2D" inherits="VisibilityNotifier2D" version="4.0">
|
||||||
<brief_description>
|
<brief_description>
|
||||||
Enables certain nodes only when approximately visible.
|
|
||||||
</brief_description>
|
</brief_description>
|
||||||
<description>
|
<description>
|
||||||
The VisibilityEnabler2D will disable [RigidBody2D], [AnimationPlayer], and other nodes when they are not visible. It will only affect nodes with the same root node as the VisibilityEnabler2D, and the root node itself.
|
|
||||||
If you just want to receive notifications, use [VisibilityNotifier2D] instead.
|
|
||||||
[b]Note:[/b] For performance reasons, VisibilityEnabler2D uses an approximate heuristic with precision determined by [member ProjectSettings.world/2d/cell_size]. If you need precise visibility checking, use another method such as adding an [Area2D] node as a child of a [Camera2D] node.
|
|
||||||
[b]Note:[/b] VisibilityEnabler2D will not affect nodes added after scene initialization.
|
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
<method name="is_enabler_enabled" qualifiers="const">
|
|
||||||
<return type="bool">
|
|
||||||
</return>
|
|
||||||
<argument index="0" name="enabler" type="int" enum="VisibilityEnabler2D.Enabler">
|
|
||||||
</argument>
|
|
||||||
<description>
|
|
||||||
Returns whether the enabler identified by given [enum Enabler] constant is active.
|
|
||||||
</description>
|
|
||||||
</method>
|
|
||||||
<method name="set_enabler">
|
|
||||||
<return type="void">
|
|
||||||
</return>
|
|
||||||
<argument index="0" name="enabler" type="int" enum="VisibilityEnabler2D.Enabler">
|
|
||||||
</argument>
|
|
||||||
<argument index="1" name="enabled" type="bool">
|
|
||||||
</argument>
|
|
||||||
<description>
|
|
||||||
Sets active state of the enabler identified by given [enum Enabler] constant.
|
|
||||||
</description>
|
|
||||||
</method>
|
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
<member name="freeze_bodies" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
|
<member name="enable_mode" type="int" setter="set_enable_mode" getter="get_enable_mode" enum="VisibilityEnabler2D.EnableMode" default="0">
|
||||||
If [code]true[/code], [RigidBody2D] nodes will be paused.
|
|
||||||
</member>
|
</member>
|
||||||
<member name="pause_animated_sprites" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
|
<member name="enable_node_path" type="NodePath" setter="set_enable_node_path" getter="get_enable_node_path" default="NodePath("..")">
|
||||||
If [code]true[/code], [AnimatedSprite2D] nodes will be paused.
|
|
||||||
</member>
|
|
||||||
<member name="pause_animations" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
|
|
||||||
If [code]true[/code], [AnimationPlayer] nodes will be paused.
|
|
||||||
</member>
|
|
||||||
<member name="pause_particles" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
|
|
||||||
If [code]true[/code], [GPUParticles2D] nodes will be paused.
|
|
||||||
</member>
|
|
||||||
<member name="physics_process_parent" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="false">
|
|
||||||
If [code]true[/code], the parent's [method Node._physics_process] will be stopped.
|
|
||||||
</member>
|
|
||||||
<member name="process_parent" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="false">
|
|
||||||
If [code]true[/code], the parent's [method Node._process] will be stopped.
|
|
||||||
</member>
|
</member>
|
||||||
</members>
|
</members>
|
||||||
<constants>
|
<constants>
|
||||||
<constant name="ENABLER_PAUSE_ANIMATIONS" value="0" enum="Enabler">
|
<constant name="ENABLE_MODE_INHERIT" value="0" enum="EnableMode">
|
||||||
This enabler will pause [AnimationPlayer] nodes.
|
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="ENABLER_FREEZE_BODIES" value="1" enum="Enabler">
|
<constant name="ENABLE_MODE_ALWAYS" value="1" enum="EnableMode">
|
||||||
This enabler will freeze [RigidBody2D] nodes.
|
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="ENABLER_PAUSE_PARTICLES" value="2" enum="Enabler">
|
<constant name="ENABLE_MODE_WHEN_PAUSED" value="2" enum="EnableMode">
|
||||||
This enabler will stop [GPUParticles2D] nodes.
|
|
||||||
</constant>
|
|
||||||
<constant name="ENABLER_PARENT_PROCESS" value="3" enum="Enabler">
|
|
||||||
This enabler will stop the parent's _process function.
|
|
||||||
</constant>
|
|
||||||
<constant name="ENABLER_PARENT_PHYSICS_PROCESS" value="4" enum="Enabler">
|
|
||||||
This enabler will stop the parent's _physics_process function.
|
|
||||||
</constant>
|
|
||||||
<constant name="ENABLER_PAUSE_ANIMATED_SPRITES" value="5" enum="Enabler">
|
|
||||||
This enabler will stop [AnimatedSprite2D] nodes animations.
|
|
||||||
</constant>
|
|
||||||
<constant name="ENABLER_MAX" value="6" enum="Enabler">
|
|
||||||
Represents the size of the [enum Enabler] enum.
|
|
||||||
</constant>
|
</constant>
|
||||||
</constants>
|
</constants>
|
||||||
</class>
|
</class>
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<class name="VisibilityNotifier2D" inherits="Node2D" version="4.0">
|
<class name="VisibilityNotifier2D" inherits="Node2D" version="4.0">
|
||||||
<brief_description>
|
<brief_description>
|
||||||
Detects approximately when the node is visible on screen.
|
Detects when the node extents are visible on screen.
|
||||||
</brief_description>
|
</brief_description>
|
||||||
<description>
|
<description>
|
||||||
The VisibilityNotifier2D detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a viewport.
|
The VisibilityNotifier2D detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a viewport.
|
||||||
If you want nodes to be disabled automatically when they exit the screen, use [VisibilityEnabler2D] instead.
|
If you want nodes to be disabled automatically when they exit the screen, use [VisibilityEnabler2D] instead.
|
||||||
[b]Note:[/b] For performance reasons, VisibilityNotifier2D uses an approximate heuristic with precision determined by [member ProjectSettings.world/2d/cell_size]. If you need precise visibility checking, use another method such as adding an [Area2D] node as a child of a [Camera2D] node.
|
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
|
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
|
||||||
@@ -37,20 +36,6 @@
|
|||||||
Emitted when the VisibilityNotifier2D exits the screen.
|
Emitted when the VisibilityNotifier2D exits the screen.
|
||||||
</description>
|
</description>
|
||||||
</signal>
|
</signal>
|
||||||
<signal name="viewport_entered">
|
|
||||||
<argument index="0" name="viewport" type="Viewport">
|
|
||||||
</argument>
|
|
||||||
<description>
|
|
||||||
Emitted when the VisibilityNotifier2D enters a [Viewport]'s view.
|
|
||||||
</description>
|
|
||||||
</signal>
|
|
||||||
<signal name="viewport_exited">
|
|
||||||
<argument index="0" name="viewport" type="Viewport">
|
|
||||||
</argument>
|
|
||||||
<description>
|
|
||||||
Emitted when the VisibilityNotifier2D exits a [Viewport]'s view.
|
|
||||||
</description>
|
|
||||||
</signal>
|
|
||||||
</signals>
|
</signals>
|
||||||
<constants>
|
<constants>
|
||||||
</constants>
|
</constants>
|
||||||
|
|||||||
@@ -170,7 +170,6 @@ void AudioStreamPlayer2D::_notification(int p_what) {
|
|||||||
//update anything related to position first, if possible of course
|
//update anything related to position first, if possible of course
|
||||||
|
|
||||||
if (!output_ready.is_set()) {
|
if (!output_ready.is_set()) {
|
||||||
List<Viewport *> viewports;
|
|
||||||
Ref<World2D> world_2d = get_world_2d();
|
Ref<World2D> world_2d = get_world_2d();
|
||||||
ERR_FAIL_COND(world_2d.is_null());
|
ERR_FAIL_COND(world_2d.is_null());
|
||||||
|
|
||||||
@@ -203,8 +202,9 @@ void AudioStreamPlayer2D::_notification(int p_what) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
world_2d->get_viewport_list(&viewports);
|
const Set<Viewport *> viewports = world_2d->get_viewports();
|
||||||
for (List<Viewport *>::Element *E = viewports.front(); E; E = E->next()) {
|
|
||||||
|
for (Set<Viewport *>::Element *E = viewports.front(); E; E = E->next()) {
|
||||||
Viewport *vp = E->get();
|
Viewport *vp = E->get();
|
||||||
if (vp->is_audio_listener_2d()) {
|
if (vp->is_audio_listener_2d()) {
|
||||||
//compute matrix to convert to screen
|
//compute matrix to convert to screen
|
||||||
|
|||||||
@@ -48,46 +48,29 @@ bool VisibilityNotifier2D::_edit_use_rect() const {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void VisibilityNotifier2D::_enter_viewport(Viewport *p_viewport) {
|
void VisibilityNotifier2D::_visibility_enter() {
|
||||||
ERR_FAIL_COND(viewports.has(p_viewport));
|
if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
|
||||||
viewports.insert(p_viewport);
|
|
||||||
|
|
||||||
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewports.size() == 1) {
|
on_screen = true;
|
||||||
emit_signal(SceneStringNames::get_singleton()->screen_entered);
|
emit_signal(SceneStringNames::get_singleton()->screen_entered);
|
||||||
|
|
||||||
_screen_enter();
|
_screen_enter();
|
||||||
}
|
|
||||||
emit_signal(SceneStringNames::get_singleton()->viewport_entered, p_viewport);
|
|
||||||
}
|
}
|
||||||
|
void VisibilityNotifier2D::_visibility_exit() {
|
||||||
void VisibilityNotifier2D::_exit_viewport(Viewport *p_viewport) {
|
if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
|
||||||
ERR_FAIL_COND(!viewports.has(p_viewport));
|
|
||||||
viewports.erase(p_viewport);
|
|
||||||
|
|
||||||
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_signal(SceneStringNames::get_singleton()->viewport_exited, p_viewport);
|
on_screen = false;
|
||||||
if (viewports.size() == 0) {
|
|
||||||
emit_signal(SceneStringNames::get_singleton()->screen_exited);
|
emit_signal(SceneStringNames::get_singleton()->screen_exited);
|
||||||
|
|
||||||
_screen_exit();
|
_screen_exit();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) {
|
void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) {
|
||||||
rect = p_rect;
|
rect = p_rect;
|
||||||
if (is_inside_tree()) {
|
if (is_inside_tree()) {
|
||||||
get_world_2d()->_update_notifier(this, get_global_transform().xform(rect));
|
RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibilityNotifier2D::_visibility_enter), callable_mp(this, &VisibilityNotifier2D::_visibility_exit));
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
|
||||||
update();
|
|
||||||
item_rect_changed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +82,8 @@ void VisibilityNotifier2D::_notification(int p_what) {
|
|||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_ENTER_TREE: {
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
//get_world_2d()->
|
//get_world_2d()->
|
||||||
get_world_2d()->_register_notifier(this, get_global_transform().xform(rect));
|
on_screen = false;
|
||||||
} break;
|
RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibilityNotifier2D::_visibility_enter), callable_mp(this, &VisibilityNotifier2D::_visibility_exit));
|
||||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
|
||||||
//get_world_2d()->
|
|
||||||
get_world_2d()->_update_notifier(this, get_global_transform().xform(rect));
|
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_DRAW: {
|
case NOTIFICATION_DRAW: {
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
@@ -111,13 +91,14 @@ void VisibilityNotifier2D::_notification(int p_what) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_EXIT_TREE: {
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
get_world_2d()->_remove_notifier(this);
|
on_screen = false;
|
||||||
|
RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), false, Rect2(), Callable(), Callable());
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisibilityNotifier2D::is_on_screen() const {
|
bool VisibilityNotifier2D::is_on_screen() const {
|
||||||
return viewports.size() > 0;
|
return on_screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisibilityNotifier2D::_bind_methods() {
|
void VisibilityNotifier2D::_bind_methods() {
|
||||||
@@ -127,235 +108,106 @@ void VisibilityNotifier2D::_bind_methods() {
|
|||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect"), "set_rect", "get_rect");
|
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect"), "set_rect", "get_rect");
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("viewport_entered", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport")));
|
|
||||||
ADD_SIGNAL(MethodInfo("viewport_exited", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport")));
|
|
||||||
ADD_SIGNAL(MethodInfo("screen_entered"));
|
ADD_SIGNAL(MethodInfo("screen_entered"));
|
||||||
ADD_SIGNAL(MethodInfo("screen_exited"));
|
ADD_SIGNAL(MethodInfo("screen_exited"));
|
||||||
}
|
}
|
||||||
|
|
||||||
VisibilityNotifier2D::VisibilityNotifier2D() {
|
VisibilityNotifier2D::VisibilityNotifier2D() {
|
||||||
rect = Rect2(-10, -10, 20, 20);
|
rect = Rect2(-10, -10, 20, 20);
|
||||||
set_notify_transform(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
void VisibilityEnabler2D::_screen_enter() {
|
void VisibilityEnabler2D::_screen_enter() {
|
||||||
for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
|
_update_enable_mode(true);
|
||||||
_change_node_state(E->key(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) {
|
|
||||||
get_parent()->set_physics_process(true);
|
|
||||||
}
|
|
||||||
if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) {
|
|
||||||
get_parent()->set_process(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
visible = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisibilityEnabler2D::_screen_exit() {
|
void VisibilityEnabler2D::_screen_exit() {
|
||||||
for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
|
_update_enable_mode(false);
|
||||||
_change_node_state(E->key(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) {
|
|
||||||
get_parent()->set_physics_process(false);
|
|
||||||
}
|
|
||||||
if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) {
|
|
||||||
get_parent()->set_process(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
visible = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisibilityEnabler2D::_find_nodes(Node *p_node) {
|
void VisibilityEnabler2D::set_enable_mode(EnableMode p_mode) {
|
||||||
bool add = false;
|
enable_mode = p_mode;
|
||||||
Variant meta;
|
if (is_inside_tree()) {
|
||||||
|
_update_enable_mode(is_on_screen());
|
||||||
{
|
|
||||||
RigidBody2D *rb2d = Object::cast_to<RigidBody2D>(p_node);
|
|
||||||
if (rb2d && ((rb2d->get_mode() == RigidBody2D::MODE_DYNAMIC || rb2d->get_mode() == RigidBody2D::MODE_DYNAMIC_LOCKED))) {
|
|
||||||
add = true;
|
|
||||||
meta = rb2d->get_mode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
|
|
||||||
if (ap) {
|
|
||||||
add = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
|
|
||||||
if (as) {
|
|
||||||
add = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
|
|
||||||
if (ps) {
|
|
||||||
add = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add) {
|
|
||||||
p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler2D::_node_removed), varray(p_node), CONNECT_ONESHOT);
|
|
||||||
nodes[p_node] = meta;
|
|
||||||
_change_node_state(p_node, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
|
||||||
Node *c = p_node->get_child(i);
|
|
||||||
if (c->get_filename() != String()) {
|
|
||||||
continue; //skip, instance
|
|
||||||
}
|
|
||||||
|
|
||||||
_find_nodes(c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VisibilityEnabler2D::EnableMode VisibilityEnabler2D::get_enable_mode() {
|
||||||
|
return enable_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisibilityEnabler2D::set_enable_node_path(NodePath p_path) {
|
||||||
|
if (enable_node_path == p_path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
enable_node_path = p_path;
|
||||||
|
if (is_inside_tree()) {
|
||||||
|
node_id = ObjectID();
|
||||||
|
Node *node = get_node(enable_node_path);
|
||||||
|
if (node) {
|
||||||
|
node_id = node->get_instance_id();
|
||||||
|
_update_enable_mode(is_on_screen());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodePath VisibilityEnabler2D::get_enable_node_path() {
|
||||||
|
return enable_node_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisibilityEnabler2D::_update_enable_mode(bool p_enable) {
|
||||||
|
Node *node = static_cast<Node *>(ObjectDB::get_instance(node_id));
|
||||||
|
if (node) {
|
||||||
|
if (p_enable) {
|
||||||
|
switch (enable_mode) {
|
||||||
|
case ENABLE_MODE_INHERIT: {
|
||||||
|
node->set_process_mode(PROCESS_MODE_INHERIT);
|
||||||
|
} break;
|
||||||
|
case ENABLE_MODE_ALWAYS: {
|
||||||
|
node->set_process_mode(PROCESS_MODE_ALWAYS);
|
||||||
|
} break;
|
||||||
|
case ENABLE_MODE_WHEN_PAUSED: {
|
||||||
|
node->set_process_mode(PROCESS_MODE_WHEN_PAUSED);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node->set_process_mode(PROCESS_MODE_DISABLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
void VisibilityEnabler2D::_notification(int p_what) {
|
void VisibilityEnabler2D::_notification(int p_what) {
|
||||||
if (p_what == NOTIFICATION_ENTER_TREE) {
|
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *from = this;
|
node_id = ObjectID();
|
||||||
//find where current scene starts
|
Node *node = get_node(enable_node_path);
|
||||||
while (from->get_parent() && from->get_filename() == String()) {
|
if (node) {
|
||||||
from = from->get_parent();
|
node_id = node->get_instance_id();
|
||||||
}
|
node->set_process_mode(PROCESS_MODE_DISABLED);
|
||||||
|
|
||||||
_find_nodes(from);
|
|
||||||
|
|
||||||
// We need to defer the call of set_process and set_physics_process,
|
|
||||||
// otherwise they are overwritten inside NOTIFICATION_READY.
|
|
||||||
// We can't use call_deferred, because it happens after a physics frame.
|
|
||||||
// The ready signal works as it's emitted immediately after NOTIFICATION_READY.
|
|
||||||
|
|
||||||
if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) {
|
|
||||||
get_parent()->connect(SceneStringNames::get_singleton()->ready,
|
|
||||||
callable_mp(get_parent(), &Node::set_physics_process), varray(false), CONNECT_ONESHOT);
|
|
||||||
}
|
|
||||||
if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) {
|
|
||||||
get_parent()->connect(SceneStringNames::get_singleton()->ready,
|
|
||||||
callable_mp(get_parent(), &Node::set_process), varray(false), CONNECT_ONESHOT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_what == NOTIFICATION_EXIT_TREE) {
|
if (p_what == NOTIFICATION_EXIT_TREE) {
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
node_id = ObjectID();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
|
|
||||||
if (!visible) {
|
|
||||||
_change_node_state(E->key(), true);
|
|
||||||
}
|
|
||||||
E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler2D::_node_removed));
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) {
|
|
||||||
ERR_FAIL_COND(!nodes.has(p_node));
|
|
||||||
|
|
||||||
if (enabler[ENABLER_FREEZE_BODIES]) {
|
|
||||||
RigidBody2D *rb = Object::cast_to<RigidBody2D>(p_node);
|
|
||||||
if (rb) {
|
|
||||||
rb->set_sleeping(!p_enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
|
|
||||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
|
|
||||||
|
|
||||||
if (ap) {
|
|
||||||
ap->set_active(p_enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) {
|
|
||||||
AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
|
|
||||||
|
|
||||||
if (as) {
|
|
||||||
if (p_enabled) {
|
|
||||||
as->play();
|
|
||||||
} else {
|
|
||||||
as->stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabler[ENABLER_PAUSE_PARTICLES]) {
|
|
||||||
GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
|
|
||||||
|
|
||||||
if (ps) {
|
|
||||||
ps->set_emitting(p_enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisibilityEnabler2D::_node_removed(Node *p_node) {
|
|
||||||
if (!visible) {
|
|
||||||
_change_node_state(p_node, true);
|
|
||||||
}
|
|
||||||
nodes.erase(p_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
TypedArray<String> VisibilityEnabler2D::get_configuration_warnings() const {
|
|
||||||
TypedArray<String> warnings = Node::get_configuration_warnings();
|
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) {
|
|
||||||
warnings.push_back(TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return warnings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisibilityEnabler2D::_bind_methods() {
|
void VisibilityEnabler2D::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler2D::set_enabler);
|
ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibilityEnabler2D::set_enable_mode);
|
||||||
ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler2D::is_enabler_enabled);
|
ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibilityEnabler2D::get_enable_mode);
|
||||||
ClassDB::bind_method(D_METHOD("_node_removed"), &VisibilityEnabler2D::_node_removed);
|
|
||||||
|
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS);
|
ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibilityEnabler2D::set_enable_node_path);
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES);
|
ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibilityEnabler2D::get_enable_node_path);
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_particles"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_PARTICLES);
|
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animated_sprites"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATED_SPRITES);
|
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "process_parent"), "set_enabler", "is_enabler_enabled", ENABLER_PARENT_PROCESS);
|
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "physics_process_parent"), "set_enabler", "is_enabler_enabled", ENABLER_PARENT_PHYSICS_PROCESS);
|
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS);
|
ADD_GROUP("Enabling", "enable_");
|
||||||
BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES);
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode");
|
||||||
BIND_ENUM_CONSTANT(ENABLER_PAUSE_PARTICLES);
|
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path");
|
||||||
BIND_ENUM_CONSTANT(ENABLER_PARENT_PROCESS);
|
|
||||||
BIND_ENUM_CONSTANT(ENABLER_PARENT_PHYSICS_PROCESS);
|
|
||||||
BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATED_SPRITES);
|
|
||||||
BIND_ENUM_CONSTANT(ENABLER_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisibilityEnabler2D::set_enabler(Enabler p_enabler, bool p_enable) {
|
BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT);
|
||||||
ERR_FAIL_INDEX(p_enabler, ENABLER_MAX);
|
BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS);
|
||||||
enabler[p_enabler] = p_enable;
|
BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED);
|
||||||
}
|
|
||||||
|
|
||||||
bool VisibilityEnabler2D::is_enabler_enabled(Enabler p_enabler) const {
|
|
||||||
ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false);
|
|
||||||
return enabler[p_enabler];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VisibilityEnabler2D::VisibilityEnabler2D() {
|
VisibilityEnabler2D::VisibilityEnabler2D() {
|
||||||
for (int i = 0; i < ENABLER_MAX; i++) {
|
|
||||||
enabler[i] = true;
|
|
||||||
}
|
|
||||||
enabler[ENABLER_PARENT_PROCESS] = false;
|
|
||||||
enabler[ENABLER_PARENT_PHYSICS_PROCESS] = false;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ class VisibilityNotifier2D : public Node2D {
|
|||||||
|
|
||||||
Rect2 rect;
|
Rect2 rect;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool on_screen = false;
|
||||||
|
void _visibility_enter();
|
||||||
|
void _visibility_exit();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend struct SpatialIndexer2D;
|
|
||||||
|
|
||||||
void _enter_viewport(Viewport *p_viewport);
|
|
||||||
void _exit_viewport(Viewport *p_viewport);
|
|
||||||
|
|
||||||
virtual void _screen_enter() {}
|
virtual void _screen_enter() {}
|
||||||
virtual void _screen_exit() {}
|
virtual void _screen_exit() {}
|
||||||
|
|
||||||
@@ -71,42 +71,35 @@ class VisibilityEnabler2D : public VisibilityNotifier2D {
|
|||||||
GDCLASS(VisibilityEnabler2D, VisibilityNotifier2D);
|
GDCLASS(VisibilityEnabler2D, VisibilityNotifier2D);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Enabler {
|
enum EnableMode {
|
||||||
ENABLER_PAUSE_ANIMATIONS,
|
ENABLE_MODE_INHERIT,
|
||||||
ENABLER_FREEZE_BODIES,
|
ENABLE_MODE_ALWAYS,
|
||||||
ENABLER_PAUSE_PARTICLES,
|
ENABLE_MODE_WHEN_PAUSED,
|
||||||
ENABLER_PARENT_PROCESS,
|
|
||||||
ENABLER_PARENT_PHYSICS_PROCESS,
|
|
||||||
ENABLER_PAUSE_ANIMATED_SPRITES,
|
|
||||||
ENABLER_MAX
|
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
ObjectID node_id;
|
||||||
virtual void _screen_enter() override;
|
virtual void _screen_enter() override;
|
||||||
virtual void _screen_exit() override;
|
virtual void _screen_exit() override;
|
||||||
|
|
||||||
bool visible = false;
|
EnableMode enable_mode = ENABLE_MODE_INHERIT;
|
||||||
|
NodePath enable_node_path = NodePath("..");
|
||||||
void _find_nodes(Node *p_node);
|
|
||||||
|
|
||||||
Map<Node *, Variant> nodes;
|
|
||||||
void _node_removed(Node *p_node);
|
|
||||||
bool enabler[ENABLER_MAX];
|
|
||||||
|
|
||||||
void _change_node_state(Node *p_node, bool p_enabled);
|
|
||||||
|
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
public:
|
void _update_enable_mode(bool p_enable);
|
||||||
void set_enabler(Enabler p_enabler, bool p_enable);
|
|
||||||
bool is_enabler_enabled(Enabler p_enabler) const;
|
|
||||||
|
|
||||||
TypedArray<String> get_configuration_warnings() const override;
|
public:
|
||||||
|
void set_enable_mode(EnableMode p_mode);
|
||||||
|
EnableMode get_enable_mode();
|
||||||
|
|
||||||
|
void set_enable_node_path(NodePath p_path);
|
||||||
|
NodePath get_enable_node_path();
|
||||||
|
|
||||||
VisibilityEnabler2D();
|
VisibilityEnabler2D();
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(VisibilityEnabler2D::Enabler);
|
VARIANT_ENUM_CAST(VisibilityEnabler2D::EnableMode);
|
||||||
|
|
||||||
#endif // VISIBILITY_NOTIFIER_2D_H
|
#endif // VISIBILITY_NOTIFIER_2D_H
|
||||||
|
|||||||
@@ -188,11 +188,6 @@ void Viewport::update_worlds() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect2 abstracted_rect = Rect2(Vector2(), get_visible_rect().size);
|
|
||||||
Rect2 xformed_rect = (global_canvas_transform * canvas_transform).affine_inverse().xform(abstracted_rect);
|
|
||||||
find_world_2d()->_update_viewport(this, xformed_rect);
|
|
||||||
find_world_2d()->_update();
|
|
||||||
|
|
||||||
find_world_3d()->_update(get_tree()->get_frame());
|
find_world_3d()->_update(get_tree()->get_frame());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,8 +436,6 @@ void Viewport::_notification(int p_what) {
|
|||||||
_update_listener();
|
_update_listener();
|
||||||
_update_listener_2d();
|
_update_listener_2d();
|
||||||
|
|
||||||
find_world_2d()->_register_viewport(this, Rect2());
|
|
||||||
|
|
||||||
add_to_group("_viewports");
|
add_to_group("_viewports");
|
||||||
if (get_tree()->is_debugging_collisions_hint()) {
|
if (get_tree()->is_debugging_collisions_hint()) {
|
||||||
//2D
|
//2D
|
||||||
@@ -499,9 +492,6 @@ void Viewport::_notification(int p_what) {
|
|||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_EXIT_TREE: {
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
_gui_cancel_tooltip();
|
_gui_cancel_tooltip();
|
||||||
if (world_2d.is_valid()) {
|
|
||||||
world_2d->_remove_viewport(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderingServer::get_singleton()->viewport_set_scenario(viewport, RID());
|
RenderingServer::get_singleton()->viewport_set_scenario(viewport, RID());
|
||||||
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
|
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
|
||||||
@@ -1156,7 +1146,6 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_inside_tree()) {
|
if (is_inside_tree()) {
|
||||||
find_world_2d()->_remove_viewport(this);
|
|
||||||
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
|
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1172,7 +1161,6 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
|
|||||||
if (is_inside_tree()) {
|
if (is_inside_tree()) {
|
||||||
current_canvas = find_world_2d()->get_canvas();
|
current_canvas = find_world_2d()->get_canvas();
|
||||||
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
|
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
|
||||||
find_world_2d()->_register_viewport(this, Rect2());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,284 +38,6 @@
|
|||||||
#include "servers/physics_server_2d.h"
|
#include "servers/physics_server_2d.h"
|
||||||
#include "servers/rendering_server.h"
|
#include "servers/rendering_server.h"
|
||||||
|
|
||||||
struct SpatialIndexer2D {
|
|
||||||
struct CellRef {
|
|
||||||
int ref = 0;
|
|
||||||
|
|
||||||
_FORCE_INLINE_ int inc() {
|
|
||||||
ref++;
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
_FORCE_INLINE_ int dec() {
|
|
||||||
ref--;
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CellKey {
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
int32_t x;
|
|
||||||
int32_t y;
|
|
||||||
};
|
|
||||||
uint64_t key = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator==(const CellKey &p_key) const { return key == p_key.key; }
|
|
||||||
_FORCE_INLINE_ bool operator<(const CellKey &p_key) const {
|
|
||||||
return key < p_key.key;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CellData {
|
|
||||||
Map<VisibilityNotifier2D *, CellRef> notifiers;
|
|
||||||
};
|
|
||||||
|
|
||||||
Map<CellKey, CellData> cells;
|
|
||||||
int cell_size;
|
|
||||||
|
|
||||||
Map<VisibilityNotifier2D *, Rect2> notifiers;
|
|
||||||
|
|
||||||
struct ViewportData {
|
|
||||||
Map<VisibilityNotifier2D *, uint64_t> notifiers;
|
|
||||||
Rect2 rect;
|
|
||||||
};
|
|
||||||
|
|
||||||
Map<Viewport *, ViewportData> viewports;
|
|
||||||
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
uint64_t pass = 0;
|
|
||||||
|
|
||||||
void _notifier_update_cells(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect, bool p_add) {
|
|
||||||
Point2i begin = p_rect.position;
|
|
||||||
begin /= cell_size;
|
|
||||||
Point2i end = p_rect.position + p_rect.size;
|
|
||||||
end /= cell_size;
|
|
||||||
for (int i = begin.x; i <= end.x; i++) {
|
|
||||||
for (int j = begin.y; j <= end.y; j++) {
|
|
||||||
CellKey ck;
|
|
||||||
ck.x = i;
|
|
||||||
ck.y = j;
|
|
||||||
Map<CellKey, CellData>::Element *E = cells.find(ck);
|
|
||||||
|
|
||||||
if (p_add) {
|
|
||||||
if (!E) {
|
|
||||||
E = cells.insert(ck, CellData());
|
|
||||||
}
|
|
||||||
E->get().notifiers[p_notifier].inc();
|
|
||||||
} else {
|
|
||||||
ERR_CONTINUE(!E);
|
|
||||||
if (E->get().notifiers[p_notifier].dec() == 0) {
|
|
||||||
E->get().notifiers.erase(p_notifier);
|
|
||||||
if (E->get().notifiers.is_empty()) {
|
|
||||||
cells.erase(E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _notifier_add(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) {
|
|
||||||
ERR_FAIL_COND(notifiers.has(p_notifier));
|
|
||||||
notifiers[p_notifier] = p_rect;
|
|
||||||
_notifier_update_cells(p_notifier, p_rect, true);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _notifier_update(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) {
|
|
||||||
Map<VisibilityNotifier2D *, Rect2>::Element *E = notifiers.find(p_notifier);
|
|
||||||
ERR_FAIL_COND(!E);
|
|
||||||
if (E->get() == p_rect) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_notifier_update_cells(p_notifier, p_rect, true);
|
|
||||||
_notifier_update_cells(p_notifier, E->get(), false);
|
|
||||||
E->get() = p_rect;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _notifier_remove(VisibilityNotifier2D *p_notifier) {
|
|
||||||
Map<VisibilityNotifier2D *, Rect2>::Element *E = notifiers.find(p_notifier);
|
|
||||||
ERR_FAIL_COND(!E);
|
|
||||||
_notifier_update_cells(p_notifier, E->get(), false);
|
|
||||||
notifiers.erase(p_notifier);
|
|
||||||
|
|
||||||
List<Viewport *> removed;
|
|
||||||
for (Map<Viewport *, ViewportData>::Element *F = viewports.front(); F; F = F->next()) {
|
|
||||||
Map<VisibilityNotifier2D *, uint64_t>::Element *G = F->get().notifiers.find(p_notifier);
|
|
||||||
|
|
||||||
if (G) {
|
|
||||||
F->get().notifiers.erase(G);
|
|
||||||
removed.push_back(F->key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!removed.is_empty()) {
|
|
||||||
p_notifier->_exit_viewport(removed.front()->get());
|
|
||||||
removed.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _add_viewport(Viewport *p_viewport, const Rect2 &p_rect) {
|
|
||||||
ERR_FAIL_COND(viewports.has(p_viewport));
|
|
||||||
ViewportData vd;
|
|
||||||
vd.rect = p_rect;
|
|
||||||
viewports[p_viewport] = vd;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _update_viewport(Viewport *p_viewport, const Rect2 &p_rect) {
|
|
||||||
Map<Viewport *, ViewportData>::Element *E = viewports.find(p_viewport);
|
|
||||||
ERR_FAIL_COND(!E);
|
|
||||||
if (E->get().rect == p_rect) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
E->get().rect = p_rect;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _remove_viewport(Viewport *p_viewport) {
|
|
||||||
ERR_FAIL_COND(!viewports.has(p_viewport));
|
|
||||||
List<VisibilityNotifier2D *> removed;
|
|
||||||
for (Map<VisibilityNotifier2D *, uint64_t>::Element *E = viewports[p_viewport].notifiers.front(); E; E = E->next()) {
|
|
||||||
removed.push_back(E->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!removed.is_empty()) {
|
|
||||||
removed.front()->get()->_exit_viewport(p_viewport);
|
|
||||||
removed.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
viewports.erase(p_viewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _update() {
|
|
||||||
if (!changed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map<Viewport *, ViewportData>::Element *E = viewports.front(); E; E = E->next()) {
|
|
||||||
Point2i begin = E->get().rect.position;
|
|
||||||
begin /= cell_size;
|
|
||||||
Point2i end = E->get().rect.position + E->get().rect.size;
|
|
||||||
end /= cell_size;
|
|
||||||
pass++;
|
|
||||||
List<VisibilityNotifier2D *> added;
|
|
||||||
List<VisibilityNotifier2D *> removed;
|
|
||||||
|
|
||||||
uint64_t visible_cells = (uint64_t)(end.x - begin.x) * (uint64_t)(end.y - begin.y);
|
|
||||||
|
|
||||||
if (visible_cells > 10000) {
|
|
||||||
//well you zoomed out a lot, it's your problem. To avoid freezing in the for loops below, we'll manually check cell by cell
|
|
||||||
|
|
||||||
for (Map<CellKey, CellData>::Element *F = cells.front(); F; F = F->next()) {
|
|
||||||
const CellKey &ck = F->key();
|
|
||||||
|
|
||||||
if (ck.x < begin.x || ck.x > end.x) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ck.y < begin.y || ck.y > end.y) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//notifiers in cell
|
|
||||||
for (Map<VisibilityNotifier2D *, CellRef>::Element *G = F->get().notifiers.front(); G; G = G->next()) {
|
|
||||||
Map<VisibilityNotifier2D *, uint64_t>::Element *H = E->get().notifiers.find(G->key());
|
|
||||||
if (!H) {
|
|
||||||
H = E->get().notifiers.insert(G->key(), pass);
|
|
||||||
added.push_back(G->key());
|
|
||||||
} else {
|
|
||||||
H->get() = pass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//check cells in grid fashion
|
|
||||||
for (int i = begin.x; i <= end.x; i++) {
|
|
||||||
for (int j = begin.y; j <= end.y; j++) {
|
|
||||||
CellKey ck;
|
|
||||||
ck.x = i;
|
|
||||||
ck.y = j;
|
|
||||||
|
|
||||||
Map<CellKey, CellData>::Element *F = cells.find(ck);
|
|
||||||
if (!F) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//notifiers in cell
|
|
||||||
for (Map<VisibilityNotifier2D *, CellRef>::Element *G = F->get().notifiers.front(); G; G = G->next()) {
|
|
||||||
Map<VisibilityNotifier2D *, uint64_t>::Element *H = E->get().notifiers.find(G->key());
|
|
||||||
if (!H) {
|
|
||||||
H = E->get().notifiers.insert(G->key(), pass);
|
|
||||||
added.push_back(G->key());
|
|
||||||
} else {
|
|
||||||
H->get() = pass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map<VisibilityNotifier2D *, uint64_t>::Element *F = E->get().notifiers.front(); F; F = F->next()) {
|
|
||||||
if (F->get() != pass) {
|
|
||||||
removed.push_back(F->key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!added.is_empty()) {
|
|
||||||
added.front()->get()->_enter_viewport(E->key());
|
|
||||||
added.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!removed.is_empty()) {
|
|
||||||
E->get().notifiers.erase(removed.front()->get());
|
|
||||||
removed.front()->get()->_exit_viewport(E->key());
|
|
||||||
removed.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SpatialIndexer2D() {
|
|
||||||
cell_size = GLOBAL_DEF("world/2d/cell_size", 100);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void World2D::_register_viewport(Viewport *p_viewport, const Rect2 &p_rect) {
|
|
||||||
indexer->_add_viewport(p_viewport, p_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World2D::_update_viewport(Viewport *p_viewport, const Rect2 &p_rect) {
|
|
||||||
indexer->_update_viewport(p_viewport, p_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World2D::_remove_viewport(Viewport *p_viewport) {
|
|
||||||
indexer->_remove_viewport(p_viewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World2D::_register_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) {
|
|
||||||
indexer->_notifier_add(p_notifier, p_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World2D::_update_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) {
|
|
||||||
indexer->_notifier_update(p_notifier, p_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World2D::_remove_notifier(VisibilityNotifier2D *p_notifier) {
|
|
||||||
indexer->_notifier_remove(p_notifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World2D::_update() {
|
|
||||||
indexer->_update();
|
|
||||||
}
|
|
||||||
|
|
||||||
RID World2D::get_canvas() const {
|
RID World2D::get_canvas() const {
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
@@ -328,12 +50,6 @@ RID World2D::get_navigation_map() const {
|
|||||||
return navigation_map;
|
return navigation_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World2D::get_viewport_list(List<Viewport *> *r_viewports) {
|
|
||||||
for (Map<Viewport *, SpatialIndexer2D::ViewportData>::Element *E = indexer->viewports.front(); E; E = E->next()) {
|
|
||||||
r_viewports->push_back(E->key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World2D::_bind_methods() {
|
void World2D::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_canvas"), &World2D::get_canvas);
|
ClassDB::bind_method(D_METHOD("get_canvas"), &World2D::get_canvas);
|
||||||
ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space);
|
ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space);
|
||||||
@@ -369,13 +85,10 @@ World2D::World2D() {
|
|||||||
NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
|
NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
|
||||||
NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10));
|
NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10));
|
||||||
NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5));
|
NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5));
|
||||||
|
|
||||||
indexer = memnew(SpatialIndexer2D);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
World2D::~World2D() {
|
World2D::~World2D() {
|
||||||
RenderingServer::get_singleton()->free(canvas);
|
RenderingServer::get_singleton()->free(canvas);
|
||||||
PhysicsServer2D::get_singleton()->free(space);
|
PhysicsServer2D::get_singleton()->free(space);
|
||||||
NavigationServer2D::get_singleton()->free(navigation_map);
|
NavigationServer2D::get_singleton()->free(navigation_map);
|
||||||
memdelete(indexer);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,23 +46,15 @@ class World2D : public Resource {
|
|||||||
RID space;
|
RID space;
|
||||||
RID navigation_map;
|
RID navigation_map;
|
||||||
|
|
||||||
SpatialIndexer2D *indexer;
|
Set<Viewport *> viewports;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
friend class Viewport;
|
friend class Viewport;
|
||||||
friend class VisibilityNotifier2D;
|
|
||||||
|
|
||||||
void _register_viewport(Viewport *p_viewport, const Rect2 &p_rect);
|
void _register_viewport(Viewport *p_viewport);
|
||||||
void _update_viewport(Viewport *p_viewport, const Rect2 &p_rect);
|
|
||||||
void _remove_viewport(Viewport *p_viewport);
|
void _remove_viewport(Viewport *p_viewport);
|
||||||
|
|
||||||
void _register_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect);
|
|
||||||
void _update_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect);
|
|
||||||
void _remove_notifier(VisibilityNotifier2D *p_notifier);
|
|
||||||
|
|
||||||
void _update();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RID get_canvas() const;
|
RID get_canvas() const;
|
||||||
RID get_space() const;
|
RID get_space() const;
|
||||||
@@ -70,7 +62,7 @@ public:
|
|||||||
|
|
||||||
PhysicsDirectSpaceState2D *get_direct_space_state();
|
PhysicsDirectSpaceState2D *get_direct_space_state();
|
||||||
|
|
||||||
void get_viewport_list(List<Viewport *> *r_viewports);
|
_FORCE_INLINE_ const Set<Viewport *> &get_viewports() { return viewports; }
|
||||||
|
|
||||||
World2D();
|
World2D();
|
||||||
~World2D();
|
~World2D();
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<Rende
|
|||||||
} while (ysort_owner && ysort_owner->sort_y);
|
} while (ysort_owner && ysort_owner->sort_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from) {
|
void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) {
|
||||||
if (ci->copy_back_buffer) {
|
if (ci->copy_back_buffer) {
|
||||||
ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
|
ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
|
||||||
}
|
}
|
||||||
@@ -173,12 +173,14 @@ void _attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
|
||||||
|
//something to draw?
|
||||||
|
|
||||||
if (ci->update_when_visible) {
|
if (ci->update_when_visible) {
|
||||||
RenderingServerDefault::redraw_request();
|
RenderingServerDefault::redraw_request();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ci->commands != nullptr && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
|
if (ci->commands != nullptr) {
|
||||||
//something to draw?
|
|
||||||
ci->final_transform = xform;
|
ci->final_transform = xform;
|
||||||
ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
|
ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
|
||||||
ci->global_rect_cache = global_rect;
|
ci->global_rect_cache = global_rect;
|
||||||
@@ -200,6 +202,16 @@ void _attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCu
|
|||||||
|
|
||||||
ci->next = nullptr;
|
ci->next = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ci->visibility_notifier) {
|
||||||
|
if (!ci->visibility_notifier->visible_element.in_list()) {
|
||||||
|
visibility_notifier_list.add(&ci->visibility_notifier->visible_element);
|
||||||
|
ci->visibility_notifier->just_visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort) {
|
void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort) {
|
||||||
@@ -215,6 +227,13 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rect2 rect = ci->get_rect();
|
Rect2 rect = ci->get_rect();
|
||||||
|
|
||||||
|
if (ci->visibility_notifier) {
|
||||||
|
if (ci->visibility_notifier->area.size != Vector2()) {
|
||||||
|
rect = rect.merge(ci->visibility_notifier->area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Transform2D xform = ci->xform;
|
Transform2D xform = ci->xform;
|
||||||
if (snapping_2d_transforms_to_pixel) {
|
if (snapping_2d_transforms_to_pixel) {
|
||||||
xform.elements[2] = xform.elements[2].floor();
|
xform.elements[2] = xform.elements[2].floor();
|
||||||
@@ -289,7 +308,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||||||
canvas_group_from = z_last_list[zidx];
|
canvas_group_from = z_last_list[zidx];
|
||||||
}
|
}
|
||||||
|
|
||||||
_attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
|
_attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RendererCanvasRender::Item *canvas_group_from = nullptr;
|
RendererCanvasRender::Item *canvas_group_from = nullptr;
|
||||||
@@ -305,7 +324,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||||||
}
|
}
|
||||||
_cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true);
|
_cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true);
|
||||||
}
|
}
|
||||||
_attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
|
_attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
|
||||||
for (int i = 0; i < child_item_count; i++) {
|
for (int i = 0; i < child_item_count; i++) {
|
||||||
if (child_items[i]->behind || use_canvas_group) {
|
if (child_items[i]->behind || use_canvas_group) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1095,6 +1114,26 @@ void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_
|
|||||||
canvas_item->use_parent_material = p_enable;
|
canvas_item->use_parent_material = p_enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) {
|
||||||
|
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||||
|
ERR_FAIL_COND(!canvas_item);
|
||||||
|
|
||||||
|
if (p_enable) {
|
||||||
|
if (!canvas_item->visibility_notifier) {
|
||||||
|
canvas_item->visibility_notifier = visibility_notifier_allocator.alloc();
|
||||||
|
}
|
||||||
|
canvas_item->visibility_notifier->area = p_area;
|
||||||
|
canvas_item->visibility_notifier->enter_callable = p_enter_callable;
|
||||||
|
canvas_item->visibility_notifier->exit_callable = p_exit_callable;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (canvas_item->visibility_notifier) {
|
||||||
|
visibility_notifier_allocator.free(canvas_item->visibility_notifier);
|
||||||
|
canvas_item->visibility_notifier = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
|
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
|
||||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||||
ERR_FAIL_COND(!canvas_item);
|
ERR_FAIL_COND(!canvas_item);
|
||||||
@@ -1477,6 +1516,44 @@ void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::
|
|||||||
ci->texture_repeat = p_repeat;
|
ci->texture_repeat = p_repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RendererCanvasCull::update_visibility_notifiers() {
|
||||||
|
SelfList<Item::VisibilityNotifierData> *E = visibility_notifier_list.first();
|
||||||
|
while (E) {
|
||||||
|
SelfList<Item::VisibilityNotifierData> *N = E->next();
|
||||||
|
|
||||||
|
Item::VisibilityNotifierData *visibility_notifier = E->self();
|
||||||
|
if (visibility_notifier->just_visible) {
|
||||||
|
visibility_notifier->just_visible = false;
|
||||||
|
|
||||||
|
if (!visibility_notifier->enter_callable.is_null()) {
|
||||||
|
if (RSG::threaded) {
|
||||||
|
visibility_notifier->enter_callable.call_deferred(nullptr, 0);
|
||||||
|
} else {
|
||||||
|
Callable::CallError ce;
|
||||||
|
Variant ret;
|
||||||
|
visibility_notifier->enter_callable.call(nullptr, 0, ret, ce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
|
||||||
|
visibility_notifier_list.remove(E);
|
||||||
|
|
||||||
|
if (!visibility_notifier->exit_callable.is_null()) {
|
||||||
|
if (RSG::threaded) {
|
||||||
|
visibility_notifier->exit_callable.call_deferred(nullptr, 0);
|
||||||
|
} else {
|
||||||
|
Callable::CallError ce;
|
||||||
|
Variant ret;
|
||||||
|
visibility_notifier->exit_callable.call(nullptr, 0, ret, ce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
E = N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool RendererCanvasCull::free(RID p_rid) {
|
bool RendererCanvasCull::free(RID p_rid) {
|
||||||
if (canvas_owner.owns(p_rid)) {
|
if (canvas_owner.owns(p_rid)) {
|
||||||
Canvas *canvas = canvas_owner.getornull(p_rid);
|
Canvas *canvas = canvas_owner.getornull(p_rid);
|
||||||
@@ -1531,6 +1608,10 @@ bool RendererCanvasCull::free(RID p_rid) {
|
|||||||
canvas_item->child_items[i]->parent = RID();
|
canvas_item->child_items[i]->parent = RID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (canvas_item->visibility_notifier != nullptr) {
|
||||||
|
visibility_notifier_allocator.free(canvas_item->visibility_notifier);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (canvas_item->material) {
|
if (canvas_item->material) {
|
||||||
canvas_item->material->owners.erase(canvas_item);
|
canvas_item->material->owners.erase(canvas_item);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#ifndef RENDERING_SERVER_CANVAS_CULL_H
|
#ifndef RENDERING_SERVER_CANVAS_CULL_H
|
||||||
#define RENDERING_SERVER_CANVAS_CULL_H
|
#define RENDERING_SERVER_CANVAS_CULL_H
|
||||||
|
|
||||||
|
#include "core/templates/paged_allocator.h"
|
||||||
#include "renderer_compositor.h"
|
#include "renderer_compositor.h"
|
||||||
#include "renderer_viewport.h"
|
#include "renderer_viewport.h"
|
||||||
|
|
||||||
@@ -55,6 +56,20 @@ public:
|
|||||||
|
|
||||||
Vector<Item *> child_items;
|
Vector<Item *> child_items;
|
||||||
|
|
||||||
|
struct VisibilityNotifierData {
|
||||||
|
Rect2 area;
|
||||||
|
Callable enter_callable;
|
||||||
|
Callable exit_callable;
|
||||||
|
bool just_visible = false;
|
||||||
|
uint64_t visible_in_frame = 0;
|
||||||
|
SelfList<VisibilityNotifierData> visible_element;
|
||||||
|
VisibilityNotifierData() :
|
||||||
|
visible_element(this) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VisibilityNotifierData *visibility_notifier = nullptr;
|
||||||
|
|
||||||
Item() {
|
Item() {
|
||||||
children_order_dirty = true;
|
children_order_dirty = true;
|
||||||
E = nullptr;
|
E = nullptr;
|
||||||
@@ -156,6 +171,11 @@ public:
|
|||||||
bool sdf_used = false;
|
bool sdf_used = false;
|
||||||
bool snapping_2d_transforms_to_pixel = false;
|
bool snapping_2d_transforms_to_pixel = false;
|
||||||
|
|
||||||
|
PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator;
|
||||||
|
SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
|
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
|
||||||
void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort);
|
void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort);
|
||||||
@@ -224,6 +244,8 @@ public:
|
|||||||
|
|
||||||
void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
|
void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
|
||||||
|
|
||||||
|
void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable);
|
||||||
|
|
||||||
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
|
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
|
||||||
|
|
||||||
RID canvas_light_allocate();
|
RID canvas_light_allocate();
|
||||||
@@ -283,6 +305,8 @@ public:
|
|||||||
void canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter);
|
void canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter);
|
||||||
void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat);
|
void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat);
|
||||||
|
|
||||||
|
void update_visibility_notifiers();
|
||||||
|
|
||||||
bool free(RID p_rid);
|
bool free(RID p_rid);
|
||||||
RendererCanvasCull();
|
RendererCanvasCull();
|
||||||
~RendererCanvasCull();
|
~RendererCanvasCull();
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
|
|||||||
_draw_margins();
|
_draw_margins();
|
||||||
RSG::rasterizer->end_frame(p_swap_buffers);
|
RSG::rasterizer->end_frame(p_swap_buffers);
|
||||||
|
|
||||||
|
RSG::canvas->update_visibility_notifiers();
|
||||||
|
|
||||||
while (frame_drawn_callbacks.front()) {
|
while (frame_drawn_callbacks.front()) {
|
||||||
Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object);
|
Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object);
|
||||||
if (obj) {
|
if (obj) {
|
||||||
@@ -396,6 +398,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
|
|||||||
server_thread = 0;
|
server_thread = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RSG::threaded = p_create_thread;
|
||||||
RSG::canvas = memnew(RendererCanvasCull);
|
RSG::canvas = memnew(RendererCanvasCull);
|
||||||
RSG::viewport = memnew(RendererViewport);
|
RSG::viewport = memnew(RendererViewport);
|
||||||
RendererSceneCull *sr = memnew(RendererSceneCull);
|
RendererSceneCull *sr = memnew(RendererSceneCull);
|
||||||
|
|||||||
@@ -820,6 +820,8 @@ public:
|
|||||||
|
|
||||||
FUNC2(canvas_item_set_use_parent_material, RID, bool)
|
FUNC2(canvas_item_set_use_parent_material, RID, bool)
|
||||||
|
|
||||||
|
FUNC5(canvas_item_set_visibility_notifier, RID, bool, const Rect2 &, const Callable &, const Callable &)
|
||||||
|
|
||||||
FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
|
FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
|
||||||
|
|
||||||
FUNCRIDSPLIT(canvas_light)
|
FUNCRIDSPLIT(canvas_light)
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "rendering_server_globals.h"
|
#include "rendering_server_globals.h"
|
||||||
|
|
||||||
|
bool RenderingServerGlobals::threaded = false;
|
||||||
|
|
||||||
RendererStorage *RenderingServerGlobals::storage = nullptr;
|
RendererStorage *RenderingServerGlobals::storage = nullptr;
|
||||||
RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr;
|
RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr;
|
||||||
RendererCompositor *RenderingServerGlobals::rasterizer = nullptr;
|
RendererCompositor *RenderingServerGlobals::rasterizer = nullptr;
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ class RendererScene;
|
|||||||
|
|
||||||
class RenderingServerGlobals {
|
class RenderingServerGlobals {
|
||||||
public:
|
public:
|
||||||
|
static bool threaded;
|
||||||
|
|
||||||
static RendererStorage *storage;
|
static RendererStorage *storage;
|
||||||
static RendererCanvasRender *canvas_render;
|
static RendererCanvasRender *canvas_render;
|
||||||
static RendererCompositor *rasterizer;
|
static RendererCompositor *rasterizer;
|
||||||
|
|||||||
@@ -1301,6 +1301,8 @@ public:
|
|||||||
|
|
||||||
virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
|
virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
|
||||||
|
|
||||||
|
virtual void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0;
|
||||||
|
|
||||||
enum CanvasGroupMode {
|
enum CanvasGroupMode {
|
||||||
CANVAS_GROUP_MODE_DISABLED,
|
CANVAS_GROUP_MODE_DISABLED,
|
||||||
CANVAS_GROUP_MODE_OPAQUE,
|
CANVAS_GROUP_MODE_OPAQUE,
|
||||||
|
|||||||
Reference in New Issue
Block a user