diff options
Diffstat (limited to 'scene')
68 files changed, 762 insertions, 1016 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 0b20b781f0..20ec06f033 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -102,7 +102,7 @@ Rect2 AnimatedSprite::_get_rect() const { void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture> &p_frame, int p_at_pos) { Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND(!E); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) E->get().frames.insert(p_at_pos, p_frame); @@ -114,7 +114,7 @@ void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture> &p_fra int SpriteFrames::get_frame_count(const StringName &p_anim) const { const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V(!E, 0); + ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); return E->get().frames.size(); } @@ -122,7 +122,7 @@ int SpriteFrames::get_frame_count(const StringName &p_anim) const { void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) { Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND(!E); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); E->get().frames.remove(p_idx); emit_changed(); @@ -130,7 +130,7 @@ void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) { void SpriteFrames::clear(const StringName &p_anim) { Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND(!E); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); E->get().frames.clear(); emit_changed(); @@ -144,7 +144,7 @@ void SpriteFrames::clear_all() { void SpriteFrames::add_animation(const StringName &p_anim) { - ERR_FAIL_COND(animations.has(p_anim)); + ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'."); animations[p_anim] = Anim(); animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX; @@ -161,8 +161,8 @@ void SpriteFrames::remove_animation(const StringName &p_anim) { void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) { - ERR_FAIL_COND(!animations.has(p_prev)); - ERR_FAIL_COND(animations.has(p_next)); + ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'."); + ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists."); Anim anim = animations[p_prev]; animations.erase(p_prev); @@ -202,26 +202,26 @@ Vector<String> SpriteFrames::get_animation_names() const { void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) { - ERR_FAIL_COND(p_fps < 0); + ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ")."); Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND(!E); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); E->get().speed = p_fps; } float SpriteFrames::get_animation_speed(const StringName &p_anim) const { const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V(!E, 0); + ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); return E->get().speed; } void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) { Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND(!E); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); E->get().loop = p_loop; } bool SpriteFrames::get_animation_loop(const StringName &p_anim) const { const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V(!E, false); + ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist."); return E->get().loop; } diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h index 2cc372bd93..3192d44678 100644 --- a/scene/2d/animated_sprite.h +++ b/scene/2d/animated_sprite.h @@ -85,7 +85,7 @@ public: _FORCE_INLINE_ Ref<Texture> get_frame(const StringName &p_anim, int p_idx) const { const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V(!E, Ref<Texture>()); + ERR_FAIL_COND_V_MSG(!E, Ref<Texture>(), "Animation '" + String(p_anim) + "' doesn't exist."); ERR_FAIL_COND_V(p_idx < 0, Ref<Texture>()); if (p_idx >= E->get().frames.size()) return Ref<Texture>(); @@ -96,7 +96,7 @@ public: _FORCE_INLINE_ Ref<Texture> get_normal_frame(const StringName &p_anim, int p_idx) const { const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V(!E, Ref<Texture>()); + ERR_FAIL_COND_V_MSG(!E, Ref<Texture>(), "Animation '" + String(p_anim) + "' doesn't exist."); ERR_FAIL_COND_V(p_idx < 0, Ref<Texture>()); const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name); @@ -109,7 +109,7 @@ public: void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture> &p_frame) { Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND(!E); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); ERR_FAIL_COND(p_idx < 0); if (p_idx >= E->get().frames.size()) return; diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index a636eea285..66a1318cb7 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -438,7 +438,7 @@ bool Area2D::is_monitorable() const { Array Area2D::get_overlapping_bodies() const { - ERR_FAIL_COND_V(!monitoring, Array()); + ERR_FAIL_COND_V_MSG(!monitoring, Array(), "Can't find overlapping bodies when monitoring is off."); Array ret; ret.resize(body_map.size()); int idx = 0; @@ -456,7 +456,7 @@ Array Area2D::get_overlapping_bodies() const { Array Area2D::get_overlapping_areas() const { - ERR_FAIL_COND_V(!monitoring, Array()); + ERR_FAIL_COND_V_MSG(!monitoring, Array(), "Can't find overlapping bodies when monitoring is off."); Array ret; ret.resize(area_map.size()); int idx = 0; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index f9f273d494..85c423964b 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -44,7 +44,7 @@ void CPUParticles2D::set_emitting(bool p_emitting) { void CPUParticles2D::set_amount(int p_amount) { - ERR_FAIL_COND(p_amount < 1); + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0."); particles.resize(p_amount); { @@ -62,7 +62,7 @@ void CPUParticles2D::set_amount(int p_amount) { } void CPUParticles2D::set_lifetime(float p_lifetime) { - ERR_FAIL_COND(p_lifetime <= 0); + ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); lifetime = p_lifetime; } @@ -866,8 +866,8 @@ void CPUParticles2D::_particles_process(float p_delta) { } //scale by scale - float base_scale = Math::lerp(parameters[PARAM_SCALE] * tex_scale, 1.0f, p.scale_rand * randomness[PARAM_SCALE]); - if (base_scale == 0.0) base_scale = 0.000001; + float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]); + if (base_scale < 0.000001) base_scale = 0.000001; p.transform.elements[0] *= base_scale; p.transform.elements[1] *= base_scale; @@ -1122,8 +1122,9 @@ void CPUParticles2D::_notification(int p_what) { } void CPUParticles2D::convert_from_particles(Node *p_particles) { + Particles2D *particles = Object::cast_to<Particles2D>(p_particles); - ERR_FAIL_COND(!particles); + ERR_FAIL_COND_MSG(!particles, "Only Particles2D nodes can be converted to CPUParticles2D."); set_emitting(particles->is_emitting()); set_amount(particles->get_amount()); diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index f4430d93f6..336c8aa78e 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -437,7 +437,7 @@ void Node2D::_bind_methods() { ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform"); diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 93c12f0103..0bf8237d37 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -51,13 +51,13 @@ void Particles2D::set_emitting(bool p_emitting) { void Particles2D::set_amount(int p_amount) { - ERR_FAIL_COND(p_amount < 1); + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1."); amount = p_amount; VS::get_singleton()->particles_set_amount(particles, amount); } void Particles2D::set_lifetime(float p_lifetime) { - ERR_FAIL_COND(p_lifetime <= 0); + ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); lifetime = p_lifetime; VS::get_singleton()->particles_set_lifetime(particles, lifetime); } diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 28f7243c44..3a4f397fe0 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -199,7 +199,7 @@ void StaticBody2D::set_friction(real_t p_friction) { WARN_DEPRECATED_MSG("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); - ERR_FAIL_COND(p_friction < 0 || p_friction > 1); + ERR_FAIL_COND_MSG(p_friction < 0 || p_friction > 1, "Friction must be between 0 and 1."); if (physics_material_override.is_null()) { physics_material_override.instance(); @@ -227,7 +227,7 @@ void StaticBody2D::set_bounce(real_t p_bounce) { WARN_DEPRECATED_MSG("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); - ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); + ERR_FAIL_COND_MSG(p_bounce < 0 || p_bounce > 1, "Bounce must be between 0 and 1."); if (physics_material_override.is_null()) { physics_material_override.instance(); @@ -622,7 +622,7 @@ void RigidBody2D::set_friction(real_t p_friction) { WARN_DEPRECATED_MSG("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); - ERR_FAIL_COND(p_friction < 0 || p_friction > 1); + ERR_FAIL_COND_MSG(p_friction < 0 || p_friction > 1, "Friction must be between 0 and 1."); if (physics_material_override.is_null()) { physics_material_override.instance(); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 32a0b732c0..5e14959e9d 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -842,7 +842,7 @@ void Polygon2D::_bind_methods() { ADD_GROUP("Texture", "texture_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset"), "set_texture_offset", "get_texture_offset"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation"); ADD_GROUP("Skeleton", ""); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton"); diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index f0c46a5fb7..e37407ceb3 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -38,8 +38,9 @@ const float DEFAULT_GIZMO_EXTENTS = 10.0; void Position2D::_draw_cross() { float extents = get_gizmo_extents(); - draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(1, 0.5, 0.5)); - draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.5, 1, 0.5)); + // Colors taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`) + draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(0.96, 0.20, 0.32)); + draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.53, 0.84, 0.01)); } Rect2 Position2D::_edit_get_rect() const { diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index d38a78780f..83f92ce2bc 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -281,7 +281,7 @@ Vector2 Sprite::get_frame_coords() const { void Sprite::set_vframes(int p_amount) { - ERR_FAIL_COND(p_amount < 1); + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1."); vframes = p_amount; update(); item_rect_changed(); @@ -294,7 +294,7 @@ int Sprite::get_vframes() const { void Sprite::set_hframes(int p_amount) { - ERR_FAIL_COND(p_amount < 1); + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1."); hframes = p_amount; update(); item_rect_changed(); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 15423f8c5e..c9ba51bafb 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -216,7 +216,7 @@ Size2 TileMap::get_cell_size() const { void TileMap::set_quadrant_size(int p_size) { - ERR_FAIL_COND(p_size < 1); + ERR_FAIL_COND_MSG(p_size < 1, "Quadrant size cannot be smaller than 1."); _clear_quadrants(); quadrant_size = p_size; @@ -1050,6 +1050,7 @@ void TileMap::update_dirty_bitmask() { void TileMap::fix_invalid_tiles() { + ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open."); for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) { if (!tile_set->has_tile(get_cell(E->key().x, E->key().y))) { @@ -1549,7 +1550,8 @@ Vector2 TileMap::_map_to_world(int p_x, int p_y, bool p_ignore_ofs) const { ret += get_cell_transform()[1] * (half_offset == HALF_OFFSET_Y ? 0.5 : -0.5); } } break; - default: { + case HALF_OFFSET_DISABLED: { + // Nothing to do. } } } @@ -1612,26 +1614,27 @@ Vector2 TileMap::world_to_map(const Vector2 &p_pos) const { switch (half_offset) { case HALF_OFFSET_X: { - if (ret.y > 0 ? int(ret.y) & 1 : (int(ret.y) - 1) & 1) { + if (int(floor(ret.y)) & 1) { ret.x -= 0.5; } } break; case HALF_OFFSET_NEGATIVE_X: { - if (ret.y > 0 ? int(ret.y) & 1 : (int(ret.y) - 1) & 1) { + if (int(floor(ret.y)) & 1) { ret.x += 0.5; } } break; case HALF_OFFSET_Y: { - if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) { + if (int(floor(ret.x)) & 1) { ret.y -= 0.5; } } break; case HALF_OFFSET_NEGATIVE_Y: { - if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) { + if (int(floor(ret.x)) & 1) { ret.y += 0.5; } } break; - default: { + case HALF_OFFSET_DISABLED: { + // Nothing to do. } } diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index b70e6dbc5d..4b1eccb40d 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -88,7 +88,7 @@ float BakedLightmapData::get_energy() const { void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance) { - ERR_FAIL_COND(p_lightmap.is_null()); + ERR_FAIL_COND_MSG(p_lightmap.is_null(), "It's not a reference to a valid Texture object."); User user; user.path = p_path; user.lightmap = p_lightmap; @@ -360,7 +360,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi //check for valid save path DirAccessRef d = DirAccess::open(save_path); if (!d) { - ERR_PRINTS("Invalid Save Path: " + save_path); + ERR_PRINTS("Invalid Save Path '" + save_path + "'."); return BAKE_ERROR_NO_SAVE_PATH; } } diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 9f8510248c..9797b5f3ab 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -548,9 +548,9 @@ void Camera::_bind_methods() { BIND_ENUM_CONSTANT(KEEP_WIDTH); BIND_ENUM_CONSTANT(KEEP_HEIGHT); - BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED) - BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP) - BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP) + BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED); + BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP); + BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP); } float Camera::get_fov() const { diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index fc16bc36cb..93ff60bc4e 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -53,7 +53,7 @@ void CPUParticles::set_emitting(bool p_emitting) { void CPUParticles::set_amount(int p_amount) { - ERR_FAIL_COND(p_amount < 1); + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0."); particles.resize(p_amount); { @@ -71,7 +71,7 @@ void CPUParticles::set_amount(int p_amount) { } void CPUParticles::set_lifetime(float p_lifetime) { - ERR_FAIL_COND(p_lifetime <= 0); + ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); lifetime = p_lifetime; } @@ -915,8 +915,8 @@ void CPUParticles::_particles_process(float p_delta) { } //scale by scale - float base_scale = Math::lerp(parameters[PARAM_SCALE] * tex_scale, 1.0f, p.scale_rand * randomness[PARAM_SCALE]); - if (base_scale == 0.0) base_scale = 0.000001; + float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]); + if (base_scale < 0.000001) base_scale = 0.000001; p.transform.basis.scale(Vector3(1, 1, 1) * base_scale); @@ -1193,7 +1193,7 @@ void CPUParticles::_notification(int p_what) { void CPUParticles::convert_from_particles(Node *p_particles) { Particles *particles = Object::cast_to<Particles>(p_particles); - ERR_FAIL_COND(!particles); + ERR_FAIL_COND_MSG(!particles, "Only Particles nodes can be converted to CPUParticles."); set_emitting(particles->is_emitting()); set_amount(particles->get_amount()); diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 12d562c0c6..ba0460d47c 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -230,7 +230,7 @@ void Navigation::navmesh_set_transform(int p_id, const Transform &p_xform) { } void Navigation::navmesh_remove(int p_id) { - ERR_FAIL_COND(!navmesh_map.has(p_id)); + ERR_FAIL_COND_MSG(!navmesh_map.has(p_id), "Trying to remove nonexisting navmesh with id: " + itos(p_id)); _navmesh_unlink(p_id); navmesh_map.erase(p_id); } diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index a6ccdb5791..241eb7d1ca 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -57,13 +57,13 @@ void Particles::set_emitting(bool p_emitting) { void Particles::set_amount(int p_amount) { - ERR_FAIL_COND(p_amount < 1); + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1."); amount = p_amount; VS::get_singleton()->particles_set_amount(particles, amount); } void Particles::set_lifetime(float p_lifetime) { - ERR_FAIL_COND(p_lifetime <= 0); + ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); lifetime = p_lifetime; VS::get_singleton()->particles_set_lifetime(particles, lifetime); } diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 71040d2d68..a02cc4bee6 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -188,7 +188,7 @@ void StaticBody::set_friction(real_t p_friction) { WARN_DEPRECATED_MSG("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); - ERR_FAIL_COND(p_friction < 0 || p_friction > 1); + ERR_FAIL_COND_MSG(p_friction < 0 || p_friction > 1, "Friction must be between 0 and 1."); if (physics_material_override.is_null()) { physics_material_override.instance(); @@ -216,7 +216,7 @@ void StaticBody::set_bounce(real_t p_bounce) { WARN_DEPRECATED_MSG("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); - ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); + ERR_FAIL_COND_MSG(p_bounce < 0 || p_bounce > 1, "Bounce must be between 0 and 1."); if (physics_material_override.is_null()) { physics_material_override.instance(); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index ead1e69f90..ae79b4eebf 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -245,6 +245,9 @@ void Skeleton::_notification(int p_what) { if (b.enabled) { Transform pose = b.pose; + if (b.custom_pose_enable) { + pose = b.custom_pose * pose; + } if (b.parent >= 0) { b.pose_global = bonesptr[b.parent].pose_global * pose; @@ -267,7 +270,9 @@ void Skeleton::_notification(int p_what) { if (b.enabled) { Transform pose = b.pose; - + if (b.custom_pose_enable) { + pose = b.custom_pose * pose; + } if (b.parent >= 0) { b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose); @@ -533,6 +538,23 @@ Transform Skeleton::get_bone_pose(int p_bone) const { return bones[p_bone].pose; } +void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) { + + ERR_FAIL_INDEX(p_bone, bones.size()); + //ERR_FAIL_COND( !is_inside_scene() ); + + bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform()); + bones.write[p_bone].custom_pose = p_custom_pose; + + _make_dirty(); +} + +Transform Skeleton::get_bone_custom_pose(int p_bone) const { + + ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); + return bones[p_bone].custom_pose; +} + void Skeleton::_make_dirty() { if (dirty) @@ -770,6 +792,7 @@ Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) { skin_bindings.insert(skin_ref.operator->()); skin->connect("changed", skin_ref.operator->(), "_skin_changed"); + _make_dirty(); return skin_ref; } @@ -808,6 +831,9 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton::get_bone_global_pose); + ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton::get_bone_custom_pose); + ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton::set_bone_custom_pose); + #ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation); diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index f20c550055..824d9567fa 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -87,6 +87,9 @@ private: Transform pose; Transform pose_global; + bool custom_pose_enable; + Transform custom_pose; + float global_pose_override_amount; bool global_pose_override_reset; Transform global_pose_override; @@ -102,6 +105,7 @@ private: parent = -1; enabled = true; disable_rest = false; + custom_pose_enable = false; global_pose_override_amount = 0; global_pose_override_reset = false; #ifndef _3D_DISABLED @@ -184,6 +188,9 @@ public: void set_bone_pose(int p_bone, const Transform &p_pose); Transform get_bone_pose(int p_bone) const; + void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose); + Transform get_bone_custom_pose(int p_bone) const; + void localize_rests(); // used for loaders and tools int get_process_order(int p_idx); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 20a09696e1..6f67d01a1c 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -350,8 +350,8 @@ void AnimationNodeOneShot::_bind_methods() { ADD_GROUP("", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync"); - BIND_ENUM_CONSTANT(MIX_MODE_BLEND) - BIND_ENUM_CONSTANT(MIX_MODE_ADD) + BIND_ENUM_CONSTANT(MIX_MODE_BLEND); + BIND_ENUM_CONSTANT(MIX_MODE_ADD); } AnimationNodeOneShot::AnimationNodeOneShot() { diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp index e26bd5b5a1..5956609244 100644 --- a/scene/animation/animation_cache.cpp +++ b/scene/animation/animation_cache.cpp @@ -80,7 +80,7 @@ void AnimationCache::_update_cache() { if (!node) { path_cache.push_back(Path()); - ERR_CONTINUE_MSG(!node, "Invalid track path in animation: " + np + "."); + ERR_CONTINUE_MSG(!node, "Invalid track path in animation '" + np + "'."); } Path path; @@ -91,7 +91,7 @@ void AnimationCache::_update_cache() { if (np.get_subname_count() > 1) { path_cache.push_back(Path()); - ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM, "Transform tracks can't have a subpath: " + np + "."); + ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM, "Transform tracks can't have a subpath '" + np + "'."); } Spatial *sp = Object::cast_to<Spatial>(node); @@ -99,7 +99,7 @@ void AnimationCache::_update_cache() { if (!sp) { path_cache.push_back(Path()); - ERR_CONTINUE_MSG(!sp, "Transform track not of type Spatial: " + np + "."); + ERR_CONTINUE_MSG(!sp, "Transform track not of type Spatial '" + np + "'."); } if (np.get_subname_count() == 1) { @@ -110,13 +110,13 @@ void AnimationCache::_update_cache() { if (!sk) { path_cache.push_back(Path()); - ERR_CONTINUE_MSG(!sk, "Property defined in Transform track, but not a Skeleton!: " + np + "."); + ERR_CONTINUE_MSG(!sk, "Property defined in Transform track, but not a Skeleton! '" + np + "'."); } int idx = sk->find_bone(ps); if (idx == -1) { path_cache.push_back(Path()); - ERR_CONTINUE_MSG(idx == -1, "Property defined in Transform track, but not a Skeleton Bone!: " + np + "."); + ERR_CONTINUE_MSG(idx == -1, "Property defined in Transform track, but not a Skeleton Bone! '" + np + "'."); } path.bone_idx = idx; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 728c23fbaa..f9bf129b59 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1098,7 +1098,7 @@ void AnimationPlayer::get_animation_list(List<StringName> *p_animations) const { void AnimationPlayer::set_blend_time(const StringName &p_animation1, const StringName &p_animation2, float p_time) { - ERR_FAIL_COND(p_time < 0); + ERR_FAIL_COND_MSG(p_time < 0, "Blend time cannot be smaller than 0."); BlendKey bk; bk.from = p_animation1; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 6dd9e401f6..ffe011e5f7 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -396,11 +396,18 @@ void ColorPicker::_update_text_value() { } void ColorPicker::_sample_draw() { - Rect2 r = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95)); + const Rect2 r = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95)); + if (color.a < 1.0) { sample->draw_texture_rect(get_icon("preset_bg", "ColorPicker"), r, true); } + sample->draw_rect(r, color); + + if (color.r > 1 || color.g > 1 || color.b > 1) { + // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview + sample->draw_texture(get_icon("overbright_indicator", "ColorPicker"), Point2()); + } } void ColorPicker::_hsv_draw(int p_which, Control *c) { @@ -894,10 +901,15 @@ void ColorPickerButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { - Ref<StyleBox> normal = get_stylebox("normal"); - Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size()); + const Ref<StyleBox> normal = get_stylebox("normal"); + const Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size()); draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true); draw_rect(r, color); + + if (color.r > 1 || color.g > 1 || color.b > 1) { + // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview + draw_texture(Control::get_icon("overbright_indicator", "ColorPicker"), normal->get_offset()); + } } break; case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index d39f017cad..fafbcf0c55 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -645,6 +645,7 @@ void Control::_notification(int p_notification) { } break; case NOTIFICATION_THEME_CHANGED: { + minimum_size_changed(); update(); } break; case NOTIFICATION_MODAL_CLOSE: { @@ -1411,6 +1412,9 @@ void Control::_size_changed() { } void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) { + + ERR_FAIL_INDEX((int)p_margin, 4); + Rect2 parent_rect = get_parent_anchorable_rect(); float parent_range = (p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? parent_rect.size.x : parent_rect.size.y; float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range; @@ -1455,6 +1459,9 @@ void Control::set_anchor_and_margin(Margin p_margin, float p_anchor, float p_pos } void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { + + ERR_FAIL_INDEX((int)p_preset, 16); + //Left switch (p_preset) { case PRESET_TOP_LEFT: @@ -1569,6 +1576,10 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { } void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode, int p_margin) { + + ERR_FAIL_INDEX((int)p_preset, 16); + ERR_FAIL_INDEX((int)p_resize_mode, 4); + // Calculate the size if the node is not resized Size2 min_size = get_minimum_size(); Size2 new_size = get_size(); @@ -1703,6 +1714,8 @@ void Control::set_anchors_and_margins_preset(LayoutPreset p_preset, LayoutPreset float Control::get_anchor(Margin p_margin) const { + ERR_FAIL_INDEX_V(int(p_margin), 4, 0.0); + return data.anchor[p_margin]; } @@ -1719,6 +1732,8 @@ void Control::_change_notify_margins() { void Control::set_margin(Margin p_margin, float p_value) { + ERR_FAIL_INDEX((int)p_margin, 4); + data.margin[p_margin] = p_value; _size_changed(); } @@ -1739,6 +1754,8 @@ void Control::set_end(const Size2 &p_point) { float Control::get_margin(Margin p_margin) const { + ERR_FAIL_INDEX_V((int)p_margin, 4, 0); + return data.margin[p_margin]; } @@ -1950,6 +1967,8 @@ void Control::add_constant_override(const StringName &p_name, int p_constant) { void Control::set_focus_mode(FocusMode p_focus_mode) { + ERR_FAIL_INDEX((int)p_focus_mode, 3); + if (is_inside_tree() && p_focus_mode == FOCUS_NONE && data.focus_mode != FOCUS_NONE && has_focus()) release_focus(); @@ -2297,6 +2316,8 @@ Control *Control::make_custom_tooltip(const String &p_text) const { void Control::set_default_cursor_shape(CursorShape p_shape) { + ERR_FAIL_INDEX(int(p_shape), CURSOR_MAX); + data.default_cursor = p_shape; } @@ -2357,6 +2378,8 @@ NodePath Control::get_focus_previous() const { Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) { + ERR_FAIL_INDEX_V((int)p_margin, 4, NULL); + if (p_count >= MAX_NEIGHBOUR_SEARCH_COUNT) return NULL; if (!data.focus_neighbour[p_margin].is_empty()) { @@ -2759,6 +2782,8 @@ bool Control::is_clipping_contents() { void Control::set_h_grow_direction(GrowDirection p_direction) { + ERR_FAIL_INDEX((int)p_direction, 3); + data.h_grow = p_direction; _size_changed(); } @@ -2770,6 +2795,8 @@ Control::GrowDirection Control::get_h_grow_direction() const { void Control::set_v_grow_direction(GrowDirection p_direction) { + ERR_FAIL_INDEX((int)p_direction, 3); + data.v_grow = p_direction; _size_changed(); } @@ -2947,7 +2974,7 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", 0), "_set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.01"), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents"); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 9ed1d2bf45..31551d6257 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -206,9 +206,9 @@ void WindowDialog::_notification(int p_what) { Color title_color = get_color("title_color", "WindowDialog"); int title_height = get_constant("title_height", "WindowDialog"); int font_height = title_font->get_height() - title_font->get_descent() * 2; - int x = (size.x - title_font->get_string_size(title).x) / 2; + int x = (size.x - title_font->get_string_size(xl_title).x) / 2; int y = (-title_height + font_height) / 2; - title_font->draw(canvas, Point2(x, y), title, title_color, size.x - panel->get_minimum_size().x); + title_font->draw(canvas, Point2(x, y), xl_title, title_color, size.x - panel->get_minimum_size().x); } break; case NOTIFICATION_THEME_CHANGED: @@ -222,8 +222,9 @@ void WindowDialog::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { String new_title = tr(title); - if (title != new_title) { - title = new_title; + if (new_title != xl_title) { + xl_title = new_title; + minimum_size_changed(); update(); } } break; @@ -283,9 +284,10 @@ int WindowDialog::_drag_hit_test(const Point2 &pos) const { void WindowDialog::set_title(const String &p_title) { - String new_title = tr(p_title); - if (title != new_title) { - title = new_title; + if (title != p_title) { + title = p_title; + xl_title = tr(p_title); + minimum_size_changed(); update(); } } @@ -306,7 +308,7 @@ Size2 WindowDialog::get_minimum_size() const { Ref<Font> font = get_font("title_font", "WindowDialog"); const int button_width = close_button->get_combined_minimum_size().x; - const int title_width = font->get_string_size(title).x; + const int title_width = font->get_string_size(xl_title).x; const int padding = button_width / 2; const int button_area = button_width + padding; diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index 1a0350ba18..afd1173f28 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -53,6 +53,7 @@ class WindowDialog : public Popup { TextureButton *close_button; String title; + String xl_title; int drag_type; Point2 drag_offset; Point2 drag_offset_far; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 9bc593ea3b..24c046457b 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -637,6 +637,8 @@ bool FileDialog::is_mode_overriding_title() const { void FileDialog::set_mode(Mode p_mode) { + ERR_FAIL_INDEX((int)p_mode, 5); + mode = p_mode; switch (mode) { diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index d0e2edc7b5..d304a37f82 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -36,20 +36,18 @@ void GridContainer::_notification(int p_what) { case NOTIFICATION_SORT_CHILDREN: { - int valid_controls_index; - - Map<int, int> col_minw; // max of min_width of all controls in each col (indexed by col) - Map<int, int> row_minh; // max of min_height of all controls in each row (indexed by row) - Set<int> col_expanded; // columns which have the SIZE_EXPAND flag set - Set<int> row_expanded; // rows which have the SIZE_EXPAND flag set + Map<int, int> col_minw; // Max of min_width of all controls in each col (indexed by col). + Map<int, int> row_minh; // Max of min_height of all controls in each row (indexed by row). + Set<int> col_expanded; // Columns which have the SIZE_EXPAND flag set. + Set<int> row_expanded; // Rows which have the SIZE_EXPAND flag set. int hsep = get_constant("hseparation"); int vsep = get_constant("vseparation"); int max_col = MIN(get_child_count(), columns); int max_row = get_child_count() / columns; - // Compute the per-column/per-row data - valid_controls_index = 0; + // Compute the per-column/per-row data. + int valid_controls_index = 0; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); if (!c || !c->is_visible_in_tree()) @@ -77,7 +75,12 @@ void GridContainer::_notification(int p_what) { } } - // Evaluate the remaining space for expanded columns/rows + // Consider all empty columns expanded. + for (int i = valid_controls_index; i < columns; i++) { + col_expanded.insert(i); + } + + // Evaluate the remaining space for expanded columns/rows. Size2 remaining_space = get_size(); for (Map<int, int>::Element *E = col_minw.front(); E; E = E->next()) { if (!col_expanded.has(E->key())) @@ -93,7 +96,7 @@ void GridContainer::_notification(int p_what) { bool can_fit = false; while (!can_fit && col_expanded.size() > 0) { - // Check if all minwidth constraints are ok if we use the remaining space + // Check if all minwidth constraints are OK if we use the remaining space. can_fit = true; int max_index = col_expanded.front()->get(); for (Set<int>::Element *E = col_expanded.front(); E; E = E->next()) { @@ -105,7 +108,7 @@ void GridContainer::_notification(int p_what) { } } - // If not, the column with maximum minwidth is not expanded + // If not, the column with maximum minwidth is not expanded. if (!can_fit) { col_expanded.erase(max_index); remaining_space.width -= col_minw[max_index]; @@ -114,7 +117,7 @@ void GridContainer::_notification(int p_what) { can_fit = false; while (!can_fit && row_expanded.size() > 0) { - // Check if all minwidth constraints are ok if we use the remaining space + // Check if all minheight constraints are OK if we use the remaining space. can_fit = true; int max_index = row_expanded.front()->get(); for (Set<int>::Element *E = row_expanded.front(); E; E = E->next()) { @@ -126,14 +129,14 @@ void GridContainer::_notification(int p_what) { } } - // If not, the row with maximum minwidth is not expanded + // If not, the row with maximum minheight is not expanded. if (!can_fit) { row_expanded.erase(max_index); remaining_space.height -= row_minh[max_index]; } } - // Finally, fit the nodes + // Finally, fit the nodes. int col_expand = col_expanded.size() > 0 ? remaining_space.width / col_expanded.size() : 0; int row_expand = row_expanded.size() > 0 ? remaining_space.height / row_expanded.size() : 0; @@ -152,11 +155,11 @@ void GridContainer::_notification(int p_what) { if (col == 0) { col_ofs = 0; if (row > 0) - row_ofs += ((row_expanded.has(row - 1)) ? row_expand : row_minh[row - 1]) + vsep; + row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + vsep; } Point2 p(col_ofs, row_ofs); - Size2 s((col_expanded.has(col)) ? col_expand : col_minw[col], (row_expanded.has(row)) ? row_expand : row_minh[row]); + Size2 s(col_expanded.has(col) ? col_expand : col_minw[col], row_expanded.has(row) ? row_expand : row_minh[row]); fit_child_in_rect(c, Rect2(p, s)); @@ -207,7 +210,7 @@ Size2 GridContainer::get_minimum_size() const { for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); - if (!c || !c->is_visible_in_tree()) + if (!c || !c->is_visible()) continue; int row = valid_controls_index / columns; int col = valid_controls_index % columns; diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index a3bc68ffcd..4d06bee0d4 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -430,6 +430,7 @@ ItemList::SelectMode ItemList::get_select_mode() const { void ItemList::set_icon_mode(IconMode p_mode) { + ERR_FAIL_INDEX((int)p_mode, 2); icon_mode = p_mode; update(); shape_changed = true; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 04e03f569e..ab6f80bfa9 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -757,20 +757,17 @@ void LineEdit::_notification(int p_what) { } } - float icon_width = MIN(r_icon->get_width(), r_icon->get_width() * (height - (style->get_margin(MARGIN_TOP) + style->get_margin(MARGIN_BOTTOM))) / r_icon->get_height()); - float icon_height = MIN(r_icon->get_height(), height - (style->get_margin(MARGIN_TOP) + style->get_margin(MARGIN_BOTTOM))); - Rect2 icon_region = Rect2(Point2(width - icon_width - style->get_margin(MARGIN_RIGHT), height / 2 - icon_height / 2), Size2(icon_width, icon_height)); - draw_texture_rect_region(r_icon, icon_region, Rect2(Point2(), r_icon->get_size()), color_icon); + r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon); if (align == ALIGN_CENTER) { if (window_pos == 0) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - icon_width - style->get_margin(MARGIN_RIGHT) * 2) / 2); + x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); } } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - icon_width - style->get_margin(MARGIN_RIGHT)); + x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT)); } - ofs_max -= icon_width; + ofs_max -= r_icon->get_width(); } int caret_height = font->get_height() > y_area ? y_area : font->get_height(); @@ -1279,10 +1276,7 @@ void LineEdit::set_cursor_position(int p_pos) { bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref<Texture> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon; - - float icon_width = MIN(r_icon->get_width(), r_icon->get_width() * (get_size().height - (style->get_margin(MARGIN_TOP) + style->get_margin(MARGIN_BOTTOM))) / r_icon->get_height()); - - window_width -= icon_width; + window_width -= r_icon->get_width(); } if (window_width < 0) @@ -1361,21 +1355,30 @@ Size2 LineEdit::get_minimum_size() const { Ref<StyleBox> style = get_stylebox("normal"); Ref<Font> font = get_font("font"); - Size2 min = style->get_minimum_size(); - min.height += font->get_height(); + Size2 min_size; // Minimum size of text. int space_size = font->get_char_size(' ').x; - int mstext = get_constant("minimum_spaces") * space_size; + min_size.width = get_constant("minimum_spaces") * space_size; if (expand_to_text_length) { // Add a space because some fonts are too exact, and because cursor needs a bit more when at the end. - mstext = MAX(mstext, font->get_string_size(text).x + space_size); + min_size.width = MAX(min_size.width, font->get_string_size(text).x + space_size); } - min.width += mstext; + min_size.height = font->get_height(); + + // Take icons into account. + if (!text.empty() && is_editable() && clear_button_enabled) { + min_size.width = MAX(min_size.width, Control::get_icon("clear")->get_width()); + min_size.height = MAX(min_size.height, Control::get_icon("clear")->get_height()); + } + if (right_icon.is_valid()) { + min_size.width = MAX(min_size.width, right_icon->get_width()); + min_size.height = MAX(min_size.height, right_icon->get_height()); + } - return min; + return style->get_minimum_size() + min_size; } void LineEdit::deselect() { @@ -1772,7 +1775,6 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled"); diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp index 67fa85b832..f9e0be5b31 100644 --- a/scene/gui/rich_text_effect.cpp +++ b/scene/gui/rich_text_effect.cpp @@ -119,4 +119,9 @@ CharFXTransform::CharFXTransform() { offset = Point2(); color = Color(); character = 0; + elapsed_time = 0.0f; +} + +CharFXTransform::~CharFXTransform() { + environment.clear(); } diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index f9c3e15399..4330cebfe6 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -64,6 +64,8 @@ public: Dictionary environment; CharFXTransform(); + ~CharFXTransform(); + uint64_t get_relative_index() { return relative_index; } void set_relative_index(uint64_t p_index) { relative_index = p_index; } uint64_t get_absolute_index() { return absolute_index; } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index d9ae42d6e6..42cb89b2d6 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -143,6 +143,8 @@ Rect2 RichTextLabel::_get_text_rect() { int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) { + ERR_FAIL_INDEX_V((int)p_mode, 3, 0); + RID ci; if (r_outside) *r_outside = false; @@ -348,6 +350,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int it_char_start = p_char_count; Vector<ItemFX *> fx_stack = Vector<ItemFX *>(); + _fetch_item_fx_stack(text, fx_stack); bool custom_fx_ok = true; if (p_mode == PROCESS_DRAW) { @@ -359,8 +362,14 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & strikethrough = true; } - fade = _fetch_by_type<ItemFade>(text, ITEM_FADE); - _fetch_item_stack<ItemFX>(text, fx_stack); + Item *fade_item = it; + while (fade_item) { + if (fade_item->type == ITEM_FADE) { + fade = static_cast<ItemFade *>(fade_item); + break; + } + fade_item = fade_item->parent; + } } else if (p_mode == PROCESS_CACHE) { l.char_count += text->text.length(); @@ -467,18 +476,16 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & faded_visibility > 0.0f); for (int j = 0; j < fx_stack.size(); j++) { - ItemCustomFX *item_custom = Object::cast_to<ItemCustomFX>(fx_stack[j]); - ItemShake *item_shake = Object::cast_to<ItemShake>(fx_stack[j]); - ItemWave *item_wave = Object::cast_to<ItemWave>(fx_stack[j]); - ItemTornado *item_tornado = Object::cast_to<ItemTornado>(fx_stack[j]); - ItemRainbow *item_rainbow = Object::cast_to<ItemRainbow>(fx_stack[j]); - - if (item_custom && custom_fx_ok) { - Ref<CharFXTransform> charfx = Ref<CharFXTransform>(memnew(CharFXTransform)); - Ref<RichTextEffect> custom_effect = _get_custom_effect_by_code(item_custom->identifier); + ItemFX *item_fx = fx_stack[j]; + + if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) { + ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx); + + Ref<CharFXTransform> charfx = item_custom->char_fx_transform; + Ref<RichTextEffect> custom_effect = item_custom->custom_effect; + if (!custom_effect.is_null()) { charfx->elapsed_time = item_custom->elapsed_time; - charfx->environment = item_custom->environment; charfx->relative_index = c_item_offset; charfx->absolute_index = p_char_count; charfx->visibility = visible; @@ -494,7 +501,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & visible &= charfx->visibility; fx_char = charfx->character; } - } else if (item_shake) { + } else if (item_fx->type == ITEM_SHAKE) { + ItemShake *item_shake = static_cast<ItemShake *>(item_fx); + uint64_t char_current_rand = item_shake->offset_random(c_item_offset); uint64_t char_previous_rand = item_shake->offset_previous_random(c_item_offset); uint64_t max_rand = 2147483647; @@ -509,14 +518,20 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f; - } else if (item_wave) { + } else if (item_fx->type == ITEM_WAVE) { + ItemWave *item_wave = static_cast<ItemWave *>(item_fx); + double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_wave->amplitude / 10.0f); fx_offset += Point2(0, 1) * value; - } else if (item_tornado) { + } else if (item_fx->type == ITEM_TORNADO) { + ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx); + double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius); double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius); fx_offset += Point2(torn_x, torn_y); - } else if (item_rainbow) { + } else if (item_fx->type == ITEM_RAINBOW) { + ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx); + fx_color = fx_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + pofs) / 50)), item_rainbow->saturation, item_rainbow->value, @@ -884,7 +899,11 @@ void RichTextLabel::_update_scroll() { void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, float p_delta_time) { Item *it = p_frame; while (it) { - ItemFX *ifx = Object::cast_to<ItemFX>(it); + ItemFX *ifx = NULL; + + if (it->type == ITEM_CUSTOMFX || it->type == ITEM_SHAKE || it->type == ITEM_WAVE || it->type == ITEM_TORNADO || it->type == ITEM_RAINBOW) { + ifx = static_cast<ItemFX *>(it); + } if (!ifx) { it = _get_next_item(it, true); @@ -893,7 +912,12 @@ void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, float p_delta_ ifx->elapsed_time += p_delta_time; - ItemShake *shake = Object::cast_to<ItemShake>(it); + ItemShake *shake = NULL; + + if (it->type == ITEM_SHAKE) { + shake = static_cast<ItemShake *>(it); + } + if (shake) { bool cycle = (shake->elapsed_time > (1.0f / shake->rate)); if (cycle) { @@ -983,9 +1007,6 @@ void RichTextLabel::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: { float dt = get_process_delta_time(); - for (int i = 0; i < custom_effects.size(); i++) { - } - _update_fx(main, dt); update(); } @@ -1397,6 +1418,9 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) { } bool RichTextLabel::_find_by_type(Item *p_item, ItemType p_type) { + + ERR_FAIL_INDEX_V((int)p_type, 19, false); + Item *item = p_item; while (item) { @@ -1408,6 +1432,17 @@ bool RichTextLabel::_find_by_type(Item *p_item, ItemType p_type) { return false; } +void RichTextLabel::_fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack) { + Item *item = p_item; + while (item) { + if (item->type == ITEM_CUSTOMFX || item->type == ITEM_SHAKE || item->type == ITEM_WAVE || item->type == ITEM_TORNADO || item->type == ITEM_RAINBOW) { + r_stack.push_back(static_cast<ItemFX *>(item)); + } + + item = item->parent; + } +} + bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item) { Item *item = p_item; @@ -1776,10 +1811,10 @@ void RichTextLabel::push_rainbow(float p_saturation, float p_value, float p_freq _add_item(item, true); } -void RichTextLabel::push_customfx(String p_identifier, Dictionary p_environment) { +void RichTextLabel::push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment) { ItemCustomFX *item = memnew(ItemCustomFX); - item->identifier = p_identifier; - item->environment = p_environment; + item->custom_effect = p_custom_effect; + item->char_fx_transform->environment = p_environment; _add_item(item, true); } @@ -2287,7 +2322,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { Ref<RichTextEffect> effect = _get_custom_effect_by_code(identifier); if (!effect.is_null()) { - push_customfx(identifier, properties); + push_customfx(effect, properties); pos = brk_end + 1; tag_stack.push_front(identifier); set_process_internal(true); @@ -2700,17 +2735,16 @@ Size2 RichTextLabel::get_minimum_size() const { } Ref<RichTextEffect> RichTextLabel::_get_custom_effect_by_code(String p_bbcode_identifier) { - Ref<RichTextEffect> r; for (int i = 0; i < custom_effects.size(); i++) { if (!custom_effects[i].is_valid()) continue; if (custom_effects[i]->get_bbcode() == p_bbcode_identifier) { - r = custom_effects[i]; + return custom_effects[i]; } } - return r; + return Ref<RichTextEffect>(); } Dictionary RichTextLabel::parse_expressions_for_values(Vector<String> p_expressions) { diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 1c212700ef..1c90d974e4 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -103,8 +103,7 @@ private: } }; - struct Item : public Object { - + struct Item { int index; Item *parent; ItemType type; @@ -128,7 +127,6 @@ private: }; struct ItemFrame : public Item { - int parent_line; bool cell; Vector<Line> lines; @@ -144,70 +142,58 @@ private: }; struct ItemText : public Item { - String text; ItemText() { type = ITEM_TEXT; } }; struct ItemImage : public Item { - Ref<Texture> image; ItemImage() { type = ITEM_IMAGE; } }; struct ItemFont : public Item { - Ref<Font> font; ItemFont() { type = ITEM_FONT; } }; struct ItemColor : public Item { - Color color; ItemColor() { type = ITEM_COLOR; } }; struct ItemUnderline : public Item { - ItemUnderline() { type = ITEM_UNDERLINE; } }; struct ItemStrikethrough : public Item { - ItemStrikethrough() { type = ITEM_STRIKETHROUGH; } }; struct ItemMeta : public Item { - Variant meta; ItemMeta() { type = ITEM_META; } }; struct ItemAlign : public Item { - Align align; ItemAlign() { type = ITEM_ALIGN; } }; struct ItemIndent : public Item { - int level; ItemIndent() { type = ITEM_INDENT; } }; struct ItemList : public Item { - ListType list_type; ItemList() { type = ITEM_LIST; } }; struct ItemNewline : public Item { - ItemNewline() { type = ITEM_NEWLINE; } }; struct ItemTable : public Item { - struct Column { bool expand; int expand_ratio; @@ -301,18 +287,20 @@ private: }; struct ItemCustomFX : public ItemFX { - String identifier; - Dictionary environment; + Ref<CharFXTransform> char_fx_transform; + Ref<RichTextEffect> custom_effect; ItemCustomFX() { - identifier = ""; - environment = Dictionary(); type = ITEM_CUSTOMFX; + + char_fx_transform.instance(); } virtual ~ItemCustomFX() { _clear_children(); - environment.clear(); + + char_fx_transform.unref(); + custom_effect.unref(); } }; @@ -391,32 +379,7 @@ private: bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = NULL); bool _find_layout_subitem(Item *from, Item *to); bool _find_by_type(Item *p_item, ItemType p_type); - template <typename T> - T *_fetch_by_type(Item *p_item, ItemType p_type) { - Item *item = p_item; - T *result = NULL; - while (item) { - if (item->type == p_type) { - result = Object::cast_to<T>(item); - if (result) - return result; - } - item = item->parent; - } - - return result; - }; - template <typename T> - void _fetch_item_stack(Item *p_item, Vector<T *> &r_stack) { - Item *item = p_item; - while (item) { - T *found = Object::cast_to<T>(item); - if (found) { - r_stack.push_back(found); - } - item = item->parent; - } - } + void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack); void _update_scroll(); void _update_fx(ItemFrame *p_frame, float p_delta_time); @@ -460,7 +423,7 @@ public: void push_wave(float p_frequency, float p_amplitude); void push_tornado(float p_frequency, float p_radius); void push_rainbow(float p_saturation, float p_value, float p_frequency); - void push_customfx(String p_identifier, Dictionary p_environment); + void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment); void set_table_column_expand(int p_column, bool p_expand, int p_ratio = 1); int get_current_table_column() const; void push_cell(); diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index b777e77bc3..9f853cf0c8 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -287,7 +287,6 @@ void Slider::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrollable"), "set_scrollable", "is_scrollable"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tick_count", PROPERTY_HINT_RANGE, "0,4096,1"), "set_ticks", "get_ticks"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ticks_on_borders"), "set_ticks_on_borders", "get_ticks_on_borders"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode"); } Slider::Slider(Orientation p_orientation) { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 292d80be9d..a29ba36bad 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -94,7 +94,7 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { return; } - // Do not activate tabs when tabs is empty + // Do not activate tabs when tabs is empty. if (get_tab_count() == 0) return; @@ -140,6 +140,76 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { pos.x -= tab_width; } } + + Ref<InputEventMouseMotion> mm = p_event; + + if (mm.is_valid()) { + + Point2 pos(mm->get_position().x, mm->get_position().y); + Size2 size = get_size(); + + // Mouse must be on tabs in the tab header area. + if (pos.x < tabs_ofs_cache || pos.y > _get_top_margin()) { + + if (menu_hovered || highlight_arrow > -1) { + menu_hovered = false; + highlight_arrow = -1; + update(); + } + return; + } + + Ref<Texture> menu = get_icon("menu"); + if (popup) { + + if (pos.x >= size.width - menu->get_width()) { + if (!menu_hovered) { + menu_hovered = true; + highlight_arrow = -1; + update(); + return; + } + } else if (menu_hovered) { + menu_hovered = false; + update(); + } + + if (menu_hovered) { + return; + } + } + + // Do not activate tabs when tabs is empty. + if ((get_tab_count() == 0 || !buttons_visible_cache) && menu_hovered) { + highlight_arrow = -1; + update(); + return; + } + + int popup_ofs = 0; + if (popup) { + popup_ofs = menu->get_width(); + } + + Ref<Texture> increment = get_icon("increment"); + Ref<Texture> decrement = get_icon("decrement"); + if (pos.x >= size.width - increment->get_width() - popup_ofs) { + + if (highlight_arrow != 1) { + highlight_arrow = 1; + update(); + } + } else if (pos.x >= size.width - increment->get_width() - decrement->get_width() - popup_ofs) { + + if (highlight_arrow != 0) { + highlight_arrow = 0; + update(); + } + } else if (highlight_arrow > -1) { + highlight_arrow = -1; + update(); + } + } } void TabContainer::_notification(int p_what) { @@ -203,9 +273,11 @@ void TabContainer::_notification(int p_what) { Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); Ref<Texture> increment = get_icon("increment"); + Ref<Texture> increment_hl = get_icon("increment_highlight"); Ref<Texture> decrement = get_icon("decrement"); + Ref<Texture> decrement_hl = get_icon("decrement_highlight"); Ref<Texture> menu = get_icon("menu"); - Ref<Texture> menu_hl = get_icon("menu_hl"); + Ref<Texture> menu_hl = get_icon("menu_highlight"); Ref<Font> font = get_font("font"); Color font_color_fg = get_color("font_color_fg"); Color font_color_bg = get_color("font_color_bg"); @@ -332,7 +404,7 @@ void TabContainer::_notification(int p_what) { x = get_size().width; if (popup) { x -= menu->get_width(); - if (mouse_x_cache > x) + if (menu_hovered) menu_hl->draw(get_canvas_item(), Size2(x, (header_height - menu_hl->get_height()) / 2)); else menu->draw(get_canvas_item(), Size2(x, (header_height - menu->get_height()) / 2)); @@ -340,23 +412,26 @@ void TabContainer::_notification(int p_what) { // Draw the navigation buttons. if (buttons_visible_cache) { - int y_center = header_height / 2; x -= increment->get_width(); - increment->draw(canvas, - Point2(x, y_center - (increment->get_height() / 2)), - Color(1, 1, 1, last_tab_cache < tabs.size() - 1 ? 1.0 : 0.5)); + if (last_tab_cache < tabs.size() - 1) { + draw_texture(highlight_arrow == 1 ? increment_hl : increment, Point2(x, (header_height - increment->get_height()) / 2)); + } else { + draw_texture(increment, Point2(x, (header_height - increment->get_height()) / 2), Color(1, 1, 1, 0.5)); + } x -= decrement->get_width(); - decrement->draw(canvas, - Point2(x, y_center - (decrement->get_height() / 2)), - Color(1, 1, 1, first_tab_cache > 0 ? 1.0 : 0.5)); + if (first_tab_cache > 0) { + draw_texture(highlight_arrow == 0 ? decrement_hl : decrement, Point2(x, (header_height - decrement->get_height()) / 2)); + } else { + draw_texture(decrement, Point2(x, (header_height - decrement->get_height()) / 2), Color(1, 1, 1, 0.5)); + } } } break; case NOTIFICATION_THEME_CHANGED: { minimum_size_changed(); - call_deferred("_on_theme_changed"); //wait until all changed theme + call_deferred("_on_theme_changed"); // Wait until all changed theme. } break; } } @@ -367,6 +442,14 @@ void TabContainer::_on_theme_changed() { } } +void TabContainer::_on_mouse_exited() { + if (menu_hovered || highlight_arrow > -1) { + menu_hovered = false; + highlight_arrow = -1; + update(); + } +} + int TabContainer::_get_tab_width(int p_index) const { ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0); @@ -894,6 +977,7 @@ void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) { bool TabContainer::get_use_hidden_tabs_for_min_size() const { return use_hidden_tabs_for_min_size; } + void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input); @@ -925,6 +1009,7 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("_child_renamed_callback"), &TabContainer::_child_renamed_callback); ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed); + ClassDB::bind_method(D_METHOD("_on_mouse_exited"), &TabContainer::_on_mouse_exited); ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab); ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); @@ -947,14 +1032,17 @@ TabContainer::TabContainer() { first_tab_cache = 0; last_tab_cache = 0; buttons_visible_cache = false; + menu_hovered = false; + highlight_arrow = -1; tabs_ofs_cache = 0; current = 0; previous = 0; - mouse_x_cache = 0; align = ALIGN_CENTER; tabs_visible = true; popup = NULL; drag_to_rearrange_enabled = false; tabs_rearrange_group = -1; use_hidden_tabs_for_min_size = false; + + connect("mouse_exited", this, "_on_mouse_exited"); } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 0314f86837..0c17ebc3ae 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -46,7 +46,6 @@ public: }; private: - int mouse_x_cache; int first_tab_cache; int tabs_ofs_cache; int last_tab_cache; @@ -54,6 +53,8 @@ private: int previous; bool tabs_visible; bool buttons_visible_cache; + bool menu_hovered; + int highlight_arrow; TabAlign align; Control *_get_tab(int p_idx) const; int _get_top_margin() const; @@ -65,6 +66,7 @@ private: Vector<Control *> _get_tabs() const; int _get_tab_width(int p_index) const; void _on_theme_changed(); + void _on_mouse_exited(); void _update_current_tab(); protected: diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 7b0836cd28..c24f15384b 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -53,7 +53,7 @@ Size2 Tabs::get_minimum_size() const { ms.width += get_constant("hseparation"); } - ms.width += Math::ceil(font->get_string_size(tabs[i].text).width); + ms.width += Math::ceil(font->get_string_size(tabs[i].xl_text).width); if (tabs[i].disabled) ms.width += tab_disabled->get_minimum_size().width; @@ -223,15 +223,12 @@ void Tabs::_notification(int p_what) { switch (p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { + for (int i = 0; i < tabs.size(); ++i) { + tabs.write[i].xl_text = tr(tabs[i].text); + } minimum_size_changed(); update(); } break; - case NOTIFICATION_MOUSE_EXIT: { - rb_hover = -1; - cb_hover = -1; - hover = -1; - update(); - } break; case NOTIFICATION_RESIZED: { _update_cache(); _ensure_no_over_offset(); @@ -324,7 +321,7 @@ void Tabs::_notification(int p_what) { w += icon->get_width() + get_constant("hseparation"); } - font->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - font->get_height()) / 2 + font->get_ascent()), tabs[i].text, col, tabs[i].size_text); + font->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - font->get_height()) / 2 + font->get_ascent()), tabs[i].xl_text, col, tabs[i].size_text); w += tabs[i].size_text; @@ -441,6 +438,7 @@ void Tabs::set_tab_title(int p_tab, const String &p_title) { ERR_FAIL_INDEX(p_tab, tabs.size()); tabs.write[p_tab].text = p_title; + tabs.write[p_tab].xl_text = tr(p_title); update(); minimum_size_changed(); } @@ -549,7 +547,7 @@ void Tabs::_update_cache() { for (int i = 0; i < tabs.size(); i++) { tabs.write[i].ofs_cache = mw; tabs.write[i].size_cache = get_tab_width(i); - tabs.write[i].size_text = Math::ceil(font->get_string_size(tabs[i].text).width); + tabs.write[i].size_text = Math::ceil(font->get_string_size(tabs[i].xl_text).width); mw += tabs[i].size_cache; if (tabs[i].size_cache <= min_width || i == current) { size_fixed += tabs[i].size_cache; @@ -597,10 +595,20 @@ void Tabs::_update_cache() { } } +void Tabs::_on_mouse_exited() { + + rb_hover = -1; + cb_hover = -1; + hover = -1; + highlight_arrow = -1; + update(); +} + void Tabs::add_tab(const String &p_str, const Ref<Texture> &p_icon) { Tab t; t.text = p_str; + t.xl_text = tr(p_str); t.icon = p_icon; t.disabled = false; t.ofs_cache = 0; @@ -656,7 +664,7 @@ Variant Tabs::get_drag_data(const Point2 &p_point) { tf->set_texture(tabs[tab_over].icon); drag_preview->add_child(tf); } - Label *label = memnew(Label(tabs[tab_over].text)); + Label *label = memnew(Label(tabs[tab_over].xl_text)); drag_preview->add_child(label); if (!tabs[tab_over].right_button.is_null()) { TextureRect *tf = memnew(TextureRect); @@ -805,7 +813,7 @@ int Tabs::get_tab_width(int p_idx) const { x += get_constant("hseparation"); } - x += Math::ceil(font->get_string_size(tabs[p_idx].text).width); + x += Math::ceil(font->get_string_size(tabs[p_idx].xl_text).width); if (tabs[p_idx].disabled) x += tab_disabled->get_minimum_size().width; @@ -948,6 +956,7 @@ void Tabs::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input); ClassDB::bind_method(D_METHOD("_update_hover"), &Tabs::_update_hover); + ClassDB::bind_method(D_METHOD("_on_mouse_exited"), &Tabs::_on_mouse_exited); ClassDB::bind_method(D_METHOD("get_tab_count"), &Tabs::get_tab_count); ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &Tabs::set_current_tab); ClassDB::bind_method(D_METHOD("get_current_tab"), &Tabs::get_current_tab); @@ -1024,4 +1033,6 @@ Tabs::Tabs() { hover = -1; drag_to_rearrange_enabled = false; tabs_rearrange_group = -1; + + connect("mouse_exited", this, "_on_mouse_exited"); } diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index 7c54f1acf2..0edf2fedc1 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -58,6 +58,7 @@ private: struct Tab { String text; + String xl_text; Ref<Texture> icon; int ofs_cache; bool disabled; @@ -89,7 +90,7 @@ private: bool cb_pressing; CloseButtonDisplayPolicy cb_displaypolicy; - int hover; // hovered tab + int hover; // Hovered tab. int min_width; bool scrolling_enabled; bool drag_to_rearrange_enabled; @@ -101,6 +102,8 @@ private: void _update_hover(); void _update_cache(); + void _on_mouse_exited(); + protected: void _gui_input(const Ref<InputEvent> &p_event); void _notification(int p_what); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index d5f1d317c7..e2bb4e3e91 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -3965,7 +3965,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r_end_line, int *r_end_char) { - if (!setting_text) + if (!setting_text && idle_detect->is_inside_tree()) idle_detect->start(); if (undo_enabled) { @@ -4019,7 +4019,7 @@ void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) { - if (!setting_text) + if (!setting_text && idle_detect->is_inside_tree()) idle_detect->start(); String text; @@ -6110,7 +6110,7 @@ bool TextEdit::is_indent_using_spaces() const { } void TextEdit::set_indent_size(const int p_size) { - ERR_FAIL_COND(p_size <= 0); + ERR_FAIL_COND_MSG(p_size <= 0, "Indend size must be greater than 0."); indent_size = p_size; text.set_indent_size(p_size); diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index c534df5cbe..9b60a9d1c3 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -344,6 +344,9 @@ void TextureProgress::_notification(int p_what) { case FILL_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: { + if (nine_patch_stretch) + s = get_size(); + float val = get_as_ratio() * rad_max_degrees / 360; if (val == 1) { Rect2 region = Rect2(Point2(), s); @@ -384,7 +387,13 @@ void TextureProgress::_notification(int p_what) { draw_polygon(points, colors, uvs, progress); } if (Engine::get_singleton()->is_editor_hint()) { - Point2 p = progress->get_size(); + Point2 p; + + if (nine_patch_stretch) + p = get_size(); + else + p = progress->get_size(); + p.x *= get_relative_center().x; p.y *= get_relative_center().y; p = p.floor(); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 57663bbe82..c9d1295557 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -547,6 +547,11 @@ Ref<Texture> TreeItem::get_button(int p_column, int p_idx) const { ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), Ref<Texture>()); return cells[p_column].buttons[p_idx].texture; } +String TreeItem::get_button_tooltip(int p_column, int p_idx) const { + ERR_FAIL_INDEX_V(p_column, cells.size(), String()); + ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), String()); + return cells[p_column].buttons[p_idx].tooltip; +} int TreeItem::get_button_id(int p_column, int p_idx) const { ERR_FAIL_INDEX_V(p_column, cells.size(), -1); ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), -1); @@ -724,6 +729,43 @@ bool TreeItem::is_folding_disabled() const { return disable_folding; } +Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + + if (p_argcount < 1) { + r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = 0; + return Variant(); + } + + if (p_args[0]->get_type() != Variant::STRING) { + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::STRING; + return Variant(); + } + + StringName method = *p_args[0]; + + call_recursive(method, &p_args[1], p_argcount - 1, r_error); + return Variant(); +} + +void recursive_call_aux(TreeItem *p_item, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + if (!p_item) { + return; + } + p_item->call(p_method, p_args, p_argcount, r_error); + TreeItem *c = p_item->get_children(); + while (c) { + recursive_call_aux(c, p_method, p_args, p_argcount, r_error); + c = c->get_next(); + } +} + +void TreeItem::call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + recursive_call_aux(this, p_method, p_args, p_argcount, r_error); +} + void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell_mode", "column", "mode"), &TreeItem::set_cell_mode); @@ -785,6 +827,7 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_color", "column", "color"), &TreeItem::set_custom_color); ClassDB::bind_method(D_METHOD("clear_custom_color", "column"), &TreeItem::clear_custom_color); + ClassDB::bind_method(D_METHOD("get_custom_color", "column"), &TreeItem::get_custom_color); ClassDB::bind_method(D_METHOD("set_custom_bg_color", "column", "color", "just_outline"), &TreeItem::set_custom_bg_color, DEFVAL(false)); ClassDB::bind_method(D_METHOD("clear_custom_bg_color", "column"), &TreeItem::clear_custom_bg_color); @@ -795,6 +838,7 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("add_button", "column", "button", "button_idx", "disabled", "tooltip"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL("")); ClassDB::bind_method(D_METHOD("get_button_count", "column"), &TreeItem::get_button_count); + ClassDB::bind_method(D_METHOD("get_button_tooltip", "column", "button_idx"), &TreeItem::get_button_tooltip); ClassDB::bind_method(D_METHOD("get_button", "column", "button_idx"), &TreeItem::get_button); ClassDB::bind_method(D_METHOD("set_button", "column", "button_idx", "button"), &TreeItem::set_button); ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button); @@ -814,6 +858,14 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding); ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled); + { + MethodInfo mi; + mi.name = "call_recursive"; + mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_recursive", &TreeItem::_call_recursive_bind, mi); + } + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_folding"), "set_disable_folding", "is_folding_disabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_minimum_height", PROPERTY_HINT_RANGE, "0,1000,1"), "set_custom_minimum_height", "get_custom_minimum_height"); @@ -2546,7 +2598,9 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } else { Rect2 rect = get_selected()->get_meta("__focus_rect"); if (rect.has_point(Point2(b->get_position().x, b->get_position().y))) { - edit_selected(); + if (!edit_selected()) { + emit_signal("item_double_clicked"); + } } else { emit_signal("item_double_clicked"); } @@ -2669,11 +2723,21 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } break; case BUTTON_WHEEL_UP: { + double prev_value = v_scroll->get_value(); v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8); + if (v_scroll->get_value() != prev_value) { + accept_event(); + } + } break; case BUTTON_WHEEL_DOWN: { + double prev_value = v_scroll->get_value(); v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8); + if (v_scroll->get_value() != prev_value) { + accept_event(); + } + } break; } } @@ -2681,7 +2745,11 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid()) { + double prev_value = v_scroll->get_value(); v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8); + if (v_scroll->get_value() != prev_value) { + accept_event(); + } } } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index f12d8fc4d2..361830173b 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -172,6 +172,8 @@ protected: remove_child(Object::cast_to<TreeItem>(p_child)); } + Variant _call_recursive_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + public: /* cell mode */ void set_cell_mode(int p_column, TreeCellMode p_mode); @@ -201,6 +203,7 @@ public: void add_button(int p_column, const Ref<Texture> &p_button, int p_id = -1, bool p_disabled = false, const String &p_tooltip = ""); int get_button_count(int p_column) const; + String get_button_tooltip(int p_column, int p_idx) const; Ref<Texture> get_button(int p_column, int p_idx) const; int get_button_id(int p_column, int p_idx) const; void erase_button(int p_column, int p_idx); @@ -279,6 +282,8 @@ public: void set_disable_folding(bool p_disable); bool is_folding_disabled() const; + void call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); + ~TreeItem(); }; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index ba04cb69f2..7b6c90766f 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2171,7 +2171,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p if (get_filename() != "") { Ref<PackedScene> res = ResourceLoader::load(get_filename()); - ERR_FAIL_COND(res.is_null()); + ERR_FAIL_COND_MSG(res.is_null(), "Cannot load scene: " + get_filename()); node = res->instance(); ERR_FAIL_COND(!node); } else { diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 0465c9305b..3ee21ce38b 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -561,6 +561,8 @@ bool SceneTree::idle(float p_time) { E = N; } + flush_transform_notifications(); //additional transforms after timers update + _call_idle_callbacks(); #ifdef TOOLS_ENABLED diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index b5c82ce4e3..39c5759871 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -98,22 +98,22 @@ NodePath ViewportTexture::get_viewport_path_in_scene() const { int ViewportTexture::get_width() const { - ERR_FAIL_COND_V(!vp, 0); + ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it."); return vp->size.width; } int ViewportTexture::get_height() const { - ERR_FAIL_COND_V(!vp, 0); + ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it."); return vp->size.height; } Size2 ViewportTexture::get_size() const { - ERR_FAIL_COND_V(!vp, Size2()); + ERR_FAIL_COND_V_MSG(!vp, Size2(), "Viewport Texture must be set to use it."); return vp->size; } RID ViewportTexture::get_rid() const { - //ERR_FAIL_COND_V(!vp, RID()); + //ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it."); return proxy; } @@ -123,7 +123,7 @@ bool ViewportTexture::has_alpha() const { } Ref<Image> ViewportTexture::get_data() const { - ERR_FAIL_COND_V(!vp, Ref<Image>()); + ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it."); return VS::get_singleton()->texture_get_data(vp->texture_rid); } void ViewportTexture::set_flags(uint32_t p_flags) { @@ -1742,6 +1742,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { return; // no one gets the event if exclusive NO ONE } + if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN || mb->get_button_index() == BUTTON_WHEEL_LEFT || mb->get_button_index() == BUTTON_WHEEL_RIGHT) { + //cancel scroll wheel events, only clicks should trigger focus changes. + set_input_as_handled(); + return; + } + top->notification(Control::NOTIFICATION_MODAL_CLOSE); top->_modal_stack_remove(); top->hide(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 418ee6af0e..314fc721fc 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -139,7 +139,6 @@ #include "scene/resources/cylinder_shape.h" #include "scene/resources/default_theme/default_theme.h" #include "scene/resources/dynamic_font.h" -#include "scene/resources/dynamic_font_stb.h" #include "scene/resources/gradient.h" #include "scene/resources/height_map_shape.h" #include "scene/resources/line_shape_2d.h" diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index f68dc9af38..0dcc184a1d 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -763,7 +763,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1)); theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7)); - // colorPicker + // ColorPicker theme->set_constant("margin", "ColorPicker", 4 * scale); theme->set_constant("sv_width", "ColorPicker", 256 * scale); @@ -776,6 +776,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("color_hue", "ColorPicker", make_icon(color_picker_hue_png)); theme->set_icon("color_sample", "ColorPicker", make_icon(color_picker_sample_png)); theme->set_icon("preset_bg", "ColorPicker", make_icon(mini_checkerboard_png)); + theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png)); theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png)); diff --git a/scene/resources/default_theme/overbright_indicator.png b/scene/resources/default_theme/overbright_indicator.png Binary files differnew file mode 100644 index 0000000000..89f800c230 --- /dev/null +++ b/scene/resources/default_theme/overbright_indicator.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 11904b7aff..0d57fc6b14 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -218,6 +218,10 @@ static const unsigned char option_button_pressed_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x4a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x2f, 0x37, 0x46, 0x43, 0x4f, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x44, 0x50, 0x2a, 0x2a, 0x30, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x27, 0x3d, 0x3a, 0x45, 0x56, 0x52, 0x60, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x43, 0x40, 0x4c, 0x42, 0x40, 0x4b, 0x4c, 0x49, 0x56, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x3a, 0x38, 0x41, 0x36, 0x34, 0x3d, 0x44, 0x41, 0x4c, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x44, 0x42, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x50, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x3f, 0x3d, 0x47, 0x4f, 0x4c, 0x59, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x45, 0x42, 0x4d, 0x41, 0x3e, 0x49, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x52, 0x4e, 0x5c, 0x51, 0x4e, 0x5b, 0x5d, 0x59, 0x69, 0x10, 0x9d, 0xe0, 0x3c, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe6, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xcf, 0x3, 0x62, 0x4, 0x51, 0x10, 0x4, 0xd0, 0xaa, 0x31, 0x62, 0xdb, 0xb8, 0x49, 0x2e, 0x9e, 0x3b, 0xc4, 0xb6, 0x9d, 0xc5, 0x58, 0x1f, 0xc1, 0xd6, 0xe8, 0x77, 0xf7, 0x1b, 0x59, 0x6c, 0x2, 0x20, 0x37, 0xaa, 0xc5, 0x17, 0x7e, 0xc7, 0x62, 0x28, 0x45, 0x75, 0xfe, 0x6c, 0xe1, 0x4f, 0x68, 0x86, 0x41, 0x69, 0x44, 0x51, 0x4b, 0xb1, 0xce, 0xcc, 0xe4, 0x83, 0xd7, 0xb0, 0x48, 0x6b, 0x98, 0xe8, 0x9, 0x38, 0x70, 0x8b, 0xa, 0xcc, 0x12, 0x1a, 0xf0, 0x4d, 0xac, 0x87, 0xf3, 0x96, 0x6f, 0x8e, 0x5f, 0x56, 0xc0, 0x53, 0x20, 0x8f, 0xbf, 0xdb, 0x86, 0x58, 0x5b, 0x9, 0xbf, 0x47, 0x80, 0xa, 0x58, 0x1a, 0x38, 0xad, 0x9, 0x5f, 0xac, 0xe3, 0x20, 0xbc, 0x4b, 0x46, 0x4b, 0x0, 0x3a, 0x1a, 0x24, 0xd0, 0x69, 0x85, 0xc0, 0x63, 0x5, 0x60, 0x68, 0xf0, 0x36, 0x7f, 0xf3, 0xaa, 0xbe, 0xe1, 0x61, 0x81, 0x69, 0x5, 0x72, 0x5b, 0x83, 0xe4, 0x6a, 0x59, 0x16, 0xf7, 0x53, 0x47, 0x77, 0x8b, 0xad, 0x12, 0xe4, 0xb9, 0xa3, 0xc1, 0xe6, 0x83, 0x7b, 0x20, 0xd6, 0xb4, 0xe7, 0xbf, 0xed, 0xe1, 0x1a, 0xd8, 0xfa, 0xdf, 0xb9, 0x70, 0xb8, 0x21, 0xd6, 0xbb, 0x17, 0x1b, 0xe3, 0x4c, 0x6a, 0xb0, 0xbd, 0x25, 0x5, 0x3b, 0x5e, 0x7c, 0x21, 0xc0, 0xc2, 0x68, 0xee, 0xf1, 0xbc, 0x6, 0x46, 0xb1, 0xbd, 0x5e, 0x30, 0x5, 0x27, 0x19, 0x24, 0xb8, 0x61, 0x6e, 0xf8, 0xf5, 0xf7, 0xcd, 0x47, 0x16, 0xa0, 0x18, 0x13, 0x6a, 0x64, 0x7d, 0xff, 0x8f, 0x1e, 0x59, 0x84, 0xa2, 0x1b, 0x0, 0xe5, 0xe0, 0x4e, 0x46, 0x1d, 0x98, 0x92, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char overbright_indicator_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x1, 0x85, 0x69, 0x43, 0x43, 0x50, 0x49, 0x43, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x0, 0x0, 0x78, 0x9c, 0x7d, 0x91, 0x3d, 0x48, 0xc3, 0x40, 0x1c, 0xc5, 0x5f, 0x53, 0xa5, 0x2a, 0x2d, 0xe, 0x16, 0x11, 0x75, 0xc8, 0x50, 0x9d, 0x2c, 0x8a, 0x8a, 0x38, 0x6a, 0x15, 0x8a, 0x50, 0x21, 0xd4, 0xa, 0xad, 0x3a, 0x98, 0x5c, 0xfa, 0x21, 0x34, 0x69, 0x48, 0x52, 0x5c, 0x1c, 0x5, 0xd7, 0x82, 0x83, 0x1f, 0x8b, 0x55, 0x7, 0x17, 0x67, 0x5d, 0x1d, 0x5c, 0x5, 0x41, 0xf0, 0x3, 0xc4, 0xc5, 0xd5, 0x49, 0xd1, 0x45, 0x4a, 0xfc, 0x5f, 0x5a, 0x68, 0x11, 0xe3, 0xc1, 0x71, 0x3f, 0xde, 0xdd, 0x7b, 0xdc, 0xbd, 0x3, 0x84, 0x6a, 0x91, 0x69, 0x56, 0xdb, 0x18, 0xa0, 0xe9, 0xb6, 0x99, 0x8c, 0xc7, 0xc4, 0x74, 0x66, 0x45, 0xc, 0xbc, 0xa2, 0x13, 0x3, 0x8, 0xa1, 0x17, 0xa3, 0x32, 0xb3, 0x8c, 0x59, 0x49, 0x4a, 0xc0, 0x73, 0x7c, 0xdd, 0xc3, 0xc7, 0xd7, 0xbb, 0x28, 0xcf, 0xf2, 0x3e, 0xf7, 0xe7, 0x8, 0xa9, 0x59, 0x8b, 0x1, 0x3e, 0x91, 0x78, 0x86, 0x19, 0xa6, 0x4d, 0xbc, 0x4e, 0x3c, 0xb5, 0x69, 0x1b, 0x9c, 0xf7, 0x89, 0xc3, 0xac, 0x20, 0xab, 0xc4, 0xe7, 0xc4, 0x23, 0x26, 0x5d, 0x90, 0xf8, 0x91, 0xeb, 0x4a, 0x9d, 0xdf, 0x38, 0xe7, 0x5d, 0x16, 0x78, 0x66, 0xd8, 0x4c, 0x25, 0xe7, 0x88, 0xc3, 0xc4, 0x62, 0xbe, 0x85, 0x95, 0x16, 0x66, 0x5, 0x53, 0x23, 0x9e, 0x24, 0x8e, 0xa8, 0x9a, 0x4e, 0xf9, 0x42, 0xba, 0xce, 0x2a, 0xe7, 0x2d, 0xce, 0x5a, 0xb1, 0xcc, 0x1a, 0xf7, 0xe4, 0x2f, 0xc, 0x66, 0xf5, 0xe5, 0x25, 0xae, 0xd3, 0x1c, 0x44, 0x1c, 0xb, 0x58, 0x84, 0x4, 0x11, 0xa, 0xca, 0xd8, 0x40, 0x11, 0x36, 0xa2, 0xb4, 0xea, 0xa4, 0x58, 0x48, 0xd2, 0x7e, 0xcc, 0xc3, 0xdf, 0xef, 0xfa, 0x25, 0x72, 0x29, 0xe4, 0xda, 0x0, 0x23, 0xc7, 0x3c, 0x4a, 0xd0, 0x20, 0xbb, 0x7e, 0xf0, 0x3f, 0xf8, 0xdd, 0xad, 0x95, 0x9b, 0x18, 0xaf, 0x27, 0x5, 0x63, 0x40, 0xfb, 0x8b, 0xe3, 0x7c, 0xc, 0x1, 0x81, 0x5d, 0xa0, 0x56, 0x71, 0x9c, 0xef, 0x63, 0xc7, 0xa9, 0x9d, 0x0, 0xfe, 0x67, 0xe0, 0x4a, 0x6f, 0xfa, 0x4b, 0x55, 0x60, 0xfa, 0x93, 0xf4, 0x4a, 0x53, 0x8b, 0x1c, 0x1, 0xdd, 0xdb, 0xc0, 0xc5, 0x75, 0x53, 0x53, 0xf6, 0x80, 0xcb, 0x1d, 0xa0, 0xef, 0xc9, 0x90, 0x4d, 0xd9, 0x95, 0xfc, 0x34, 0x85, 0x5c, 0xe, 0x78, 0x3f, 0xa3, 0x6f, 0xca, 0x0, 0x3d, 0xb7, 0x40, 0xd7, 0x6a, 0xbd, 0xb7, 0xc6, 0x3e, 0x4e, 0x1f, 0x80, 0x14, 0x75, 0x95, 0xb8, 0x1, 0xe, 0xe, 0x81, 0xe1, 0x3c, 0x65, 0xaf, 0x79, 0xbc, 0xbb, 0xa3, 0xb5, 0xb7, 0x7f, 0xcf, 0x34, 0xfa, 0xfb, 0x1, 0x8e, 0x80, 0x72, 0xb2, 0xed, 0x78, 0xfa, 0x7b, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x15, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x63, 0x63, 0x66, 0x0, 0x0, 0x3, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4c, 0x39, 0x3a, 0xe, 0x0, 0x0, 0x0, 0x6, 0x74, 0x52, 0x4e, 0x53, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x80, 0x2c, 0x16, 0xc1, 0x6d, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6, 0x61, 0x66, 0xb8, 0x7d, 0x0, 0x0, 0x0, 0x32, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x0, 0x1, 0x46, 0x65, 0x17, 0x17, 0x30, 0x43, 0xc8, 0x4, 0x50, 0x88, 0x1c, 0x52, 0x1, 0x0, 0x2, 0x40, 0x14, 0xbb, 0x70, 0x8b, 0x40, 0xff, 0x2c, 0x18, 0xbe, 0xc6, 0xed, 0x8d, 0x42, 0xa1, 0x50, 0x28, 0x14, 0xa, 0x85, 0xbd, 0xb0, 0x13, 0xfc, 0x71, 0x1, 0xca, 0xf, 0x19, 0x62, 0x24, 0xd6, 0x8, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char panel_bg_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x25, 0x2a, 0x35, 0x32, 0x3b, 0x4a, 0x73, 0x58, 0x4a, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 2364a4a8a3..99a2881d58 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -130,7 +130,7 @@ Error DynamicFontAtSize::_load() { } else { FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open font file '" + font->font_path + "'."); size_t len = f->get_len(); _fontdata[font->font_path] = Vector<uint8_t>(); @@ -145,7 +145,7 @@ Error DynamicFontAtSize::_load() { if (font->font_mem == NULL && font->font_path != String()) { FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open font file '" + font->font_path + "'."); memset(&stream, 0, sizeof(FT_StreamRec)); stream.base = NULL; @@ -182,18 +182,17 @@ Error DynamicFontAtSize::_load() { //error = FT_New_Face( library, src_path.utf8().get_data(),0,&face ); if (error == FT_Err_Unknown_File_Format) { - ERR_EXPLAIN("Unknown font format."); + FT_Done_FreeType(library); + ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, "Unknown font format."); } else if (error) { - ERR_EXPLAIN("Error loading font."); FT_Done_FreeType(library); + ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, "Error loading font."); } - ERR_FAIL_COND_V(error, ERR_FILE_CANT_OPEN); - - if (FT_HAS_COLOR(face)) { + if (FT_HAS_COLOR(face) && face->num_fixed_sizes > 0) { int best_match = 0; int diff = ABS(id.size - ((int64_t)face->available_sizes[0].width)); scale_color_font = float(id.size) / face->available_sizes[0].width; diff --git a/scene/resources/dynamic_font_stb.cpp b/scene/resources/dynamic_font_stb.cpp deleted file mode 100644 index ccff617a16..0000000000 --- a/scene/resources/dynamic_font_stb.cpp +++ /dev/null @@ -1,524 +0,0 @@ -/*************************************************************************/ -/* dynamic_font_stb.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "dynamic_font_stb.h" - -#ifndef FREETYPE_ENABLED - -#define STB_TRUETYPE_IMPLEMENTATION -#include "core/os/file_access.h" - -void DynamicFontData::lock() { - - fr = font_data.read(); - - if (fr.ptr() != last_data_ptr) { - - last_data_ptr = fr.ptr(); - - if (!stbtt_InitFont(&info, last_data_ptr, 0)) { - valid = false; - } else { - valid = true; - } - - last_data_ptr = fr.ptr(); - } -} - -void DynamicFontData::unlock() { - - fr.release(); -} - -void DynamicFontData::set_font_data(const PoolVector<uint8_t> &p_font) { - //clear caches and stuff - ERR_FAIL_COND(font_data.size()); - font_data = p_font; - - lock(); - - if (valid) { - stbtt_GetFontVMetrics(&info, &ascent, &descent, &linegap); - descent = -descent + linegap; - - for (int i = 32; i < 1024; i++) { - for (int j = 32; j < 1024; j++) { - - int kern = stbtt_GetCodepointKernAdvance(&info, i, j); - if (kern != 0) { - KerningPairKey kpk; - kpk.A = i; - kpk.B = j; - kerning_map[kpk] = kern; - } - } - } - } - - unlock(); - //clear existing stuff - - ERR_FAIL_COND(!valid); -} - -Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { - - ERR_FAIL_COND_V(!valid, Ref<DynamicFontAtSize>()); - - if (size_cache.has(p_size)) { - return Ref<DynamicFontAtSize>(size_cache[p_size]); - } - - Ref<DynamicFontAtSize> dfas; - dfas.instance(); - - dfas->font = Ref<DynamicFontData>(this); - - size_cache[p_size] = dfas.ptr(); - - dfas->size = p_size; - - lock(); - - dfas->scale = stbtt_ScaleForPixelHeight(&info, p_size); - - unlock(); - - return dfas; -} - -DynamicFontData::DynamicFontData() { - last_data_ptr = NULL; - valid = false; -} - -DynamicFontData::~DynamicFontData() { -} - -//////////////////// - -float DynamicFontAtSize::get_height() const { - - return (font->ascent + font->descent) * scale; -} - -float DynamicFontAtSize::get_ascent() const { - - return font->ascent * scale; -} -float DynamicFontAtSize::get_descent() const { - - return font->descent * scale; -} - -Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next) const { - - const_cast<DynamicFontAtSize *>(this)->_update_char(p_char); - - const Character *c = char_map.getptr(p_char); - ERR_FAIL_COND_V(!c, Size2()); - - Size2 ret(c->advance, get_height()); - - if (p_next) { - DynamicFontData::KerningPairKey kpk; - kpk.A = p_char; - kpk.B = p_next; - - const Map<DynamicFontData::KerningPairKey, int>::Element *K = font->kerning_map.find(kpk); - if (K) { - ret.x += K->get() * scale; - } - } - - return ret; -} - -float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const { - - const_cast<DynamicFontAtSize *>(this)->_update_char(p_char); - - const Character *c = char_map.getptr(p_char); - - if (!c) { - return 0; - } - - if (!p_outline) { - Point2 cpos = p_pos; - cpos.x += c->h_align; - cpos.y -= get_ascent(); - cpos.y += c->v_align; - ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0); - if (c->texture_idx != -1) - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect, p_modulate); - } - - //textures[c->texture_idx].texture->draw(p_canvas_item,Vector2()); - - float ret = c->advance; - if (p_next) { - DynamicFontData::KerningPairKey kpk; - kpk.A = p_char; - kpk.B = p_next; - - const Map<DynamicFontData::KerningPairKey, int>::Element *K = font->kerning_map.find(kpk); - if (K) { - ret += K->get() * scale; - } - } - - return ret; -} - -void DynamicFontAtSize::_update_char(CharType p_char) { - - if (char_map.has(p_char)) - return; - - font->lock(); - - int w, h, xofs, yofs; - unsigned char *cpbitmap = stbtt_GetCodepointBitmap(&font->info, scale, scale, p_char, &w, &h, &xofs, &yofs); - - if (!cpbitmap) { - //no glyph - - int advance; - stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); - Character ch; - ch.texture_idx = -1; - ch.advance = advance * scale; - ch.h_align = 0; - ch.v_align = 0; - - char_map[p_char] = ch; - - font->unlock(); - - return; - } - - int mw = w + rect_margin * 2; - int mh = h + rect_margin * 2; - - if (mw > 4096 || mh > 4096) { - - stbtt_FreeBitmap(cpbitmap, NULL); - font->unlock(); - ERR_FAIL_COND(mw > 4096); - ERR_FAIL_COND(mh > 4096); - } - - //find a texture to fit this... - - int tex_index = -1; - int tex_x = 0; - int tex_y = 0; - - for (int i = 0; i < textures.size(); i++) { - - CharTexture &ct = textures[i]; - - if (mw > ct.texture_size || mh > ct.texture_size) //too big for this texture - continue; - - tex_y = 0x7FFFFFFF; - tex_x = 0; - - for (int j = 0; j < ct.texture_size - mw; j++) { - - int max_y = 0; - - for (int k = j; k < j + mw; k++) { - - int y = ct.offsets[k]; - if (y > max_y) - max_y = y; - } - - if (max_y < tex_y) { - tex_y = max_y; - tex_x = j; - } - } - - if (tex_y == 0x7FFFFFFF || tex_y + mh > ct.texture_size) - continue; //fail, could not fit it here - - tex_index = i; - break; - } - - if (tex_index == -1) { - //could not find texture to fit, create one - tex_x = 0; - tex_y = 0; - - int texsize = MAX(size * 8, 256); - if (mw > texsize) - texsize = mw; //special case, adapt to it? - if (mh > texsize) - texsize = mh; //special case, adapt to it? - - texsize = next_power_of_2(texsize); - - texsize = MIN(texsize, 4096); - - CharTexture tex; - tex.texture_size = texsize; - tex.imgdata.resize(texsize * texsize * 2); //grayscale alpha - - { - //zero texture - PoolVector<uint8_t>::Write w = tex.imgdata.write(); - ERR_FAIL_COND(texsize * texsize * 2 > tex.imgdata.size()); - for (int i = 0; i < texsize * texsize * 2; i++) { - w[i] = 0; - } - } - tex.offsets.resize(texsize); - for (int i = 0; i < texsize; i++) //zero offsets - tex.offsets[i] = 0; - - textures.push_back(tex); - tex_index = textures.size() - 1; - } - - //fit character in char texture - - CharTexture &tex = textures[tex_index]; - - { - PoolVector<uint8_t>::Write wr = tex.imgdata.write(); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - - int ofs = ((i + tex_y + rect_margin) * tex.texture_size + j + tex_x + rect_margin) * 2; - ERR_FAIL_COND(ofs >= tex.imgdata.size()); - wr[ofs + 0] = 255; //grayscale as 1 - wr[ofs + 1] = cpbitmap[i * w + j]; //alpha as 0 - } - } - } - - //blit to image and texture - { - Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, Image::FORMAT_LA8, tex.imgdata)); - - if (tex.texture.is_null()) { - tex.texture.instance(); - tex.texture->create_from_image(img, Texture::FLAG_FILTER); - } else { - tex.texture->set_data(img); //update - } - } - - // update height array - - for (int k = tex_x; k < tex_x + mw; k++) { - - tex.offsets[k] = tex_y + mh; - } - - int advance; - stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); - - Character chr; - chr.h_align = xofs; - chr.v_align = yofs + get_ascent(); - chr.advance = advance * scale; - chr.texture_idx = tex_index; - - chr.rect = Rect2(tex_x + rect_margin, tex_y + rect_margin, w, h); - - char_map[p_char] = chr; - - stbtt_FreeBitmap(cpbitmap, NULL); - - font->unlock(); -} - -DynamicFontAtSize::DynamicFontAtSize() { - - rect_margin = 1; -} - -DynamicFontAtSize::~DynamicFontAtSize() { - - ERR_FAIL_COND(!font.ptr()); - font->size_cache.erase(size); -} - -///////////////////////// - -void DynamicFont::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_font_data", "data"), &DynamicFont::set_font_data); - ClassDB::bind_method(D_METHOD("get_font_data"), &DynamicFont::get_font_data); - - ClassDB::bind_method(D_METHOD("set_size", "data"), &DynamicFont::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &DynamicFont::get_size); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "font/size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font/font", PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData"), "set_font_data", "get_font_data"); -} - -void DynamicFont::set_font_data(const Ref<DynamicFontData> &p_data) { - - data = p_data; - data_at_size = data->_get_dynamic_font_at_size(size); -} - -Ref<DynamicFontData> DynamicFont::get_font_data() const { - - return data; -} - -void DynamicFont::set_size(int p_size) { - - if (size == p_size) - return; - size = p_size; - ERR_FAIL_COND(p_size < 1); - if (!data.is_valid()) - return; - data_at_size = data->_get_dynamic_font_at_size(size); -} -int DynamicFont::get_size() const { - - return size; -} - -float DynamicFont::get_height() const { - - if (!data_at_size.is_valid()) - return 1; - - return data_at_size->get_height(); -} - -float DynamicFont::get_ascent() const { - - if (!data_at_size.is_valid()) - return 1; - - return data_at_size->get_ascent(); -} - -float DynamicFont::get_descent() const { - - if (!data_at_size.is_valid()) - return 1; - - return data_at_size->get_descent(); -} - -Size2 DynamicFont::get_char_size(CharType p_char, CharType p_next) const { - - if (!data_at_size.is_valid()) - return Size2(1, 1); - - return data_at_size->get_char_size(p_char, p_next); -} - -bool DynamicFont::is_distance_field_hint() const { - - return false; -} - -float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const { - - if (!data_at_size.is_valid()) - return 0; - - return data_at_size->draw_char(p_canvas_item, p_pos, p_char, p_next, p_modulate, p_outline); -} - -DynamicFont::DynamicFont() { - - size = 16; -} - -DynamicFont::~DynamicFont() { -} - -///////////////////////// - -RES ResourceFormatLoaderDynamicFont::load(const String &p_path, const String &p_original_path, Error *r_error) { - - if (r_error) - *r_error = ERR_FILE_CANT_OPEN; - - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, RES()); - - PoolVector<uint8_t> data; - - data.resize(f->get_len()); - - ERR_FAIL_COND_V(data.size() == 0, RES()); - - { - PoolVector<uint8_t>::Write w = data.write(); - f->get_buffer(w.ptr(), data.size()); - } - - Ref<DynamicFontData> dfd; - dfd.instance(); - dfd->set_font_data(data); - - if (r_error) - *r_error = OK; - - return dfd; -} - -void ResourceFormatLoaderDynamicFont::get_recognized_extensions(List<String> *p_extensions) const { - - p_extensions->push_back("ttf"); -} - -bool ResourceFormatLoaderDynamicFont::handles_type(const String &p_type) const { - - return (p_type == "DynamicFontData"); -} - -String ResourceFormatLoaderDynamicFont::get_resource_type(const String &p_path) const { - - String el = p_path.get_extension().to_lower(); - if (el == "ttf") - return "DynamicFontData"; - return ""; -} - -#endif diff --git a/scene/resources/dynamic_font_stb.h b/scene/resources/dynamic_font_stb.h deleted file mode 100644 index caee6e7e32..0000000000 --- a/scene/resources/dynamic_font_stb.h +++ /dev/null @@ -1,191 +0,0 @@ -/*************************************************************************/ -/* dynamic_font_stb.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef DYNAMICFONT_STB_H -#define DYNAMICFONT_STB_H - -#ifndef FREETYPE_ENABLED - -#include "core/io/resource_loader.h" -#include "font.h" - -#include "thirdparty/misc/stb_truetype.h" - -class DynamicFontAtSize; -class DynamicFont; - -class DynamicFontData : public Resource { - - GDCLASS(DynamicFontData, Resource); - - bool valid; - - PoolVector<uint8_t> font_data; - PoolVector<uint8_t>::Read fr; - const uint8_t *last_data_ptr; - - struct KerningPairKey { - - union { - struct { - uint32_t A, B; - }; - - uint64_t pair; - }; - - _FORCE_INLINE_ bool operator<(const KerningPairKey &p_r) const { return pair < p_r.pair; } - }; - - Map<KerningPairKey, int> kerning_map; - - Map<int, DynamicFontAtSize *> size_cache; - - friend class DynamicFontAtSize; - - stbtt_fontinfo info; - int ascent; - int descent; - int linegap; - - void lock(); - void unlock(); - - friend class DynamicFont; - - Ref<DynamicFontAtSize> _get_dynamic_font_at_size(int p_size); - -public: - void set_font_data(const PoolVector<uint8_t> &p_font); - DynamicFontData(); - ~DynamicFontData(); -}; - -class DynamicFontAtSize : public Reference { - - GDCLASS(DynamicFontAtSize, Reference); - - int rect_margin; - - struct CharTexture { - - PoolVector<uint8_t> imgdata; - int texture_size; - Vector<int> offsets; - Ref<ImageTexture> texture; - }; - - Vector<CharTexture> textures; - - struct Character { - - int texture_idx; - Rect2 rect; - float v_align; - float h_align; - float advance; - - Character() { - texture_idx = 0; - v_align = 0; - } - }; - - HashMap<CharType, Character> char_map; - - _FORCE_INLINE_ void _update_char(CharType p_char); - - friend class DynamicFontData; - Ref<DynamicFontData> font; - float scale; - int size; - -protected: -public: - float get_height() const; - - float get_ascent() const; - float get_descent() const; - - Size2 get_char_size(CharType p_char, CharType p_next = 0) const; - - float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const; - - DynamicFontAtSize(); - ~DynamicFontAtSize(); -}; - -/////////////// - -class DynamicFont : public Font { - - GDCLASS(DynamicFont, Font); - - Ref<DynamicFontData> data; - Ref<DynamicFontAtSize> data_at_size; - int size; - -protected: - static void _bind_methods(); - -public: - void set_font_data(const Ref<DynamicFontData> &p_data); - Ref<DynamicFontData> get_font_data() const; - - void set_size(int p_size); - int get_size() const; - - virtual float get_height() const; - - virtual float get_ascent() const; - virtual float get_descent() const; - - virtual Size2 get_char_size(CharType p_char, CharType p_next = 0) const; - - virtual bool is_distance_field_hint() const; - - virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const; - - DynamicFont(); - ~DynamicFont(); -}; - -///////////// - -class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader { -public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; -}; - -#endif -#endif // DYNAMICFONT_H diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index afb7f1102b..bc96b5e9f3 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -354,10 +354,6 @@ void Environment::_validate_property(PropertyInfo &property) const { "tonemap_", "ss_reflections_", "ssao_", - "dof_blur_far_", - "dof_blur_near_", - "glow_", - "adjustment_", NULL }; diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index cff77acdd7..124e4d37e6 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -96,7 +96,7 @@ void Font::_bind_methods() { ClassDB::bind_method(D_METHOD("get_height"), &Font::get_height); ClassDB::bind_method(D_METHOD("is_distance_field_hint"), &Font::is_distance_field_hint); ClassDB::bind_method(D_METHOD("get_string_size", "string"), &Font::get_string_size); - ClassDB::bind_method(D_METHOD("get_wordwrap_string_size", "string", "p_width"), &Font::get_wordwrap_string_size); + ClassDB::bind_method(D_METHOD("get_wordwrap_string_size", "string", "width"), &Font::get_wordwrap_string_size); ClassDB::bind_method(D_METHOD("has_outline"), &Font::has_outline); ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "position", "char", "next", "modulate", "outline"), &Font::draw_char, DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(false)); ClassDB::bind_method(D_METHOD("update_changes"), &Font::update_changes); @@ -358,7 +358,7 @@ float BitmapFont::get_descent() const { void BitmapFont::add_texture(const Ref<Texture> &p_texture) { - ERR_FAIL_COND(p_texture.is_null()); + ERR_FAIL_COND_MSG(p_texture.is_null(), "It's not a reference to a valid Texture object."); textures.push_back(p_texture); } diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index d40a5dee2e..f04af29761 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "mesh_library.h" +#include "core/engine.h" bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) { @@ -117,7 +118,7 @@ void MeshLibrary::create_item(int p_item) { void MeshLibrary::set_item_name(int p_item, const String &p_name) { - ERR_FAIL_COND(!item_map.has(p_item)); + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].name = p_name; emit_changed(); _change_notify(); @@ -125,7 +126,7 @@ void MeshLibrary::set_item_name(int p_item, const String &p_name) { void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { - ERR_FAIL_COND(!item_map.has(p_item)); + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].mesh = p_mesh; notify_change_to_owners(); emit_changed(); @@ -134,7 +135,7 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) { - ERR_FAIL_COND(!item_map.has(p_item)); + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].shapes = p_shapes; _change_notify(); notify_change_to_owners(); @@ -144,7 +145,7 @@ void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh) { - ERR_FAIL_COND(!item_map.has(p_item)); + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].navmesh = p_navmesh; _change_notify(); notify_change_to_owners(); @@ -154,7 +155,7 @@ void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navm void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) { - ERR_FAIL_COND(!item_map.has(p_item)); + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].navmesh_transform = p_transform; notify_change_to_owners(); emit_changed(); @@ -163,7 +164,7 @@ void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_tran void MeshLibrary::set_item_preview(int p_item, const Ref<Texture> &p_preview) { - ERR_FAIL_COND(!item_map.has(p_item)); + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].preview = p_preview; emit_changed(); _change_notify(); @@ -171,37 +172,42 @@ void MeshLibrary::set_item_preview(int p_item, const Ref<Texture> &p_preview) { String MeshLibrary::get_item_name(int p_item) const { - ERR_FAIL_COND_V(!item_map.has(p_item), ""); + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), "", "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); return item_map[p_item].name; } Ref<Mesh> MeshLibrary::get_item_mesh(int p_item) const { - ERR_FAIL_COND_V(!item_map.has(p_item), Ref<Mesh>()); + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<Mesh>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); return item_map[p_item].mesh; } Vector<MeshLibrary::ShapeData> MeshLibrary::get_item_shapes(int p_item) const { - ERR_FAIL_COND_V(!item_map.has(p_item), Vector<ShapeData>()); + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Vector<ShapeData>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); return item_map[p_item].shapes; } Ref<NavigationMesh> MeshLibrary::get_item_navmesh(int p_item) const { - ERR_FAIL_COND_V(!item_map.has(p_item), Ref<NavigationMesh>()); + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<NavigationMesh>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); return item_map[p_item].navmesh; } Transform MeshLibrary::get_item_navmesh_transform(int p_item) const { - ERR_FAIL_COND_V(!item_map.has(p_item), Transform()); + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); return item_map[p_item].navmesh_transform; } Ref<Texture> MeshLibrary::get_item_preview(int p_item) const { - ERR_FAIL_COND_V(!item_map.has(p_item), Ref<Texture>()); + if (!Engine::get_singleton()->is_editor_hint()) { + ERR_PRINT("MeshLibrary item previews are only generated in an editor context, which means they aren't available in a running project."); + return Ref<Texture>(); + } + + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<Texture>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); return item_map[p_item].preview; } @@ -211,7 +217,7 @@ bool MeshLibrary::has_item(int p_item) const { } void MeshLibrary::remove_item(int p_item) { - ERR_FAIL_COND(!item_map.has(p_item)); + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map.erase(p_item); notify_change_to_owners(); _change_notify(); diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index dc6ef2b49c..969743f78c 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -567,8 +567,8 @@ void ParticlesMaterial::_update_shader() { } } //scale by scale - code += " float base_scale = mix(scale * tex_scale, 1.0, scale_random * scale_rand);\n"; - code += " if (base_scale == 0.0) {\n"; + code += " float base_scale = tex_scale * mix(scale, 1.0, scale_random * scale_rand);\n"; + code += " if (base_scale < 0.000001) {\n"; code += " base_scale = 0.000001;\n"; code += " }\n"; if (trail_size_modifier.is_valid()) { diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index 52fc21ac11..bd3236cb5b 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -466,11 +466,11 @@ Dictionary PolygonPathFinder::_get_data() const { PoolVector<Vector2> p; PoolVector<int> ind; Array connections; - p.resize(points.size() - 2); - connections.resize(points.size() - 2); + p.resize(MAX(0, points.size() - 2)); + connections.resize(MAX(0, points.size() - 2)); ind.resize(edges.size() * 2); PoolVector<float> penalties; - penalties.resize(points.size() - 2); + penalties.resize(MAX(0, points.size() - 2)); { PoolVector<Vector2>::Write wp = p.write(); PoolVector<float>::Write pw = penalties.write(); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 1c41f30a94..baffc1396d 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1225,7 +1225,7 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoaderText::load_interactive(const Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - ERR_FAIL_COND_V(err != OK, Ref<ResourceInteractiveLoader>()); + ERR_FAIL_COND_V_MSG(err != OK, Ref<ResourceInteractiveLoader>(), "Cannot open file '" + p_path + "'."); Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); String path = p_original_path != "" ? p_original_path : p_path; @@ -1321,7 +1321,7 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, Error err; FileAccess *f = FileAccess::open(p_src_path, FileAccess::READ, &err); - ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'."); Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); const String &path = p_src_path; @@ -1481,7 +1481,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r Error err; f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(err, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(err, ERR_CANT_OPEN, "Cannot save file '" + p_path + "'."); FileAccessRef _fref(f); local_path = ProjectSettings::get_singleton()->localize_path(p_path); diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 89570beb5f..57e2470164 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -222,10 +222,7 @@ Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resourc Error err; FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); - if (err) { - - ERR_FAIL_COND_V(err, err); - } + ERR_FAIL_COND_V_MSG(err, err, "Cannot save shader '" + p_path + "'."); file->store_string(source); if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp index 8446e2f249..98c114e0e6 100644 --- a/scene/resources/skin.cpp +++ b/scene/resources/skin.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #include "skin.h" void Skin::set_bind_count(int p_size) { diff --git a/scene/resources/skin.h b/scene/resources/skin.h index a7e55bfa89..7dd02eca5d 100644 --- a/scene/resources/skin.h +++ b/scene/resources/skin.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #ifndef SKIN_H #define SKIN_H diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp index b84f3f1f9e..3faedc883d 100644 --- a/scene/resources/text_file.cpp +++ b/scene/resources/text_file.cpp @@ -53,9 +53,8 @@ Error TextFile::load_text(const String &p_path) { PoolVector<uint8_t> sourcef; Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (err) { - ERR_FAIL_COND_V(err, err); - } + + ERR_FAIL_COND_V_MSG(err, err, "Cannot open TextFile '" + p_path + "'."); int len = f->get_len(); sourcef.resize(len + 1); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 5d1c35dfbf..c2e2f85723 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -176,7 +176,7 @@ void ImageTexture::_reload_hook(const RID &p_hook) { img.instance(); Error err = ImageLoader::load_image(path, img); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Cannot load image from path '" + path + "'."); VisualServer::get_singleton()->texture_set_data(texture, img); @@ -2362,7 +2362,7 @@ RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String } FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, RES()); + ERR_FAIL_COND_V_MSG(!f, RES(), "Cannot open file '" + p_path + "'."); uint8_t header[5] = { 0, 0, 0, 0, 0 }; f->get_buffer(header, 4); @@ -2379,7 +2379,7 @@ RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String } } else { - ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture file format: " + String((const char *)header) + "."); + ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture file format '" + String((const char *)header) + "'."); } int tw = f->get_32(); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index f5ea6adc85..58bbf86241 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -103,6 +103,10 @@ String VisualShaderNode::get_warning(Shader::Mode p_mode, VisualShader::Type p_t return String(); } +String VisualShaderNode::get_input_port_default_hint(int p_port) const { + return ""; +} + void VisualShaderNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview); @@ -122,7 +126,8 @@ void VisualShaderNode::_bind_methods() { BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR); BIND_ENUM_CONSTANT(PORT_TYPE_BOOLEAN); BIND_ENUM_CONSTANT(PORT_TYPE_TRANSFORM); - BIND_ENUM_CONSTANT(PORT_TYPE_ICON_COLOR); + BIND_ENUM_CONSTANT(PORT_TYPE_SAMPLER); + BIND_ENUM_CONSTANT(PORT_TYPE_MAX); } VisualShaderNode::VisualShaderNode() { @@ -1058,7 +1063,15 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui String src_var = "n_out" + itos(from_node) + "p" + itos(from_port); - if (in_type == out_type) { + if (in_type == VisualShaderNode::PORT_TYPE_SAMPLER && out_type == VisualShaderNode::PORT_TYPE_SAMPLER) { + + VisualShaderNodeUniform *uniform = (VisualShaderNodeUniform *)graph[type].nodes[from_node].node.ptr(); + if (uniform) { + inputs[i] = uniform->get_uniform_name(); + } else { + inputs[i] = ""; + } + } else if (in_type == out_type) { inputs[i] = src_var; } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_VECTOR) { inputs[i] = "dot(" + src_var + ",vec3(0.333333,0.333333,0.333333))"; @@ -1139,12 +1152,16 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui global_code += vsnode->generate_global(get_mode(), type, node); - if (!r_classes.has(vsnode->get_class_name())) { + String class_name = vsnode->get_class_name(); + if (class_name == "VisualShaderNodeCustom") { + class_name = vsnode->get_script_instance()->get_script()->get_language()->get_global_class_name(vsnode->get_script_instance()->get_script()->get_path()); + } + if (!r_classes.has(class_name)) { global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node); for (int i = 0; i < TYPE_MAX; i++) { global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node); } - r_classes.insert(vsnode->get_class_name()); + r_classes.insert(class_name); } } @@ -2207,7 +2224,7 @@ void VisualShaderNodeGroupBase::clear_output_ports() { void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) { ERR_FAIL_COND(!has_input_port(p_id)); - ERR_FAIL_COND(p_type < 0 || p_type > PORT_TYPE_TRANSFORM); + ERR_FAIL_COND(p_type < 0 || p_type >= PORT_TYPE_MAX); if (input_ports[p_id].type == p_type) return; @@ -2273,7 +2290,7 @@ String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const { void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) { ERR_FAIL_COND(!has_output_port(p_id)); - ERR_FAIL_COND(p_type < 0 || p_type > PORT_TYPE_TRANSFORM); + ERR_FAIL_COND(p_type < 0 || p_type >= PORT_TYPE_MAX); if (output_ports[p_id].type == p_type) return; @@ -2410,10 +2427,10 @@ void VisualShaderNodeGroupBase::_bind_methods() { ClassDB::bind_method(D_METHOD("has_output_port", "id"), &VisualShaderNodeGroupBase::has_output_port); ClassDB::bind_method(D_METHOD("clear_output_ports"), &VisualShaderNodeGroupBase::clear_output_ports); - ClassDB::bind_method(D_METHOD("set_input_port_name"), &VisualShaderNodeGroupBase::set_input_port_name); - ClassDB::bind_method(D_METHOD("set_input_port_type"), &VisualShaderNodeGroupBase::set_input_port_type); - ClassDB::bind_method(D_METHOD("set_output_port_name"), &VisualShaderNodeGroupBase::set_output_port_name); - ClassDB::bind_method(D_METHOD("set_output_port_type"), &VisualShaderNodeGroupBase::set_output_port_type); + ClassDB::bind_method(D_METHOD("set_input_port_name", "id", "name"), &VisualShaderNodeGroupBase::set_input_port_name); + ClassDB::bind_method(D_METHOD("set_input_port_type", "id", "type"), &VisualShaderNodeGroupBase::set_input_port_type); + ClassDB::bind_method(D_METHOD("set_output_port_name", "id", "name"), &VisualShaderNodeGroupBase::set_output_port_name); + ClassDB::bind_method(D_METHOD("set_output_port_type", "id", "type"), &VisualShaderNodeGroupBase::set_output_port_type); ClassDB::bind_method(D_METHOD("get_free_input_port_id"), &VisualShaderNodeGroupBase::get_free_input_port_id); ClassDB::bind_method(D_METHOD("get_free_output_port_id"), &VisualShaderNodeGroupBase::get_free_output_port_id); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 45beb8e6ca..8b6b659836 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -184,7 +184,8 @@ public: PORT_TYPE_VECTOR, PORT_TYPE_BOOLEAN, PORT_TYPE_TRANSFORM, - PORT_TYPE_ICON_COLOR // just a hint for node tree icons, do not use it as actual port type ! + PORT_TYPE_SAMPLER, + PORT_TYPE_MAX, }; virtual String get_caption() const = 0; @@ -200,6 +201,8 @@ public: virtual PortType get_output_port_type(int p_port) const = 0; virtual String get_output_port_name(int p_port) const = 0; + virtual String get_input_port_default_hint(int p_port) const; + void set_output_port_for_preview(int p_index); int get_output_port_for_preview() const; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index b7173b157e..2e58c512b8 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -361,15 +361,35 @@ String VisualShaderNodeTexture::get_caption() const { } int VisualShaderNodeTexture::get_input_port_count() const { - return 2; + return 3; } VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_input_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; + + switch (p_port) { + case 0: + return PORT_TYPE_VECTOR; + case 1: + return PORT_TYPE_SCALAR; + case 2: + return PORT_TYPE_SAMPLER; + default: + return PORT_TYPE_SCALAR; + } } String VisualShaderNodeTexture::get_input_port_name(int p_port) const { - return p_port == 0 ? "uv" : "lod"; + + switch (p_port) { + case 0: + return "uv"; + case 1: + return "lod"; + case 2: + return "sampler"; + default: + return ""; + } } int VisualShaderNodeTexture::get_output_port_count() const { @@ -388,6 +408,13 @@ String VisualShaderNodeTexture::get_output_port_name(int p_port) const { return p_port == 0 ? "rgb" : "alpha"; } +String VisualShaderNodeTexture::get_input_port_default_hint(int p_port) const { + if (p_port == 0) { + return "UV.xy"; + } + return ""; +} + static String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name) { static const char *typepf[VisualShader::TYPE_MAX] = { "vtx", "frg", "lgt" }; @@ -424,10 +451,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (source == SOURCE_TEXTURE) { String id = make_unique_id(p_type, p_id, "tex"); String code; - if (p_input_vars[0] == String()) { //none bound, do nothing - - code += "\tvec4 " + id + "_read = vec4(0.0);\n"; + if (p_input_vars[0] == String()) { // Use UV by default. + code += "\tvec4 " + id + "_read = texture( " + id + " , UV.xy );\n"; } else if (p_input_vars[1] == String()) { //no lod code += "\tvec4 " + id + "_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n"; @@ -440,12 +466,35 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: return code; } + if (source == SOURCE_PORT) { + String id = p_input_vars[2]; + String code; + if (id == String()) { + code += "\tvec4 " + id + "_tex_read = vec4(0.0);\n"; + } else { + if (p_input_vars[0] == String()) { // Use UV by default. + + code += "\tvec4 " + id + "_tex_read = texture( " + id + " , UV.xy );\n"; + + } else if (p_input_vars[1] == String()) { + //no lod + code += "\tvec4 " + id + "_tex_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n"; + } else { + code += "\tvec4 " + id + "_tex_read = textureLod( " + id + " , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n"; + } + + code += "\t" + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n"; + code += "\t" + p_output_vars[1] + " = " + id + "_tex_read.a;\n"; + } + return code; + } + if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { String code = "\t{\n"; - if (p_input_vars[0] == String() || p_for_preview) { //none bound, do nothing + if (p_input_vars[0] == String() || p_for_preview) { // Use UV by default. - code += "\t\tvec4 _tex_read = vec4(0.0);\n"; + code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , UV.xy, 0.0 );\n"; } else if (p_input_vars[1] == String()) { //no lod @@ -463,9 +512,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { String code = "\t{\n"; - if (p_input_vars[0] == String()) { //none bound, do nothing + if (p_input_vars[0] == String()) { // Use UV by default. - code += "\t\tvec4 _tex_read = vec4(0.0);\n"; + code += "\t\tvec4 _tex_read = texture( TEXTURE , UV.xy );\n"; } else if (p_input_vars[1] == String()) { //no lod @@ -483,9 +532,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { String code = "\t{\n"; - if (p_input_vars[0] == String()) { //none bound, do nothing + if (p_input_vars[0] == String()) { // Use UV by default. - code += "\t\tvec4 _tex_read = vec4(0.0);\n"; + code += "\t\tvec4 _tex_read = texture( NORMAL_TEXTURE , UV.xy );\n"; } else if (p_input_vars[1] == String()) { //no lod @@ -513,9 +562,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (source == SOURCE_DEPTH && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) { String code = "\t{\n"; - if (p_input_vars[0] == String()) { //none bound, do nothing + if (p_input_vars[0] == String()) { // Use UV by default. - code += "\t\tfloat _depth = 0.0;\n"; + code += "\t\tfloat _depth = texture( DEPTH_TEXTURE , UV.xy ).r;\n"; } else if (p_input_vars[1] == String()) { //no lod @@ -588,6 +637,10 @@ String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::T return String(); // all good } + if (source == SOURCE_PORT) { + return String(); // all good + } + if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { return String(); // all good @@ -625,7 +678,7 @@ void VisualShaderNodeTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeTexture::set_texture_type); ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTexture::get_texture_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth"), "set_source", "get_source"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort"), "set_source", "get_source"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type"); @@ -3023,15 +3076,35 @@ String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const { } int VisualShaderNodeTextureUniform::get_output_port_count() const { - return 2; + return 3; } VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; + + switch (p_port) { + case 0: + return PORT_TYPE_VECTOR; + case 1: + return PORT_TYPE_SCALAR; + case 2: + return PORT_TYPE_SAMPLER; + default: + return PORT_TYPE_SCALAR; + } } String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const { - return p_port == 0 ? "rgb" : "alpha"; + + switch (p_port) { + case 0: + return "rgb"; + case 1: + return "alpha"; + case 2: + return "sampler"; + default: + return ""; + } } String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { @@ -3061,9 +3134,9 @@ String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, Visual String id = get_uniform_name(); String code = "\t{\n"; - if (p_input_vars[0] == String()) { //none bound, do nothing + if (p_input_vars[0] == String()) { // Use UV by default. - code += "\t\tvec4 n_tex_read = vec4(0.0);\n"; + code += "\t\tvec4 n_tex_read = texture( " + id + " , UV.xy );\n"; } else if (p_input_vars[1] == String()) { //no lod code += "\t\tvec4 n_tex_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n"; @@ -3122,6 +3195,13 @@ void VisualShaderNodeTextureUniform::_bind_methods() { BIND_ENUM_CONSTANT(COLOR_DEFAULT_BLACK); } +String VisualShaderNodeTextureUniform::get_input_port_default_hint(int p_port) const { + if (p_port == 0) { + return "UV.xy"; + } + return ""; +} + VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() { texture_type = TYPE_DATA; color_default = COLOR_DEFAULT_WHITE; @@ -3216,6 +3296,15 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod return code; } +String VisualShaderNodeTextureUniformTriplanar::get_input_port_default_hint(int p_port) const { + if (p_port == 0) { + return "default"; + } else if (p_port == 1) { + return "default"; + } + return ""; +} + VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() { } diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 0c6e060353..d5ee990191 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -199,7 +199,8 @@ public: SOURCE_SCREEN, SOURCE_2D_TEXTURE, SOURCE_2D_NORMAL, - SOURCE_DEPTH + SOURCE_DEPTH, + SOURCE_PORT, }; enum TextureType { @@ -226,6 +227,8 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) const; + virtual String get_input_port_default_hint(int p_port) const; + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const; virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty @@ -1422,6 +1425,7 @@ public: virtual int get_input_port_count() const; virtual PortType get_input_port_type(int p_port) const; virtual String get_input_port_name(int p_port) const; + virtual String get_input_port_default_hint(int p_port) const; virtual int get_output_port_count() const; virtual PortType get_output_port_type(int p_port) const; @@ -1456,6 +1460,8 @@ public: virtual PortType get_input_port_type(int p_port) const; virtual String get_input_port_name(int p_port) const; + virtual String get_input_port_default_hint(int p_port) const; + virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty |