Merge pull request #67043 from clayjohn/clip_children
Improve behaviour of clip_children by clipping to parent alpha value but still retaining parent color
This commit is contained in:
commit
e1caa8797b
11 changed files with 135 additions and 31 deletions
|
@ -535,7 +535,7 @@
|
|||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="clip_children" type="bool" setter="set_clip_children" getter="is_clipping_children" default="false">
|
||||
<member name="clip_children" type="int" setter="set_clip_children_mode" getter="get_clip_children_mode" enum="CanvasItem.ClipChildrenMode" default="0">
|
||||
Allows the current node to clip children nodes, essentially acting as a mask.
|
||||
</member>
|
||||
<member name="light_mask" type="int" setter="set_light_mask" getter="get_light_mask" default="1">
|
||||
|
@ -653,5 +653,13 @@
|
|||
<constant name="TEXTURE_REPEAT_MAX" value="4" enum="TextureRepeat">
|
||||
Represents the size of the [enum TextureRepeat] enum.
|
||||
</constant>
|
||||
<constant name="CLIP_CHILDREN_DISABLED" value="0" enum="ClipChildrenMode">
|
||||
</constant>
|
||||
<constant name="CLIP_CHILDREN_ONLY" value="1" enum="ClipChildrenMode">
|
||||
</constant>
|
||||
<constant name="CLIP_CHILDREN_AND_DRAW" value="2" enum="ClipChildrenMode">
|
||||
</constant>
|
||||
<constant name="CLIP_CHILDREN_MAX" value="3" enum="ClipChildrenMode">
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -4576,9 +4576,11 @@
|
|||
</constant>
|
||||
<constant name="CANVAS_GROUP_MODE_DISABLED" value="0" enum="CanvasGroupMode">
|
||||
</constant>
|
||||
<constant name="CANVAS_GROUP_MODE_OPAQUE" value="1" enum="CanvasGroupMode">
|
||||
<constant name="CANVAS_GROUP_MODE_CLIP_ONLY" value="1" enum="CanvasGroupMode">
|
||||
</constant>
|
||||
<constant name="CANVAS_GROUP_MODE_TRANSPARENT" value="2" enum="CanvasGroupMode">
|
||||
<constant name="CANVAS_GROUP_MODE_CLIP_AND_DRAW" value="2" enum="CanvasGroupMode">
|
||||
</constant>
|
||||
<constant name="CANVAS_GROUP_MODE_TRANSPARENT" value="3" enum="CanvasGroupMode">
|
||||
</constant>
|
||||
<constant name="CANVAS_LIGHT_MODE_POINT" value="0" enum="CanvasLightMode">
|
||||
</constant>
|
||||
|
|
|
@ -436,10 +436,12 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
|||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, false);
|
||||
item_count = 0;
|
||||
|
||||
Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
|
||||
|
||||
if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) {
|
||||
if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
|
||||
Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
|
||||
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false);
|
||||
if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
|
||||
items[item_count++] = ci->canvas_group_owner;
|
||||
}
|
||||
} else if (!backbuffer_cleared) {
|
||||
texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
|
||||
backbuffer_cleared = true;
|
||||
|
@ -547,9 +549,18 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
|
|||
}
|
||||
|
||||
RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
|
||||
|
||||
if (material.is_null() && ci->canvas_group != nullptr) {
|
||||
material = default_canvas_group_material;
|
||||
if (ci->canvas_group != nullptr) {
|
||||
if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
|
||||
if (!p_to_backbuffer) {
|
||||
material = default_clip_children_material;
|
||||
}
|
||||
} else {
|
||||
if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_ONLY) {
|
||||
material = default_clip_children_material;
|
||||
} else {
|
||||
material = default_canvas_group_material;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLES3::CanvasShaderData *shader_data_cache = nullptr;
|
||||
|
@ -2078,6 +2089,26 @@ void fragment() {
|
|||
material_storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
|
||||
}
|
||||
|
||||
{
|
||||
default_clip_children_shader = material_storage->shader_allocate();
|
||||
material_storage->shader_initialize(default_clip_children_shader);
|
||||
|
||||
material_storage->shader_set_code(default_clip_children_shader, R"(
|
||||
// Default clip children shader.
|
||||
|
||||
shader_type canvas_item;
|
||||
|
||||
void fragment() {
|
||||
vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
|
||||
COLOR.rgb = c.rgb;
|
||||
}
|
||||
)");
|
||||
default_clip_children_material = material_storage->material_allocate();
|
||||
material_storage->material_initialize(default_clip_children_material);
|
||||
|
||||
material_storage->material_set_shader(default_clip_children_material, default_clip_children_shader);
|
||||
}
|
||||
|
||||
default_canvas_texture = texture_storage->canvas_texture_allocate();
|
||||
texture_storage->canvas_texture_initialize(default_canvas_texture);
|
||||
|
||||
|
@ -2090,6 +2121,8 @@ RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
|
|||
material_storage->shaders.canvas_shader.version_free(data.canvas_shader_default_version);
|
||||
material_storage->material_free(default_canvas_group_material);
|
||||
material_storage->shader_free(default_canvas_group_shader);
|
||||
material_storage->material_free(default_clip_children_material);
|
||||
material_storage->shader_free(default_clip_children_shader);
|
||||
singleton = nullptr;
|
||||
|
||||
glDeleteBuffers(1, &data.canvas_quad_vertices);
|
||||
|
|
|
@ -284,6 +284,8 @@ public:
|
|||
RID default_canvas_texture;
|
||||
RID default_canvas_group_material;
|
||||
RID default_canvas_group_shader;
|
||||
RID default_clip_children_material;
|
||||
RID default_clip_children_shader;
|
||||
|
||||
typedef void Texture;
|
||||
|
||||
|
|
|
@ -986,8 +986,8 @@ void CanvasItem::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
|
||||
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children);
|
||||
ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children);
|
||||
ClassDB::bind_method(D_METHOD("set_clip_children_mode", "mode"), &CanvasItem::set_clip_children_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_clip_children_mode"), &CanvasItem::get_clip_children_mode);
|
||||
|
||||
GDVIRTUAL_BIND(_draw);
|
||||
|
||||
|
@ -997,7 +997,7 @@ void CanvasItem::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "clip_children", PROPERTY_HINT_ENUM, "Disabled,Clip Only, Clip + Draw"), "set_clip_children_mode", "get_clip_children_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
|
||||
|
||||
ADD_GROUP("Texture", "texture_");
|
||||
|
@ -1035,6 +1035,11 @@ void CanvasItem::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
|
||||
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
|
||||
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
|
||||
|
||||
BIND_ENUM_CONSTANT(CLIP_CHILDREN_DISABLED);
|
||||
BIND_ENUM_CONSTANT(CLIP_CHILDREN_ONLY);
|
||||
BIND_ENUM_CONSTANT(CLIP_CHILDREN_AND_DRAW);
|
||||
BIND_ENUM_CONSTANT(CLIP_CHILDREN_MAX);
|
||||
}
|
||||
|
||||
Transform2D CanvasItem::get_canvas_transform() const {
|
||||
|
@ -1185,20 +1190,23 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
|
|||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
void CanvasItem::set_clip_children(bool p_enabled) {
|
||||
if (clip_children == p_enabled) {
|
||||
void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
|
||||
ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX);
|
||||
|
||||
if (clip_children_mode == p_clip_mode) {
|
||||
return;
|
||||
}
|
||||
clip_children = p_enabled;
|
||||
clip_children_mode = p_clip_mode;
|
||||
|
||||
if (Object::cast_to<CanvasGroup>(this) != nullptr) {
|
||||
//avoid accidental bugs, make this not work on CanvasGroup
|
||||
return;
|
||||
}
|
||||
RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED);
|
||||
|
||||
RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
|
||||
}
|
||||
bool CanvasItem::is_clipping_children() const {
|
||||
return clip_children;
|
||||
CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
|
||||
return clip_children_mode;
|
||||
}
|
||||
|
||||
CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
|
||||
|
|
|
@ -66,8 +66,16 @@ public:
|
|||
TEXTURE_REPEAT_MAX,
|
||||
};
|
||||
|
||||
enum ClipChildrenMode {
|
||||
CLIP_CHILDREN_DISABLED,
|
||||
CLIP_CHILDREN_ONLY,
|
||||
CLIP_CHILDREN_AND_DRAW,
|
||||
CLIP_CHILDREN_MAX,
|
||||
};
|
||||
|
||||
private:
|
||||
mutable SelfList<Node> xform_change;
|
||||
mutable SelfList<Node>
|
||||
xform_change;
|
||||
|
||||
RID canvas_item;
|
||||
StringName canvas_group;
|
||||
|
@ -85,7 +93,6 @@ private:
|
|||
Window *window = nullptr;
|
||||
bool visible = true;
|
||||
bool parent_visible_in_tree = false;
|
||||
bool clip_children = false;
|
||||
bool pending_update = false;
|
||||
bool top_level = false;
|
||||
bool drawing = false;
|
||||
|
@ -95,6 +102,8 @@ private:
|
|||
bool notify_local_transform = false;
|
||||
bool notify_transform = false;
|
||||
|
||||
ClipChildrenMode clip_children_mode = CLIP_CHILDREN_DISABLED;
|
||||
|
||||
RS::CanvasItemTextureFilter texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
|
||||
RS::CanvasItemTextureRepeat texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
|
||||
TextureFilter texture_filter = TEXTURE_FILTER_PARENT_NODE;
|
||||
|
@ -202,8 +211,8 @@ public:
|
|||
void queue_redraw();
|
||||
void move_to_front();
|
||||
|
||||
void set_clip_children(bool p_enabled);
|
||||
bool is_clipping_children() const;
|
||||
void set_clip_children_mode(ClipChildrenMode p_clip_mode);
|
||||
ClipChildrenMode get_clip_children_mode() const;
|
||||
|
||||
virtual void set_light_mask(int p_light_mask);
|
||||
int get_light_mask() const;
|
||||
|
@ -326,6 +335,7 @@ public:
|
|||
|
||||
VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
|
||||
VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
|
||||
VARIANT_ENUM_CAST(CanvasItem::ClipChildrenMode)
|
||||
|
||||
class CanvasTexture : public Texture2D {
|
||||
GDCLASS(CanvasTexture, Texture2D);
|
||||
|
|
|
@ -357,8 +357,8 @@ void CopyEffects::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, cons
|
|||
copy.push_constant.flags |= COPY_FLAG_ALPHA_TO_ONE;
|
||||
}
|
||||
|
||||
copy.push_constant.section[0] = 0;
|
||||
copy.push_constant.section[1] = 0;
|
||||
copy.push_constant.section[0] = p_rect.position.x;
|
||||
copy.push_constant.section[1] = p_rect.position.y;
|
||||
copy.push_constant.section[2] = p_rect.size.width;
|
||||
copy.push_constant.section[3] = p_rect.size.height;
|
||||
copy.push_constant.target[0] = p_rect.position.x;
|
||||
|
|
|
@ -1111,8 +1111,20 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
|
|||
|
||||
RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
|
||||
|
||||
if (material.is_null() && ci->canvas_group != nullptr) {
|
||||
material = default_canvas_group_material;
|
||||
if (ci->canvas_group != nullptr) {
|
||||
if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
|
||||
if (!p_to_backbuffer) {
|
||||
material = default_clip_children_material;
|
||||
}
|
||||
} else {
|
||||
if (material.is_null()) {
|
||||
if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_ONLY) {
|
||||
material = default_clip_children_material;
|
||||
} else {
|
||||
material = default_canvas_group_material;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (material != prev_material) {
|
||||
|
@ -1437,10 +1449,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
|
||||
item_count = 0;
|
||||
|
||||
Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
|
||||
|
||||
if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) {
|
||||
if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
|
||||
Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
|
||||
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false);
|
||||
if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
|
||||
items[item_count++] = ci->canvas_group_owner;
|
||||
}
|
||||
} else if (!backbuffer_cleared) {
|
||||
texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
|
||||
backbuffer_cleared = true;
|
||||
|
@ -2738,6 +2752,26 @@ void fragment() {
|
|||
material_storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
|
||||
}
|
||||
|
||||
{
|
||||
default_clip_children_shader = material_storage->shader_allocate();
|
||||
material_storage->shader_initialize(default_clip_children_shader);
|
||||
|
||||
material_storage->shader_set_code(default_clip_children_shader, R"(
|
||||
// Default clip children shader.
|
||||
|
||||
shader_type canvas_item;
|
||||
|
||||
void fragment() {
|
||||
vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
|
||||
COLOR.rgb = c.rgb;
|
||||
}
|
||||
)");
|
||||
default_clip_children_material = material_storage->material_allocate();
|
||||
material_storage->material_initialize(default_clip_children_material);
|
||||
|
||||
material_storage->material_set_shader(default_clip_children_material, default_clip_children_shader);
|
||||
}
|
||||
|
||||
static_assert(sizeof(PushConstant) == 128);
|
||||
}
|
||||
|
||||
|
@ -2789,6 +2823,9 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() {
|
|||
material_storage->material_free(default_canvas_group_material);
|
||||
material_storage->shader_free(default_canvas_group_shader);
|
||||
|
||||
material_storage->material_free(default_clip_children_material);
|
||||
material_storage->shader_free(default_clip_children_shader);
|
||||
|
||||
{
|
||||
if (state.canvas_state_buffer.is_valid()) {
|
||||
RD::get_singleton()->free(state.canvas_state_buffer);
|
||||
|
|
|
@ -421,6 +421,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|||
|
||||
RID default_canvas_group_shader;
|
||||
RID default_canvas_group_material;
|
||||
RID default_clip_children_material;
|
||||
RID default_clip_children_shader;
|
||||
|
||||
RS::CanvasItemTextureFilter default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
|
||||
RS::CanvasItemTextureRepeat default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
|
||||
|
|
|
@ -2636,7 +2636,8 @@ void RenderingServer::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MAX);
|
||||
|
||||
BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_DISABLED);
|
||||
BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_OPAQUE);
|
||||
BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_CLIP_ONLY);
|
||||
BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_CLIP_AND_DRAW);
|
||||
BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_TRANSPARENT);
|
||||
|
||||
/* CANVAS LIGHT */
|
||||
|
|
|
@ -1367,7 +1367,8 @@ public:
|
|||
|
||||
enum CanvasGroupMode {
|
||||
CANVAS_GROUP_MODE_DISABLED,
|
||||
CANVAS_GROUP_MODE_OPAQUE,
|
||||
CANVAS_GROUP_MODE_CLIP_ONLY,
|
||||
CANVAS_GROUP_MODE_CLIP_AND_DRAW,
|
||||
CANVAS_GROUP_MODE_TRANSPARENT,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue