diff options
Diffstat (limited to 'scene')
418 files changed, 11017 insertions, 4372 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index b11c2c2886..5bf70e12b7 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -93,7 +93,7 @@ Rect2 AnimatedSprite::_get_rect() const { Point2 ofs = offset; if (centered) - ofs -= s / 2; + ofs -= Size2(s) / 2; if (s == Size2(0, 0)) s = Size2(1, 1); @@ -276,9 +276,9 @@ void SpriteFrames::_set_animations(const Array &p_animations) { anim.speed = d["speed"]; anim.loop = d["loop"]; Array frames = d["frames"]; - for (int i = 0; i < frames.size(); i++) { + for (int j = 0; j < frames.size(); j++) { - RES res = frames[i]; + RES res = frames[j]; anim.frames.push_back(res); } @@ -393,19 +393,30 @@ void AnimatedSprite::_notification(int p_what) { timeout = _get_frame_duration(); int fc = frames->get_frame_count(animation); - if (frame >= fc - 1) { + if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) { if (frames->get_animation_loop(animation)) { + if (backwards) + frame = fc - 1; + else + frame = 0; + emit_signal(SceneStringNames::get_singleton()->animation_finished); - frame = 0; } else { - frame = fc - 1; + if (backwards) + frame = 0; + else + frame = fc - 1; + if (!is_over) { is_over = true; emit_signal(SceneStringNames::get_singleton()->animation_finished); } } } else { - frame++; + if (backwards) + frame--; + else + frame++; } update(); @@ -594,10 +605,12 @@ bool AnimatedSprite::_is_playing() const { return playing; } -void AnimatedSprite::play(const StringName &p_animation) { +void AnimatedSprite::play(const StringName &p_animation, const bool p_backwards) { if (p_animation) set_animation(p_animation); + + backwards = p_backwards; _set_playing(true); } @@ -632,6 +645,10 @@ void AnimatedSprite::_reset_timeout() { void AnimatedSprite::set_animation(const StringName &p_animation) { + ERR_EXPLAIN(vformat("There is no animation with name '%s'.", p_animation)); + ERR_FAIL_COND(frames == NULL); + ERR_FAIL_COND(frames->get_animation_names().find(p_animation) == -1); + if (animation == p_animation) return; @@ -666,7 +683,7 @@ void AnimatedSprite::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite::_set_playing); ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite::_is_playing); - ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite::play, DEFVAL(StringName())); + ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite::play, DEFVAL(StringName()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite::stop); ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite::is_playing); @@ -713,6 +730,7 @@ AnimatedSprite::AnimatedSprite() { frame = 0; speed_scale = 1.0f; playing = false; + backwards = false; animation = "default"; timeout = 0; is_over = false; diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h index 7270ee4d0e..2cc372bd93 100644 --- a/scene/2d/animated_sprite.h +++ b/scene/2d/animated_sprite.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -128,6 +128,7 @@ class AnimatedSprite : public Node2D { Ref<SpriteFrames> frames; bool playing; + bool backwards; StringName animation; int frame; float speed_scale; @@ -169,7 +170,7 @@ public: void set_sprite_frames(const Ref<SpriteFrames> &p_frames); Ref<SpriteFrames> get_sprite_frames() const; - void play(const StringName &p_animation = StringName()); + void play(const StringName &p_animation = StringName(), const bool p_backwards = false); void stop(); bool is_playing() const; diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 4a4aaf3238..b322cfe8f1 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -261,8 +261,9 @@ void Area2D::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ Map<ObjectID, AreaState>::Element *E = area_map.find(objid); - ERR_FAIL_COND(!area_in && !E); - + if (!area_in && !E) { + return; //likely removed from the tree + } locked = true; if (area_in) { @@ -426,10 +427,10 @@ bool Area2D::is_monitoring() const { void Area2D::set_monitorable(bool p_enable) { - if (locked || Physics2DServer::get_singleton()->is_flushing_queries()) { + if (locked || (is_inside_tree() && Physics2DServer::get_singleton()->is_flushing_queries())) { ERR_EXPLAIN("Function blocked during in/out signal. Use set_deferred(\"monitorable\",true/false)"); + ERR_FAIL(); } - ERR_FAIL_COND(locked || Physics2DServer::get_singleton()->is_flushing_queries()); if (p_enable == monitorable) return; diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index cd60b6c1e1..2d1527810e 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index c2af725919..73f583111b 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -467,6 +467,10 @@ bool AudioStreamPlayer2D::get_stream_paused() const { return stream_paused; } +Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() { + return stream_playback; +} + void AudioStreamPlayer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream); @@ -506,6 +510,8 @@ void AudioStreamPlayer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer2D::set_stream_paused); ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer2D::get_stream_paused); + ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer2D::get_stream_playback); + ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer2D::_bus_layout_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h index e68e6eeca5..ffa3d4edb4 100644 --- a/scene/2d/audio_stream_player_2d.h +++ b/scene/2d/audio_stream_player_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,7 +37,7 @@ class AudioStreamPlayer2D : public Node2D { - GDCLASS(AudioStreamPlayer2D, Node2D) + GDCLASS(AudioStreamPlayer2D, Node2D); private: enum { @@ -129,6 +129,8 @@ public: void set_stream_paused(bool p_pause); bool get_stream_paused() const; + Ref<AudioStreamPlayback> get_stream_playback(); + AudioStreamPlayer2D(); ~AudioStreamPlayer2D(); }; diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp index e06c30ec6b..4a4bc4410f 100644 --- a/scene/2d/back_buffer_copy.cpp +++ b/scene/2d/back_buffer_copy.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h index b1ee12544b..52b0c016cc 100644 --- a/scene/2d/back_buffer_copy.h +++ b/scene/2d/back_buffer_copy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index cc297d742d..a0d74dd283 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,10 +29,11 @@ /*************************************************************************/ #include "camera_2d.h" + +#include "core/engine.h" #include "core/math/math_funcs.h" #include "scene/scene_string_names.h" #include "servers/visual_server.h" -#include <editor/editor_node.h> void Camera2D::_update_scroll() { @@ -44,15 +45,16 @@ void Camera2D::_update_scroll() { return; } + if (!viewport) + return; + if (current) { ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)); Transform2D xform = get_camera_transform(); - if (viewport) { - viewport->set_canvas_transform(xform); - } + viewport->set_canvas_transform(xform); Size2 screen_size = viewport->get_visible_rect().size; Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2()); @@ -61,6 +63,20 @@ void Camera2D::_update_scroll() { }; } +void Camera2D::_update_process_mode() { + + if (Engine::get_singleton()->is_editor_hint()) { + set_process_internal(false); + set_physics_process_internal(false); + } else if (process_mode == CAMERA2D_PROCESS_IDLE) { + set_process_internal(true); + set_physics_process_internal(false); + } else { + set_process_internal(false); + set_physics_process_internal(true); + } +} + void Camera2D::set_zoom(const Vector2 &p_zoom) { zoom = p_zoom; @@ -143,7 +159,7 @@ Transform2D Camera2D::get_camera_transform() { if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) { - float c = smoothing * get_process_delta_time(); + float c = smoothing * (process_mode == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time()); smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos; ret_camera_pos = smoothed_camera_pos; //camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing; @@ -217,14 +233,15 @@ void Camera2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_INTERNAL_PROCESS: { + case NOTIFICATION_INTERNAL_PROCESS: + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { _update_scroll(); } break; case NOTIFICATION_TRANSFORM_CHANGED: { - if (!is_processing_internal()) + if (!is_processing_internal() && !is_physics_processing_internal()) _update_scroll(); } break; @@ -245,10 +262,7 @@ void Camera2D::_notification(int p_what) { add_to_group(group_name); add_to_group(canvas_group_name); - if (Engine::get_singleton()->is_editor_hint()) { - set_process_internal(false); - } - + _update_process_mode(); _update_scroll(); first = true; @@ -379,6 +393,20 @@ bool Camera2D::is_rotating() const { return rotating; } +void Camera2D::set_process_mode(Camera2DProcessMode p_mode) { + + if (process_mode == p_mode) + return; + + process_mode = p_mode; + _update_process_mode(); +} + +Camera2D::Camera2DProcessMode Camera2D::get_process_mode() const { + + return process_mode; +} + void Camera2D::_make_current(Object *p_which) { if (p_which == this) { @@ -410,6 +438,7 @@ void Camera2D::make_current() { } else { get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", this); } + _update_scroll(); } void Camera2D::clear_current() { @@ -656,6 +685,9 @@ void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_scroll"), &Camera2D::_update_scroll); + ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Camera2D::set_process_mode); + ClassDB::bind_method(D_METHOD("get_process_mode"), &Camera2D::get_process_mode); + ClassDB::bind_method(D_METHOD("_set_current", "current"), &Camera2D::_set_current); ClassDB::bind_method(D_METHOD("is_current"), &Camera2D::is_current); @@ -716,6 +748,7 @@ void Camera2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "_set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom"), "set_zoom", "get_zoom"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); ADD_GROUP("Limit", "limit_"); ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_left"), "set_limit", "get_limit", MARGIN_LEFT); @@ -749,6 +782,8 @@ void Camera2D::_bind_methods() { BIND_ENUM_CONSTANT(ANCHOR_MODE_FIXED_TOP_LEFT); BIND_ENUM_CONSTANT(ANCHOR_MODE_DRAG_CENTER); + BIND_ENUM_CONSTANT(CAMERA2D_PROCESS_PHYSICS); + BIND_ENUM_CONSTANT(CAMERA2D_PROCESS_IDLE); } Camera2D::Camera2D() { @@ -771,6 +806,7 @@ Camera2D::Camera2D() { limit_smoothing_enabled = false; custom_viewport = NULL; custom_viewport_id = 0; + process_mode = CAMERA2D_PROCESS_IDLE; smoothing = 5.0; zoom = Vector2(1, 1); diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 99571500bf..7f16ecff41 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -44,6 +44,11 @@ public: ANCHOR_MODE_DRAG_CENTER }; + enum Camera2DProcessMode { + CAMERA2D_PROCESS_PHYSICS, + CAMERA2D_PROCESS_IDLE + }; + protected: Point2 camera_pos; Point2 smoothed_camera_pos; @@ -73,6 +78,7 @@ protected: float v_ofs; Point2 camera_screen_center; + void _update_process_mode(); void _update_scroll(); void _make_current(Object *p_which); @@ -84,6 +90,8 @@ protected: bool limit_drawing_enabled; bool margin_drawing_enabled; + Camera2DProcessMode process_mode; + protected: virtual Transform2D get_camera_transform(); void _notification(int p_what); @@ -126,6 +134,9 @@ public: void set_follow_smoothing(float p_speed); float get_follow_smoothing() const; + void set_process_mode(Camera2DProcessMode p_mode); + Camera2DProcessMode get_process_mode() const; + void make_current(); void clear_current(); bool is_current() const; @@ -156,5 +167,6 @@ public: }; VARIANT_ENUM_CAST(Camera2D::AnchorMode); +VARIANT_ENUM_CAST(Camera2D::Camera2DProcessMode); #endif // CAMERA_2D_H diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 2534f676ca..78e98deb93 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -64,6 +64,7 @@ void CanvasItemMaterial::init_shaders() { void CanvasItemMaterial::finish_shaders() { memdelete(dirty_materials); + memdelete(shader_names); dirty_materials = NULL; #ifndef NO_THREADS @@ -130,19 +131,15 @@ void CanvasItemMaterial::_update_shader() { code += "\tVERTEX.xy /= vec2(h_frames, v_frames);\n"; - code += "\tint total_frames = particles_anim_h_frames * particles_anim_v_frames;\n"; - code += "\tint frame = int(float(total_frames) * INSTANCE_CUSTOM.z);\n"; - code += "\tif (particles_anim_loop) {\n"; - code += "\t\tframe = abs(frame) % total_frames;\n"; + code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n"; + code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n"; + code += "\tif (!particles_anim_loop) {\n"; + code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n"; code += "\t} else {\n"; - code += "\t\tframe = clamp(frame, 0, total_frames - 1);\n"; - code += "\t}\n"; - - code += "\tfloat frame_w = 1.0 / h_frames;\n"; - code += "\tfloat frame_h = 1.0 / v_frames;\n"; - code += "\tUV.x = UV.x * frame_w + frame_w * float(frame % particles_anim_h_frames);\n"; - code += "\tUV.y = UV.y * frame_h + frame_h * float(frame / particles_anim_h_frames);\n"; - + code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n"; + code += "\t}"; + code += "\tUV /= vec2(h_frames, v_frames);\n"; + code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n"; code += "}\n"; } @@ -433,6 +430,11 @@ void CanvasItem::hide() { _change_notify("visible"); } +CanvasItem *CanvasItem::current_item_drawn = NULL; +CanvasItem *CanvasItem::get_current_item_drawn() { + return current_item_drawn; +} + void CanvasItem::_update_callback() { if (!is_inside_tree()) { @@ -448,11 +450,13 @@ void CanvasItem::_update_callback() { first_draw = false; } drawing = true; + current_item_drawn = this; notification(NOTIFICATION_DRAW); emit_signal(SceneStringNames::get_singleton()->draw); if (get_script_instance()) { get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, NULL, 0); } + current_item_drawn = NULL; drawing = false; } //todo updating = false @@ -887,13 +891,13 @@ void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Colo VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, p_antialiased); } -void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) { +void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, const Transform2D &p_transform, const Color &p_modulate) { ERR_FAIL_COND(p_mesh.is_null()); RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), texture_rid, normal_map_rid); + VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid); } void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) { @@ -1164,7 +1168,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "antialiased"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1)), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1))); - ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>())); + ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "transform", "modulate"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture>())); ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 1a6016e6e1..1f585d84ce 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -46,7 +46,7 @@ class StyleBox; class CanvasItemMaterial : public Material { - GDCLASS(CanvasItemMaterial, Material) + GDCLASS(CanvasItemMaterial, Material); public: enum BlendMode { @@ -222,6 +222,8 @@ private: void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); } bool _is_on_top() const { return !is_draw_behind_parent_enabled(); } + static CanvasItem *current_item_drawn; + protected: _FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; @@ -315,7 +317,7 @@ public: void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false); void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false); - void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map); + void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1)); void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map); void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1); @@ -324,6 +326,8 @@ public: void draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale); void draw_set_transform_matrix(const Transform2D &p_matrix); + static CanvasItem *get_current_item_drawn(); + /* RECT / TRANSFORM */ void set_as_toplevel(bool p_toplevel); diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index 2f8568ccbf..009d664462 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -70,7 +70,7 @@ void CanvasModulate::_bind_methods() { void CanvasModulate::set_color(const Color &p_color) { color = p_color; - if (is_inside_tree()) { + if (is_visible_in_tree()) { VS::get_singleton()->canvas_set_modulate(get_canvas(), color); } } diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h index 888ed95f6b..101abb4f00 100644 --- a/scene/2d/canvas_modulate.h +++ b/scene/2d/canvas_modulate.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 738f7ddf59..375375285d 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "collision_object_2d.h" + #include "scene/scene_string_names.h" #include "servers/physics_2d_server.h" @@ -56,7 +57,7 @@ void CollisionObject2D::_notification(int p_what) { _update_pickable(); //get space - } + } break; case NOTIFICATION_ENTER_CANVAS: { @@ -64,7 +65,7 @@ void CollisionObject2D::_notification(int p_what) { Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, get_canvas_layer_instance_id()); else Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, get_canvas_layer_instance_id()); - } + } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -101,7 +102,7 @@ void CollisionObject2D::_notification(int p_what) { Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, 0); else Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, 0); - } + } break; } } @@ -163,7 +164,7 @@ void CollisionObject2D::shape_owner_set_one_way_collision(uint32_t p_owner, bool ShapeData &sd = shapes[p_owner]; sd.one_way_collision = p_enable; for (int i = 0; i < sd.shapes.size(); i++) { - Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, p_enable); + Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin); } } @@ -174,6 +175,27 @@ bool CollisionObject2D::is_shape_owner_one_way_collision_enabled(uint32_t p_owne return shapes[p_owner].one_way_collision; } +void CollisionObject2D::shape_owner_set_one_way_collision_margin(uint32_t p_owner, float p_margin) { + + if (area) + return; //not for areas + + ERR_FAIL_COND(!shapes.has(p_owner)); + + ShapeData &sd = shapes[p_owner]; + sd.one_way_collision_margin = p_margin; + for (int i = 0; i < sd.shapes.size(); i++) { + Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin); + } +} + +float CollisionObject2D::get_shape_owner_one_way_collision_margin(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), 0); + + return shapes[p_owner].one_way_collision_margin; +} + void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) { for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { @@ -229,9 +251,9 @@ void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2 s.index = total_subshapes; s.shape = p_shape; if (area) { - Physics2DServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform); + Physics2DServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled); } else { - Physics2DServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform); + Physics2DServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled); } sd.shapes.push_back(s); @@ -390,6 +412,8 @@ void CollisionObject2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_shape_owner_disabled", "owner_id"), &CollisionObject2D::is_shape_owner_disabled); ClassDB::bind_method(D_METHOD("shape_owner_set_one_way_collision", "owner_id", "enable"), &CollisionObject2D::shape_owner_set_one_way_collision); ClassDB::bind_method(D_METHOD("is_shape_owner_one_way_collision_enabled", "owner_id"), &CollisionObject2D::is_shape_owner_one_way_collision_enabled); + ClassDB::bind_method(D_METHOD("shape_owner_set_one_way_collision_margin", "owner_id", "margin"), &CollisionObject2D::shape_owner_set_one_way_collision_margin); + ClassDB::bind_method(D_METHOD("get_shape_owner_one_way_collision_margin", "owner_id"), &CollisionObject2D::get_shape_owner_one_way_collision_margin); ClassDB::bind_method(D_METHOD("shape_owner_add_shape", "owner_id", "shape"), &CollisionObject2D::shape_owner_add_shape); ClassDB::bind_method(D_METHOD("shape_owner_get_shape_count", "owner_id"), &CollisionObject2D::shape_owner_get_shape_count); ClassDB::bind_method(D_METHOD("shape_owner_get_shape", "owner_id", "shape_id"), &CollisionObject2D::shape_owner_get_shape); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 29a00bd9f9..4e7d01c8e6 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -36,7 +36,7 @@ class CollisionObject2D : public Node2D { - GDCLASS(CollisionObject2D, Node2D) + GDCLASS(CollisionObject2D, Node2D); bool area; RID rid; @@ -54,10 +54,12 @@ class CollisionObject2D : public Node2D { Vector<Shape> shapes; bool disabled; bool one_way_collision; + float one_way_collision_margin; ShapeData() { disabled = false; one_way_collision = false; + one_way_collision_margin = 0; owner = NULL; } }; @@ -98,6 +100,9 @@ public: void shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable); bool is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const; + void shape_owner_set_one_way_collision_margin(uint32_t p_owner, float p_margin); + float get_shape_owner_one_way_collision_margin(uint32_t p_owner) const; + void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape); int shape_owner_get_shape_count(uint32_t p_owner) const; Ref<Shape2D> shape_owner_get_shape(uint32_t p_owner, int p_shape) const; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 07bbbd9321..ef7644fcab 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -78,40 +78,7 @@ void CollisionPolygon2D::_build_polygon() { } Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() { - - Vector<Vector<Vector2> > decomp; - List<TriangulatorPoly> in_poly, out_poly; - - TriangulatorPoly inp; - inp.Init(polygon.size()); - for (int i = 0; i < polygon.size(); i++) { - inp.GetPoint(i) = polygon[i]; - } - inp.SetOrientation(TRIANGULATOR_CCW); - in_poly.push_back(inp); - TriangulatorPartition tpart; - if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! - ERR_PRINT("Convex decomposing failed!"); - return decomp; - } - - decomp.resize(out_poly.size()); - int idx = 0; - - for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) { - - TriangulatorPoly &tp = I->get(); - - decomp.write[idx].resize(tp.GetNumPoints()); - - for (int i = 0; i < tp.GetNumPoints(); i++) { - - decomp.write[idx].write[i] = tp.GetPoint(i); - } - - idx++; - } - + Vector<Vector<Vector2> > decomp = Geometry::decompose_polygon_in_convex(polygon); return decomp; } @@ -122,6 +89,7 @@ void CollisionPolygon2D::_update_in_shape_owner(bool p_xform_only) { return; parent->shape_owner_set_disabled(owner_id, disabled); parent->shape_owner_set_one_way_collision(owner_id, one_way_collision); + parent->shape_owner_set_one_way_collision_margin(owner_id, one_way_collision_margin); } void CollisionPolygon2D::_notification(int p_what) { @@ -311,6 +279,16 @@ bool CollisionPolygon2D::is_one_way_collision_enabled() const { return one_way_collision; } +void CollisionPolygon2D::set_one_way_collision_margin(float p_margin) { + one_way_collision_margin = p_margin; + if (parent) { + parent->shape_owner_set_one_way_collision_margin(owner_id, one_way_collision_margin); + } +} + +float CollisionPolygon2D::get_one_way_collision_margin() const { + return one_way_collision_margin; +} void CollisionPolygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CollisionPolygon2D::set_polygon); @@ -322,11 +300,14 @@ void CollisionPolygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon2D::is_disabled); ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionPolygon2D::set_one_way_collision); ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionPolygon2D::is_one_way_collision_enabled); + ClassDB::bind_method(D_METHOD("set_one_way_collision_margin", "margin"), &CollisionPolygon2D::set_one_way_collision_margin); + ClassDB::bind_method(D_METHOD("get_one_way_collision_margin"), &CollisionPolygon2D::get_one_way_collision_margin); ADD_PROPERTY(PropertyInfo(Variant::INT, "build_mode", PROPERTY_HINT_ENUM, "Solids,Segments"), "set_build_mode", "get_build_mode"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "one_way_collision_margin", PROPERTY_HINT_RANGE, "0,128,0.1"), "set_one_way_collision_margin", "get_one_way_collision_margin"); BIND_ENUM_CONSTANT(BUILD_SOLIDS); BIND_ENUM_CONSTANT(BUILD_SEGMENTS); @@ -341,4 +322,5 @@ CollisionPolygon2D::CollisionPolygon2D() { owner_id = 0; disabled = false; one_way_collision = false; + one_way_collision_margin = 1.0; } diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 412a923292..b88679f15b 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -54,6 +54,7 @@ protected: CollisionObject2D *parent; bool disabled; bool one_way_collision; + float one_way_collision_margin; Vector<Vector<Vector2> > _decompose_in_convex(); @@ -84,6 +85,9 @@ public: void set_one_way_collision(bool p_enable); bool is_one_way_collision_enabled() const; + void set_one_way_collision_margin(float p_margin); + float get_one_way_collision_margin() const; + CollisionPolygon2D(); }; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index d3e25d541a..5440a1d8c3 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -36,9 +36,9 @@ #include "scene/resources/circle_shape_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" +#include "scene/resources/line_shape_2d.h" #include "scene/resources/rectangle_shape_2d.h" #include "scene/resources/segment_shape_2d.h" -#include "scene/resources/shape_line_2d.h" void CollisionShape2D::_shape_changed() { @@ -52,6 +52,7 @@ void CollisionShape2D::_update_in_shape_owner(bool p_xform_only) { return; parent->shape_owner_set_disabled(owner_id, disabled); parent->shape_owner_set_one_way_collision(owner_id, one_way_collision); + parent->shape_owner_set_one_way_collision_margin(owner_id, one_way_collision_margin); } void CollisionShape2D::_notification(int p_what) { @@ -219,6 +220,17 @@ bool CollisionShape2D::is_one_way_collision_enabled() const { return one_way_collision; } +void CollisionShape2D::set_one_way_collision_margin(float p_margin) { + one_way_collision_margin = p_margin; + if (parent) { + parent->shape_owner_set_one_way_collision_margin(owner_id, one_way_collision_margin); + } +} + +float CollisionShape2D::get_one_way_collision_margin() const { + return one_way_collision_margin; +} + void CollisionShape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape2D::set_shape); @@ -227,11 +239,14 @@ void CollisionShape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape2D::is_disabled); ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionShape2D::set_one_way_collision); ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionShape2D::is_one_way_collision_enabled); + ClassDB::bind_method(D_METHOD("set_one_way_collision_margin", "margin"), &CollisionShape2D::set_one_way_collision_margin); + ClassDB::bind_method(D_METHOD("get_one_way_collision_margin"), &CollisionShape2D::get_one_way_collision_margin); ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape2D::_shape_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "one_way_collision_margin", PROPERTY_HINT_RANGE, "0,128,0.1"), "set_one_way_collision_margin", "get_one_way_collision_margin"); } CollisionShape2D::CollisionShape2D() { @@ -242,4 +257,5 @@ CollisionShape2D::CollisionShape2D() { parent = NULL; disabled = false; one_way_collision = false; + one_way_collision_margin = 1.0; } diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index ed2c09d53d..26c61f47bd 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -38,7 +38,7 @@ class CollisionObject2D; class CollisionShape2D : public Node2D { - GDCLASS(CollisionShape2D, Node2D) + GDCLASS(CollisionShape2D, Node2D); Ref<Shape2D> shape; Rect2 rect; uint32_t owner_id; @@ -46,6 +46,7 @@ class CollisionShape2D : public Node2D { void _shape_changed(); bool disabled; bool one_way_collision; + float one_way_collision_margin; void _update_in_shape_owner(bool p_xform_only = false); @@ -65,6 +66,9 @@ public: void set_one_way_collision(bool p_enable); bool is_one_way_collision_enabled() const; + void set_one_way_collision_margin(float p_margin); + float get_one_way_collision_margin() const; + virtual String get_configuration_warning() const; CollisionShape2D(); diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 93ad99272c..a8d72bb774 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,28 +29,17 @@ /*************************************************************************/ #include "cpu_particles_2d.h" -#include "particles_2d.h" + #include "scene/2d/canvas_item.h" +#include "scene/2d/particles_2d.h" #include "scene/resources/particles_material.h" #include "servers/visual_server.h" void CPUParticles2D::set_emitting(bool p_emitting) { emitting = p_emitting; - if (!is_processing_internal()) { + if (emitting) set_process_internal(true); - if (is_inside_tree()) { -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true); - -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } - } } void CPUParticles2D::set_amount(int p_amount) { @@ -97,7 +86,9 @@ void CPUParticles2D::set_randomness_ratio(float p_ratio) { void CPUParticles2D::set_use_local_coordinates(bool p_enable) { local_coords = p_enable; + set_notify_transform(!p_enable); } + void CPUParticles2D::set_speed_scale(float p_scale) { speed_scale = p_scale; @@ -336,9 +327,9 @@ void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv case PARAM_ANGULAR_VELOCITY: { _adjust_curve_range(p_curve, -360, 360); } break; - /*case PARAM_ORBIT_VELOCITY: { + case PARAM_ORBIT_VELOCITY: { _adjust_curve_range(p_curve, -500, 500); - } break;*/ + } break; case PARAM_LINEAR_ACCEL: { _adjust_curve_range(p_curve, -200, 200); } break; @@ -365,7 +356,8 @@ void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv } break; case PARAM_ANIM_OFFSET: { } break; - default: {} + default: { + } } } Ref<Curve> CPUParticles2D::get_param_curve(Parameter p_param) const { @@ -477,7 +469,7 @@ void CPUParticles2D::_validate_property(PropertyInfo &property) const { property.usage = 0; } - if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_CIRCLE) { + if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { property.usage = 0; } @@ -500,12 +492,6 @@ void CPUParticles2D::_validate_property(PropertyInfo &property) const { if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { property.usage = 0; } - - /* - if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { - property.usage = 0; - } - */ } static uint32_t idhash(uint32_t x) { @@ -556,6 +542,8 @@ void CPUParticles2D::_particles_process(float p_delta) { velocity_xform[2] = Vector2(); } + float system_phase = time / lifetime; + for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; @@ -563,21 +551,26 @@ void CPUParticles2D::_particles_process(float p_delta) { if (!emitting && !p.active) continue; - float restart_time = (float(i) / float(pcount)) * lifetime; float local_delta = p_delta; + // The phase is a ratio between 0 (birth) and 1 (end of life) for each particle. + // While we use time in tests later on, for randomness we use the phase as done in the + // original shader code, and we later multiply by lifetime to get the time. + float restart_phase = float(i) / float(pcount); + if (randomness_ratio > 0.0) { uint32_t seed = cycle; - if (restart_time >= time) { + if (restart_phase >= system_phase) { seed -= uint32_t(1); } seed *= uint32_t(pcount); seed += uint32_t(i); float random = float(idhash(seed) % uint32_t(65536)) / 65536.0; - restart_time += randomness_ratio * random * 1.0 / float(pcount); + restart_phase += randomness_ratio * random * 1.0 / float(pcount); } - restart_time *= (1.0 - explosiveness_ratio); + restart_phase *= (1.0 - explosiveness_ratio); + float restart_time = restart_phase * lifetime; bool restart = false; if (time > prev_time) { @@ -586,7 +579,7 @@ void CPUParticles2D::_particles_process(float p_delta) { if (restart_time >= prev_time && restart_time < time) { restart = true; if (fractional_delta) { - local_delta = (time - restart_time) * lifetime; + local_delta = time - restart_time; } } @@ -594,13 +587,13 @@ void CPUParticles2D::_particles_process(float p_delta) { if (restart_time >= prev_time) { restart = true; if (fractional_delta) { - local_delta = (1.0 - restart_time + time) * lifetime; + local_delta = lifetime - restart_time + time; } } else if (restart_time < time) { restart = true; if (fractional_delta) { - local_delta = (time - restart_time) * lifetime; + local_delta = time - restart_time; } } } @@ -654,8 +647,9 @@ void CPUParticles2D::_particles_process(float p_delta) { case EMISSION_SHAPE_POINT: { //do none } break; - case EMISSION_SHAPE_CIRCLE: { - p.transform[2] = Vector2(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0).normalized() * emission_sphere_radius; + case EMISSION_SHAPE_SPHERE: { + Vector3 sphere_shape = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0).normalized() * emission_sphere_radius; + p.transform[2] = Vector2(sphere_shape.x, sphere_shape.y); } break; case EMISSION_SHAPE_RECTANGLE: { p.transform[2] = Vector2(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_rect_extents; @@ -699,16 +693,12 @@ void CPUParticles2D::_particles_process(float p_delta) { if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]); } - /* - float tex_orbit_velocity = 0.0; - if (flags[FLAG_DISABLE_Z]) { - - if (curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY].is_valid()) { - tex_orbit_velocity = curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY]->interpolate(p.custom[1]); - } + float tex_orbit_velocity = 0.0; + if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { + tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]); } -*/ + float tex_angular_velocity = 0.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]); @@ -759,22 +749,19 @@ void CPUParticles2D::_particles_process(float p_delta) { force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2(); //apply tangential acceleration; Vector2 yx = Vector2(diff.y, diff.x); - force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2(); + force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2(); //apply attractor forces p.velocity += force * local_delta; //orbit velocity -#if 0 - if (flags[FLAG_DISABLE_Z]) { - - float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random); - if (orbit_amount != 0.0) { - float ang = orbit_amount * DELTA * pi * 2.0; - mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang))); - TRANSFORM[3].xy -= diff.xy; - TRANSFORM[3].xy += rot * diff.xy; - } + float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); + if (orbit_amount != 0.0) { + float ang = orbit_amount * local_delta * Math_PI * 2.0; + // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, + // but we use -ang here to reproduce its behavior. + Transform2D rot = Transform2D(-ang, Vector2()); + p.transform[2] -= diff; + p.transform[2] += rot.basis_xform(diff); } -#endif if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { p.velocity = p.velocity.normalized() * tex_linear_velocity; } @@ -840,7 +827,7 @@ void CPUParticles2D::_particles_process(float p_delta) { if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { if (p.velocity.length() > 0.0) { - p.transform.elements[0] = p.velocity.normalized(); + p.transform.elements[1] = p.velocity.normalized(); p.transform.elements[0] = p.transform.elements[1].tangent(); } @@ -876,11 +863,6 @@ void CPUParticles2D::_update_particle_data_buffer() { PoolVector<Particle>::Read r = particles.read(); float *ptr = w.ptr(); - Transform2D un_transform; - if (!local_coords) { - un_transform = get_global_transform().affine_inverse(); - } - if (draw_order != DRAW_ORDER_INDEX) { ow = particle_order.write(); order = ow.ptr(); @@ -902,7 +884,7 @@ void CPUParticles2D::_update_particle_data_buffer() { Transform2D t = r[idx].transform; if (!local_coords) { - t = un_transform * t; + t = inv_emission_transform * t; } if (r[idx].active) { @@ -941,6 +923,26 @@ void CPUParticles2D::_update_particle_data_buffer() { #endif } +void CPUParticles2D::_set_redraw(bool p_redraw) { + if (redraw == p_redraw) + return; + redraw = p_redraw; +#ifndef NO_THREADS + update_mutex->lock(); +#endif + if (redraw) { + VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true); + } else { + VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false); + } +#ifndef NO_THREADS + update_mutex->unlock(); +#endif + update(); // redraw to update render list +} + void CPUParticles2D::_update_render_thread() { #ifndef NO_THREADS @@ -957,38 +959,19 @@ void CPUParticles2D::_update_render_thread() { void CPUParticles2D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - if (is_processing_internal()) { - -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true); - -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } + set_process_internal(emitting); } if (p_what == NOTIFICATION_EXIT_TREE) { - if (is_processing_internal()) { - -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } + _set_redraw(false); } if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { } if (p_what == NOTIFICATION_DRAW) { + if (!redraw) + return; // don't add to render list RID texrid; if (texture.is_valid()) { @@ -1005,26 +988,20 @@ void CPUParticles2D::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (particles.size() == 0 || !is_visible_in_tree()) + if (particles.size() == 0 || !is_visible_in_tree()) { + _set_redraw(false); return; + } float delta = get_process_delta_time(); if (emitting) { - inactive_time = 0; } else { inactive_time += delta; if (inactive_time > lifetime * 1.2) { set_process_internal(false); -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false); + _set_redraw(false); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif //reset variables time = 0; inactive_time = 0; @@ -1033,6 +1010,7 @@ void CPUParticles2D::_notification(int p_what) { return; } } + _set_redraw(true); if (time == 0 && pre_process_time > 0.0) { @@ -1075,6 +1053,42 @@ void CPUParticles2D::_notification(int p_what) { _update_particle_data_buffer(); } + + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + + inv_emission_transform = get_global_transform().affine_inverse(); + + if (!local_coords) { + + int pc = particles.size(); + + PoolVector<float>::Write w = particle_data.write(); + PoolVector<Particle>::Read r = particles.read(); + float *ptr = w.ptr(); + + for (int i = 0; i < pc; i++) { + + Transform2D t = inv_emission_transform * r[i].transform; + + if (r[i].active) { + + ptr[0] = t.elements[0][0]; + ptr[1] = t.elements[1][0]; + ptr[2] = 0; + ptr[3] = t.elements[2][0]; + ptr[4] = t.elements[0][1]; + ptr[5] = t.elements[1][1]; + ptr[6] = 0; + ptr[7] = t.elements[2][1]; + + } else { + zeromem(ptr, sizeof(float) * 8); + } + + ptr += 13; + } + } + } } void CPUParticles2D::convert_from_particles(Node *p_particles) { @@ -1189,15 +1203,16 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); ADD_GROUP("Drawing", ""); + // No visibility_rect property contrarily to Particles2D, it's updated automatically. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); @@ -1278,12 +1293,10 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY); - /* ADD_GROUP("Orbit Velocity", "orbit_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY); -*/ ADD_GROUP("Linear Accel", "linear_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); @@ -1339,10 +1352,12 @@ void CPUParticles2D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_MAX); BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); // Unused, but exposed for consistency with 3D. + BIND_ENUM_CONSTANT(FLAG_DISABLE_Z); // Unused, but exposed for consistency with 3D. BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); - BIND_ENUM_CONSTANT(EMISSION_SHAPE_CIRCLE); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); BIND_ENUM_CONSTANT(EMISSION_SHAPE_RECTANGLE); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); @@ -1354,6 +1369,7 @@ CPUParticles2D::CPUParticles2D() { inactive_time = 0; frame_remainder = 0; cycle = 0; + redraw = false; mesh = VisualServer::get_singleton()->mesh_create(); multimesh = VisualServer::get_singleton()->multimesh_create(); @@ -1376,8 +1392,9 @@ CPUParticles2D::CPUParticles2D() { set_spread(45); set_flatness(0); set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); - //set_param(PARAM_ORBIT_VELOCITY, 0); + set_param(PARAM_ORBIT_VELOCITY, 0); set_param(PARAM_LINEAR_ACCEL, 0); + set_param(PARAM_ANGULAR_VELOCITY, 0); set_param(PARAM_RADIAL_ACCEL, 0); set_param(PARAM_TANGENTIAL_ACCEL, 0); set_param(PARAM_DAMPING, 0); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index d967c3be26..6c83abb311 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -68,12 +68,14 @@ public: enum Flags { FLAG_ALIGN_Y_TO_VELOCITY, + FLAG_ROTATE_Y, // Unused, but exposed for consistency with 3D. + FLAG_DISABLE_Z, // Unused, but exposed for consistency with 3D. FLAG_MAX }; enum EmissionShape { EMISSION_SHAPE_POINT, - EMISSION_SHAPE_CIRCLE, + EMISSION_SHAPE_SPHERE, EMISSION_SHAPE_RECTANGLE, EMISSION_SHAPE_POINTS, EMISSION_SHAPE_DIRECTED_POINTS, @@ -103,6 +105,7 @@ private: float inactive_time; float frame_remainder; int cycle; + bool redraw; RID mesh; RID multimesh; @@ -115,7 +118,7 @@ private: const Particle *particles; bool operator()(int p_a, int p_b) const { - return particles[p_a].time < particles[p_b].time; + return particles[p_a].time > particles[p_b].time; } }; @@ -141,6 +144,8 @@ private: int fixed_fps; bool fractional_delta; + Transform2D inv_emission_transform; + DrawOrder draw_order; Ref<Texture> texture; @@ -179,6 +184,8 @@ private: void _update_mesh_texture(); + void _set_redraw(bool p_redraw); + protected: static void _bind_methods(); void _notification(int p_what); diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index b9a48e1fdc..5b14b3e8e1 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h index 744994f0a7..a3951eb9d2 100644 --- a/scene/2d/joints_2d.h +++ b/scene/2d/joints_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index e6a5a0b651..7f01ff8806 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -431,14 +431,14 @@ void Light2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture,ImageTexture"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_texture_offset", "get_texture_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_scale", PROPERTY_HINT_RANGE, "0.01,50,0.01"), "set_texture_scale", "get_texture_scale"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix,Mask"), "set_mode", "get_mode"); ADD_GROUP("Range", "range_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "range_height", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "range_height", PROPERTY_HINT_RANGE, "-2048,2048,0.1,or_lesser,or_greater"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_min", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_min", "get_z_range_min"); ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_max", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_max", "get_z_range_max"); ADD_PROPERTY(PropertyInfo(Variant::INT, "range_layer_min", PROPERTY_HINT_RANGE, "-512,512,1"), "set_layer_range_min", "get_layer_range_min"); @@ -450,7 +450,7 @@ void Light2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_buffer_size", PROPERTY_HINT_RANGE, "32,16384,1"), "set_shadow_buffer_size", "get_shadow_buffer_size"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_gradient_length", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_shadow_gradient_length", "get_shadow_gradient_length"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_filter", PROPERTY_HINT_ENUM, "None,PCF3,PCF5,PCF7,PCF9,PCF13"), "set_shadow_filter", "get_shadow_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_filter", PROPERTY_HINT_ENUM, "None,PCF3,PCF5,PCF7,PCF9,PCF13"), "set_shadow_filter", "get_shadow_filter"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "shadow_filter_smooth", PROPERTY_HINT_RANGE, "0,64,0.1"), "set_shadow_smooth", "get_shadow_smooth"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_item_cull_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_item_shadow_cull_mask", "get_item_shadow_cull_mask"); diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index 40469cfbc8..b1940f64cd 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index ab15b49985..3a3f90ac4b 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,9 +32,59 @@ #include "core/engine.h" +#define LINE_GRAB_WIDTH 8 +Rect2 OccluderPolygon2D::_edit_get_rect() const { + + if (rect_cache_dirty) { + if (closed) { + PoolVector<Vector2>::Read r = polygon.read(); + item_rect = Rect2(); + for (int i = 0; i < polygon.size(); i++) { + Vector2 pos = r[i]; + if (i == 0) + item_rect.position = pos; + else + item_rect.expand_to(pos); + } + rect_cache_dirty = false; + } else { + if (polygon.size() == 0) { + item_rect = Rect2(); + } else { + Vector2 d = Vector2(LINE_GRAB_WIDTH, LINE_GRAB_WIDTH); + item_rect = Rect2(polygon[0] - d, 2 * d); + for (int i = 1; i < polygon.size(); i++) { + item_rect.expand_to(polygon[i] - d); + item_rect.expand_to(polygon[i] + d); + } + } + } + } + + return item_rect; +} + +bool OccluderPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + + if (closed) { + return Geometry::is_point_in_polygon(p_point, Variant(polygon)); + } else { + const real_t d = LINE_GRAB_WIDTH / 2 + p_tolerance; + PoolVector<Vector2>::Read points = polygon.read(); + for (int i = 0; i < polygon.size() - 1; i++) { + Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, &points[i]); + if (p.distance_to(p_point) <= d) + return true; + } + + return false; + } +} + void OccluderPolygon2D::set_polygon(const PoolVector<Vector2> &p_polygon) { polygon = p_polygon; + rect_cache_dirty = true; VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, p_polygon, closed); emit_changed(); } @@ -100,6 +150,7 @@ OccluderPolygon2D::OccluderPolygon2D() { occ_polygon = VS::get_singleton()->canvas_occluder_polygon_create(); closed = true; cull = CULL_DISABLED; + rect_cache_dirty = true; } OccluderPolygon2D::~OccluderPolygon2D() { @@ -164,6 +215,16 @@ void LightOccluder2D::_notification(int p_what) { } } +Rect2 LightOccluder2D::_edit_get_rect() const { + + return occluder_polygon.is_valid() ? occluder_polygon->_edit_get_rect() : Rect2(); +} + +bool LightOccluder2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + + return occluder_polygon.is_valid() ? occluder_polygon->_edit_is_selected_on_click(p_point, p_tolerance) : false; +} + void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon) { #ifdef DEBUG_ENABLED diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index d59c9100b0..7931cd0b30 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -50,10 +50,16 @@ private: bool closed; CullMode cull; + mutable Rect2 item_rect; + mutable bool rect_cache_dirty; + protected: static void _bind_methods(); public: + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + void set_polygon(const PoolVector<Vector2> &p_polygon); PoolVector<Vector2> get_polygon() const; @@ -85,6 +91,9 @@ protected: static void _bind_methods(); public: + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + void set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon); Ref<OccluderPolygon2D> get_occluder_polygon() const; diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 6faf8c2855..5ba184b324 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -105,6 +105,7 @@ void Line2D::set_point_position(int i, Vector2 pos) { } Vector2 Line2D::get_point_position(int i) const { + ERR_FAIL_INDEX_V(i, _points.size(), Vector2()); return _points.get(i); } @@ -112,8 +113,20 @@ int Line2D::get_point_count() const { return _points.size(); } -void Line2D::add_point(Vector2 pos) { - _points.append(pos); +void Line2D::clear_points() { + int count = _points.size(); + if (count > 0) { + _points.resize(0); + update(); + } +} + +void Line2D::add_point(Vector2 pos, int atpos) { + if (atpos < 0 || _points.size() < atpos) { + _points.append(pos); + } else { + _points.insert(atpos, pos); + } update(); } @@ -310,9 +323,11 @@ void Line2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_count"), &Line2D::get_point_count); - ClassDB::bind_method(D_METHOD("add_point", "position"), &Line2D::add_point); + ClassDB::bind_method(D_METHOD("add_point", "position", "at_position"), &Line2D::add_point, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("remove_point", "i"), &Line2D::remove_point); + ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points); + ClassDB::bind_method(D_METHOD("set_width", "width"), &Line2D::set_width); ClassDB::bind_method(D_METHOD("get_width"), &Line2D::get_width); diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 6918018c12..11be5055d4 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -35,7 +35,7 @@ class Line2D : public Node2D { - GDCLASS(Line2D, Node2D) + GDCLASS(Line2D, Node2D); public: enum LineJointMode { @@ -70,7 +70,9 @@ public: int get_point_count() const; - void add_point(Vector2 pos); + void clear_points(); + + void add_point(Vector2 pos, int atpos = -1); void remove_point(int i); void set_width(float width); diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index d5e8a33805..eb09d3c9d3 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -279,6 +279,10 @@ void LineBuilder::build() { } } else { // No intersection: fallback + if (current_joint_mode == Line2D::LINE_JOINT_SHARP) { + // There is no fallback implementation for LINE_JOINT_SHARP so switch to the LINE_JOINT_BEVEL + current_joint_mode = Line2D::LINE_JOINT_BEVEL; + } pos_up1 = corner_pos_up; pos_down1 = corner_pos_down; } diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index f9d26f12af..b961385e33 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,7 @@ #include "core/color.h" #include "core/math/vector2.h" #include "line_2d.h" -#include "scene/resources/color_ramp.h" +#include "scene/resources/gradient.h" class LineBuilder { public: diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index 46777665d8..bcd4bca940 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -50,6 +50,8 @@ void MeshInstance2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &MeshInstance2D::set_normal_map); ClassDB::bind_method(D_METHOD("get_normal_map"), &MeshInstance2D::get_normal_map); + ADD_SIGNAL(MethodInfo("texture_changed")); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map"); diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h index c9889c1c03..af552415ca 100644 --- a/scene/2d/mesh_instance_2d.h +++ b/scene/2d/mesh_instance_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,7 @@ #include "scene/2d/node_2d.h" class MeshInstance2D : public Node2D { - GDCLASS(MeshInstance2D, Node2D) + GDCLASS(MeshInstance2D, Node2D); Ref<Mesh> mesh; diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp new file mode 100644 index 0000000000..ca75302163 --- /dev/null +++ b/scene/2d/multimesh_instance_2d.cpp @@ -0,0 +1,111 @@ +/*************************************************************************/ +/* multimesh_instance_2d.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 "multimesh_instance_2d.h" + +void MultiMeshInstance2D::_notification(int p_what) { + + if (p_what == NOTIFICATION_DRAW) { + if (multimesh.is_valid()) { + draw_multimesh(multimesh, texture, normal_map); + } + } +} + +void MultiMeshInstance2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_multimesh", "multimesh"), &MultiMeshInstance2D::set_multimesh); + ClassDB::bind_method(D_METHOD("get_multimesh"), &MultiMeshInstance2D::get_multimesh); + + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &MultiMeshInstance2D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &MultiMeshInstance2D::get_texture); + + ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &MultiMeshInstance2D::set_normal_map); + ClassDB::bind_method(D_METHOD("get_normal_map"), &MultiMeshInstance2D::get_normal_map); + + ADD_SIGNAL(MethodInfo("texture_changed")); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multimesh", PROPERTY_HINT_RESOURCE_TYPE, "MultiMesh"), "set_multimesh", "get_multimesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map"); +} + +void MultiMeshInstance2D::set_multimesh(const Ref<MultiMesh> &p_multimesh) { + + multimesh = p_multimesh; + update(); +} + +Ref<MultiMesh> MultiMeshInstance2D::get_multimesh() const { + + return multimesh; +} + +void MultiMeshInstance2D::set_texture(const Ref<Texture> &p_texture) { + + if (p_texture == texture) + return; + texture = p_texture; + update(); + emit_signal("texture_changed"); + _change_notify("texture"); +} + +Ref<Texture> MultiMeshInstance2D::get_texture() const { + + return texture; +} + +void MultiMeshInstance2D::set_normal_map(const Ref<Texture> &p_texture) { + + normal_map = p_texture; + update(); +} + +Ref<Texture> MultiMeshInstance2D::get_normal_map() const { + + return normal_map; +} + +Rect2 MultiMeshInstance2D::_edit_get_rect() const { + + if (multimesh.is_valid()) { + AABB aabb = multimesh->get_aabb(); + return Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + } + + return Node2D::_edit_get_rect(); +} + +MultiMeshInstance2D::MultiMeshInstance2D() { +} + +MultiMeshInstance2D::~MultiMeshInstance2D() { +} diff --git a/scene/resources/bounds.cpp b/scene/2d/multimesh_instance_2d.h index b115d92be3..3795497183 100644 --- a/scene/resources/bounds.cpp +++ b/scene/2d/multimesh_instance_2d.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* bounds.cpp */ +/* multimesh_instance_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,25 +28,38 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "bounds.h" +#ifndef MULTIMESH_INSTANCE_2D_H +#define MULTIMESH_INSTANCE_2D_H -void Bounds::_bind_methods() { +#include "scene/2d/node_2d.h" +#include "scene/resources/multimesh.h" - ClassDB::bind_method(D_METHOD("set_bsp_tree", "bsp_tree"), &Bounds::set_bsp_tree); - ClassDB::bind_method(D_METHOD("get_bsp_tree"), &Bounds::get_bsp_tree); +class MultiMeshInstance2D : public Node2D { + GDCLASS(MultiMeshInstance2D, Node2D); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bsp_tree"), "set_bsp_tree", "get_bsp_tree"); -} + Ref<MultiMesh> multimesh; -void Bounds::set_bsp_tree(const BSP_Tree &p_bsp_tree) { + Ref<Texture> texture; + Ref<Texture> normal_map; - bsp_tree = p_bsp_tree; -} +protected: + void _notification(int p_what); + static void _bind_methods(); -BSP_Tree Bounds::get_bsp_tree() const { +public: + void set_multimesh(const Ref<MultiMesh> &p_multimesh); + Ref<MultiMesh> get_multimesh() const; - return bsp_tree; -} + void set_texture(const Ref<Texture> &p_texture); + Ref<Texture> get_texture() const; -Bounds::Bounds() { -} + void set_normal_map(const Ref<Texture> &p_texture); + Ref<Texture> get_normal_map() const; + + virtual Rect2 _edit_get_rect() const; + + MultiMeshInstance2D(); + ~MultiMeshInstance2D(); +}; + +#endif // MULTIMESH_INSTANCE_2D_H diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation_2d.cpp index 1b789bab9d..72b5f2fb12 100644 --- a/scene/2d/navigation2d.cpp +++ b/scene/2d/navigation_2d.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* navigation2d.cpp */ +/* navigation_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "navigation2d.h" +#include "navigation_2d.h" #define USE_ENTRY_POINT @@ -542,7 +542,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect if (CLOCK_TANGENT(apex_point, portal_left, left) >= 0) { //process - if (portal_left.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, left, portal_right) > 0) { + if (Math::is_zero_approx(portal_left.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, left, portal_right) > 0) { left_poly = p; portal_left = left; } else { @@ -552,7 +552,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect left_poly = p; portal_left = apex_point; portal_right = apex_point; - if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON) + if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point))) path.push_back(apex_point); skip = true; } @@ -560,7 +560,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect if (!skip && CLOCK_TANGENT(apex_point, portal_right, right) <= 0) { //process - if (portal_right.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, right, portal_left) < 0) { + if (Math::is_zero_approx(portal_right.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, right, portal_left) < 0) { right_poly = p; portal_right = right; } else { @@ -570,7 +570,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect right_poly = p; portal_right = apex_point; portal_left = apex_point; - if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON) + if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point))) path.push_back(apex_point); } } @@ -596,7 +596,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect } } - if (!path.size() || path[path.size() - 1].distance_squared_to(begin_point) > CMP_EPSILON) { + if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(begin_point))) { path.push_back(begin_point); // Add the begin point } else { path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point @@ -604,7 +604,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect path.invert(); - if (path.size() <= 1 || path[path.size() - 1].distance_squared_to(end_point) > CMP_EPSILON) { + if (path.size() <= 1 || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(end_point))) { path.push_back(end_point); // Add the end point } else { path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation_2d.h index 02c46d5de1..b4d659ff5c 100644 --- a/scene/2d/navigation2d.h +++ b/scene/2d/navigation_2d.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* navigation2d.h */ +/* navigation_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -171,4 +171,4 @@ public: Navigation2D(); }; -#endif // Navigation2D2D_H +#endif // NAVIGATION_2D_H diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index 9154929e0b..e389d5f98f 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "core/engine.h" -#include "navigation2d.h" +#include "navigation_2d.h" #include "thirdparty/misc/triangulator.h" @@ -312,7 +312,7 @@ void NavigationPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines); ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines"); } diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h index d7684c2d94..ebbe67d949 100644 --- a/scene/2d/navigation_polygon.h +++ b/scene/2d/navigation_polygon.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 2d9bbfe657..f4430d93f6 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -376,7 +376,7 @@ void Node2D::look_at(const Vector2 &p_pos) { float Node2D::get_angle_to(const Vector2 &p_pos) const { - return (get_global_transform().affine_inverse().xform(p_pos)).angle(); + return (to_local(p_pos) * get_scale()).angle(); } Point2 Node2D::to_local(Point2 p_global) const { diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 924a84fb88..c07dc88720 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 59cb16fe91..4ead1bbd1e 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -207,7 +207,7 @@ void ParallaxBackground::_bind_methods() { ParallaxBackground::ParallaxBackground() { scale = 1.0; - set_layer(-1); //behind all by default + set_layer(-100); //behind all by default base_scale = Vector2(1, 1); ignore_camera_zoom = false; diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h index 31d1c553a2..38d59ac737 100644 --- a/scene/2d/parallax_background.h +++ b/scene/2d/parallax_background.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 06de723f27..9a6b63b9a3 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -105,6 +105,11 @@ void ParallaxLayer::_notification(int p_what) { orig_scale = get_scale(); _update_mirroring(); } break; + case NOTIFICATION_EXIT_TREE: { + + set_position(orig_offset); + set_scale(orig_scale); + } break; } } diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h index b2b98b0ef6..b5db111a38 100644 --- a/scene/2d/parallax_layer.h +++ b/scene/2d/parallax_layer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 35b7e7da3e..9701998f5d 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -30,6 +30,7 @@ #include "particles_2d.h" +#include "core/os/os.h" #include "scene/resources/particles_material.h" #include "scene/scene_string_names.h" @@ -213,6 +214,10 @@ bool Particles2D::get_fractional_delta() const { String Particles2D::get_configuration_warning() const { + if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles\" option for this purpose."); + } + String warnings; if (process_material.is_null()) { diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index 6d52f8b28e..0276978f83 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,7 +37,7 @@ class Particles2D : public Node2D { private: - GDCLASS(Particles2D, Node2D) + GDCLASS(Particles2D, Node2D); public: enum DrawOrder { diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 5eae43b2d5..e062067248 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -95,7 +95,7 @@ void Path2D::_notification(int p_what) { return; } -#if TOOLS_ENABLED +#ifdef TOOLS_ENABLED const float line_width = 2 * EDSCALE; #else const float line_width = 2; @@ -170,6 +170,9 @@ void PathFollow2D::_update_transform() { return; float path_length = c->get_baked_length(); + if (path_length == 0) { + return; + } float bounded_offset = offset; if (loop) bounded_offset = Math::fposmod(bounded_offset, path_length); @@ -261,7 +264,7 @@ void PathFollow2D::_validate_property(PropertyInfo &property) const { if (path && path->get_curve().is_valid()) max = path->get_curve()->get_baked_length(); - property.hint_string = "0," + rtos(max) + ",0.01"; + property.hint_string = "0," + rtos(max) + ",0.01,or_lesser"; } } @@ -303,8 +306,8 @@ void PathFollow2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead); ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotate"), "set_rotate", "is_rotating"); @@ -316,8 +319,24 @@ void PathFollow2D::_bind_methods() { void PathFollow2D::set_offset(float p_offset) { offset = p_offset; - if (path) + if (path) { + if (path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { + float path_length = path->get_curve()->get_baked_length(); + + if (loop) { + while (offset > path_length) + offset -= path_length; + + while (offset < 0) + offset += path_length; + + } else { + offset = CLAMP(offset, 0, path_length); + } + } + _update_transform(); + } _change_notify("offset"); _change_notify("unit_offset"); } diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index 64696442c3..4efad19938 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/path_texture.cpp b/scene/2d/path_texture.cpp index d36a9fb65a..3de2079ebe 100644 --- a/scene/2d/path_texture.cpp +++ b/scene/2d/path_texture.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/path_texture.h b/scene/2d/path_texture.h index 7a347c0653..313aa772c4 100644 --- a/scene/2d/path_texture.h +++ b/scene/2d/path_texture.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index c440512c84..2bd9e5e2a2 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -199,12 +199,12 @@ real_t StaticBody2D::get_constant_angular_velocity() const { #ifndef DISABLE_DEPRECATED void StaticBody2D::set_friction(real_t p_friction) { - if (p_friction == 1.0) { // default value, don't create an override for that + if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } - ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_friction < 0 || p_friction > 1); @@ -217,8 +217,8 @@ void StaticBody2D::set_friction(real_t p_friction) { real_t StaticBody2D::get_friction() const { - ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 1; @@ -229,12 +229,12 @@ real_t StaticBody2D::get_friction() const { void StaticBody2D::set_bounce(real_t p_bounce) { - if (p_bounce == 0.0) { // default value, don't create an override for that + if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } - ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); @@ -247,8 +247,8 @@ void StaticBody2D::set_bounce(real_t p_bounce) { real_t StaticBody2D::get_bounce() const { - ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 0; @@ -626,12 +626,12 @@ real_t RigidBody2D::get_weight() const { #ifndef DISABLE_DEPRECATED void RigidBody2D::set_friction(real_t p_friction) { - if (p_friction == 1.0) { // default value, don't create an override for that + if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } - ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_friction < 0 || p_friction > 1); @@ -643,8 +643,8 @@ void RigidBody2D::set_friction(real_t p_friction) { } real_t RigidBody2D::get_friction() const { - ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 1; @@ -655,12 +655,12 @@ real_t RigidBody2D::get_friction() const { void RigidBody2D::set_bounce(real_t p_bounce) { - if (p_bounce == 0.0) { // default value, don't create an override for that + if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } - ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); @@ -672,8 +672,8 @@ void RigidBody2D::set_bounce(real_t p_bounce) { } real_t RigidBody2D::get_bounce() const { - ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 0; @@ -1198,6 +1198,9 @@ bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) { + if (sync_to_physics) { + ERR_PRINT("Functions move_and_slide and move_and_collide do not work together with 'sync to physics' option. Please read the documentation."); + } Transform2D gt = get_global_transform(); Physics2DServer::MotionResult result; bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes); @@ -1272,9 +1275,6 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const if (collided) { found_collision = true; - } - - if (collided) { colliders.push_back(collision); motion = collision.remainder; @@ -1290,7 +1290,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const floor_velocity = collision.collider_vel; if (p_stop_on_slope) { - if (Vector2() == lv_n + p_floor_direction && collision.travel.length() < 1) { + if ((lv_n + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) { Transform2D gt = get_global_transform(); gt.elements[2] -= collision.travel.project(p_floor_direction.tangent()); set_global_transform(gt); @@ -1309,9 +1309,6 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const motion = motion.slide(n); lv = lv.slide(n); } - - if (p_stop_on_slope) - break; } if (!found_collision) { @@ -1338,13 +1335,27 @@ Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_veloci Transform2D gt = get_global_transform(); if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { - gt.elements[2] += col.travel; - if (p_floor_direction != Vector2() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { - on_floor = true; - on_floor_body = col.collider_rid; - floor_velocity = col.collider_vel; + bool apply = true; + if (p_floor_direction != Vector2()) { + if (Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { + on_floor = true; + on_floor_body = col.collider_rid; + floor_velocity = col.collider_vel; + if (p_stop_on_slope) { + // move and collide may stray the object a bit because of pre un-stucking, + // so only ensure that motion happens on floor direction in this case. + col.travel = p_floor_direction * p_floor_direction.dot(col.travel); + } + + } else { + apply = false; + } + } + + if (apply) { + gt.elements[2] += col.travel; + set_global_transform(gt); } - set_global_transform(gt); } return ret; diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index c7b42add84..89dd1e5341 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index aa6d57a67d..f6f1bad581 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -81,7 +81,15 @@ bool Polygon2D::_edit_use_rect() const { bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - return Geometry::is_point_in_polygon(p_point - get_offset(), Variant(polygon)); + Vector<Vector2> polygon2d = Variant(polygon); + if (internal_vertices > 0) { + polygon2d.resize(polygon2d.size() - internal_vertices); + } + return Geometry::is_point_in_polygon(p_point - get_offset(), polygon2d); +} + +void Polygon2D::_skeleton_bone_setup_changed() { + update(); } void Polygon2D::_notification(int p_what) { @@ -98,19 +106,44 @@ void Polygon2D::_notification(int p_what) { skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton)); } - if (skeleton_node) + ObjectID new_skeleton_id = 0; + + if (skeleton_node) { VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton()); - else + new_skeleton_id = skeleton_node->get_instance_id(); + } else { VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID()); + } + + if (new_skeleton_id != current_skeleton_id) { + Object *old_skeleton = ObjectDB::get_instance(current_skeleton_id); + if (old_skeleton) { + old_skeleton->disconnect("bone_setup_changed", this, "_skeleton_bone_setup_changed"); + } + + if (skeleton_node) { + skeleton_node->connect("bone_setup_changed", this, "_skeleton_bone_setup_changed"); + } + + current_skeleton_id = new_skeleton_id; + } Vector<Vector2> points; Vector<Vector2> uvs; Vector<int> bones; Vector<float> weights; - points.resize(polygon.size()); + int len = polygon.size(); + if ((invert || polygons.size() == 0) && internal_vertices > 0) { + //if no polygons are around, internal vertices must not be drawn, else let them be + len -= internal_vertices; + } + + if (len <= 0) { + return; + } + points.resize(len); - int len = points.size(); { PoolVector<Vector2>::Read polyr = polygon.read(); @@ -177,7 +210,8 @@ void Polygon2D::_notification(int p_what) { Transform2D texmat(tex_rot, tex_ofs); texmat.scale(tex_scale); Size2 tex_size = texture->get_size(); - uvs.resize(points.size()); + + uvs.resize(len); if (points.size() == uv.size()) { @@ -196,7 +230,7 @@ void Polygon2D::_notification(int p_what) { if (skeleton_node && !invert && bone_weights.size()) { //a skeleton is set! fill indices and weights - int vc = points.size(); + int vc = len; bones.resize(vc * 4); weights.resize(vc * 4); @@ -258,93 +292,247 @@ void Polygon2D::_notification(int p_what) { } Vector<Color> colors; - int color_len = vertex_colors.size(); - colors.resize(len); - { + if (vertex_colors.size() == points.size()) { + colors.resize(len); PoolVector<Color>::Read color_r = vertex_colors.read(); - for (int i = 0; i < color_len && i < len; i++) { + for (int i = 0; i < len; i++) { colors.write[i] = color_r[i]; } - for (int i = color_len; i < len; i++) { - colors.write[i] = color; - } + } else { + colors.push_back(color); } // Vector<int> indices = Geometry::triangulate_polygon(points); // VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); - if (invert || splits.size() == 0) { + if (invert || polygons.size() == 0) { Vector<int> indices = Geometry::triangulate_polygon(points); - VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); + if (indices.size()) { + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); + } } else { + //draw individual polygons + Vector<int> total_indices; + for (int i = 0; i < polygons.size(); i++) { + PoolVector<int> src_indices = polygons[i]; + int ic = src_indices.size(); + if (ic < 3) + continue; + PoolVector<int>::Read r = src_indices.read(); + + Vector<Vector2> tmp_points; + tmp_points.resize(ic); + + for (int j = 0; j < ic; j++) { + int idx = r[j]; + ERR_CONTINUE(idx < 0 || idx >= points.size()); + tmp_points.write[j] = points[r[j]]; + } + Vector<int> indices = Geometry::triangulate_polygon(tmp_points); + int ic2 = indices.size(); + const int *r2 = indices.ptr(); + + int bic = total_indices.size(); + total_indices.resize(bic + ic2); + int *w2 = total_indices.ptrw(); + + for (int j = 0; j < ic2; j++) { + w2[j + bic] = r[r2[j]]; + } + } + + if (total_indices.size()) { + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), total_indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); + } + +#if 0 //use splits Vector<int> loop; int sc = splits.size(); PoolVector<int>::Read r = splits.read(); - int last = points.size(); + + print_line("has splits, amount " + itos(splits.size())); Vector<Vector<int> > loops; - for (int i = 0; i < last; i++) { + // find a point that can be used to begin, must not be in a split, and have to the left and right the same one + // like this one -> x---o + // \ / \ . + // o---o + int base_point = -1; + { + int current_point = -1; + int base_point_prev_split = -1; + + + for (int i = 0; i < points.size(); i++) { + + //find if this point is in a split + int split_index = -1; + bool has_prev_split = false; + int min_dist_to_end = 0x7FFFFFFF; + + for (int j = 0; j < sc; j += 2) { + + int split_pos = -1; + int split_end = -1; + + if (r[j + 0] == i) { //found split in first point + split_pos = r[j + 0]; + split_end = r[j + 1]; + } else if (r[j + 1] == i) { //found split in second point + split_pos = r[j + 1]; + split_end = r[j + 0]; + } + + if (split_pos == split_end) { + continue; //either nothing found or begin == end, this not a split in either case + } + + if (j == base_point_prev_split) { + has_prev_split = true; + } + + //compute distance from split pos to split end in current traversal direction + int dist_to_end = split_end > split_pos ? split_end - split_pos : (last - split_pos + split_end); + + if (dist_to_end < min_dist_to_end) { + //always keep the valid split with the least distance to the loop + min_dist_to_end = dist_to_end; + split_index = j; + } + } + + if (split_index == -1) { + current_point = i; //no split here, we are testing this point + } else if (has_prev_split) { + base_point = current_point; // there is a split and it contains the previous visited split, success + break; + } else { + //invalidate current point and keep split + current_point = -1; + base_point_prev_split = split_index; + } + } + } + + print_line("found base point: " + itos(base_point)); - int split; - int min_end = -1; + if (base_point != -1) { + int point = base_point; + int last = base_point; + //go through all the points, find splits do { - loop.push_back(i); + int split; + int last_dist_to_end = -1; //maximum valid distance to end - split = -1; - int end = -1; + do { - for (int j = 0; j < sc; j += 2) { - if (r[j + 1] >= last) - continue; //no longer valid - if (min_end != -1 && r[j + 1] >= min_end) - continue; - if (r[j] == i) { - if (split == -1 || r[j + 1] > end) { - split = r[j]; - end = r[j + 1]; + loop.push_back(point); //push current point + + split = -1; + int end = -1; + + int max_dist_to_end = 0; + + //find if this point is in a split + for (int j = 0; j < sc; j += 2) { + + int split_pos = -1; + int split_end = -1; + + if (r[j + 0] == point) { //match first split index + split_pos = r[j + 0]; + split_end = r[j + 1]; + } else if (r[j + 1] == point) { //match second split index + split_pos = r[j + 1]; + split_end = r[j + 0]; + } + + if (split_pos == split_end) { + continue; //either nothing found or begin == end, this not a split in either case + } + + //compute distance from split pos to split end + int dist_to_end = split_end > split_pos ? split_end - split_pos : (points.size() - split_pos + split_end); + + if (last_dist_to_end != -1 && dist_to_end >= last_dist_to_end) { + //distance must be shorter than in last iteration, means we've tested this before so ignore + continue; + } else if (dist_to_end > max_dist_to_end) { + //always keep the valid point with the most distance (as long as it's valid) + max_dist_to_end = dist_to_end; + split = split_pos; + end = split_end; } } - } - if (split != -1) { - for (int j = end; j < last; j++) { - loop.push_back(j); + if (split != -1) { + //found a split! + int from = end; + + //add points until last is reached + while (true) { + //find if point is in a split + loop.push_back(from); + + if (from == last) { + break; + } + + from++; + if (from >= points.size()) { //wrap if reached end + from = 0; + } + + if (from == loop[0]) { + break; //end because we reached split source + } + } + + loops.push_back(loop); //done with this loop + loop.clear(); + + last_dist_to_end = max_dist_to_end; + last = end; //algorithm can safely finish in this split point } - loops.push_back(loop); - last = end + 1; - loop.clear(); - min_end = end; //avoid this split from repeating - } - } while (split != -1); + } while (split != -1); + + } while (point != last); } - if (loop.size()) { + if (loop.size() >=2 ) { //points remained + //points remain + loop.push_back(last); //no splits found, use last loops.push_back(loop); } - Vector<int> indices; + print_line("total loops: " + itos(loops.size())); - for (int i = 0; i < loops.size(); i++) { - Vector<int> loop = loops[i]; - Vector<Vector2> vertices; - vertices.resize(loop.size()); - for (int j = 0; j < vertices.size(); j++) { - vertices.write[j] = points[loop[j]]; - } - Vector<int> sub_indices = Geometry::triangulate_polygon(vertices); - int from = indices.size(); - indices.resize(from + sub_indices.size()); - for (int j = 0; j < sub_indices.size(); j++) { - indices.write[from + j] = loop[sub_indices[j]]; + if (loops.size()) { //loops found + Vector<int> indices; + + for (int i = 0; i < loops.size(); i++) { + Vector<int> loop = loops[i]; + Vector<Vector2> vertices; + vertices.resize(loop.size()); + for (int j = 0; j < vertices.size(); j++) { + vertices.write[j] = points[loop[j]]; + } + Vector<int> sub_indices = Geometry::triangulate_polygon(vertices); + int from = indices.size(); + indices.resize(from + sub_indices.size()); + for (int j = 0; j < sub_indices.size(); j++) { + indices.write[from + j] = loop[sub_indices[j]]; + } } - } - VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); + } +#endif } } break; @@ -362,6 +550,15 @@ PoolVector<Vector2> Polygon2D::get_polygon() const { return polygon; } +void Polygon2D::set_internal_vertex_count(int p_count) { + + internal_vertices = p_count; +} + +int Polygon2D::get_internal_vertex_count() const { + return internal_vertices; +} + void Polygon2D::set_uv(const PoolVector<Vector2> &p_uv) { uv = p_uv; @@ -373,16 +570,15 @@ PoolVector<Vector2> Polygon2D::get_uv() const { return uv; } -void Polygon2D::set_splits(const PoolVector<int> &p_splits) { +void Polygon2D::set_polygons(const Array &p_polygons) { - ERR_FAIL_COND(p_splits.size() & 1); //splits should be multiple of 2 - splits = p_splits; + polygons = p_polygons; update(); } -PoolVector<int> Polygon2D::get_splits() const { +Array Polygon2D::get_polygons() const { - return splits; + return polygons; } void Polygon2D::set_color(const Color &p_color) { @@ -585,8 +781,8 @@ void Polygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color", "color"), &Polygon2D::set_color); ClassDB::bind_method(D_METHOD("get_color"), &Polygon2D::get_color); - ClassDB::bind_method(D_METHOD("set_splits", "splits"), &Polygon2D::set_splits); - ClassDB::bind_method(D_METHOD("get_splits"), &Polygon2D::get_splits); + ClassDB::bind_method(D_METHOD("set_polygons", "polygons"), &Polygon2D::set_polygons); + ClassDB::bind_method(D_METHOD("get_polygons"), &Polygon2D::get_polygons); ClassDB::bind_method(D_METHOD("set_vertex_colors", "vertex_colors"), &Polygon2D::set_vertex_colors); ClassDB::bind_method(D_METHOD("get_vertex_colors"), &Polygon2D::get_vertex_colors); @@ -630,14 +826,15 @@ void Polygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &Polygon2D::set_skeleton); ClassDB::bind_method(D_METHOD("get_skeleton"), &Polygon2D::get_skeleton); + ClassDB::bind_method(D_METHOD("set_internal_vertex_count", "internal_vertex_count"), &Polygon2D::set_internal_vertex_count); + ClassDB::bind_method(D_METHOD("get_internal_vertex_count"), &Polygon2D::get_internal_vertex_count); + ClassDB::bind_method(D_METHOD("_set_bones", "bones"), &Polygon2D::_set_bones); ClassDB::bind_method(D_METHOD("_get_bones"), &Polygon2D::_get_bones); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "uv"), "set_uv", "get_uv"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "splits"), "set_splits", "get_splits"); + ClassDB::bind_method(D_METHOD("_skeleton_bone_setup_changed"), &Polygon2D::_skeleton_bone_setup_changed); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "vertex_colors"), "set_vertex_colors", "get_vertex_colors"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "get_antialiased"); ADD_GROUP("Texture", ""); @@ -654,7 +851,13 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "invert_border", PROPERTY_HINT_RANGE, "0.1,16384,0.1"), "set_invert_border", "get_invert_border"); + ADD_GROUP("Data", ""); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "uv"), "set_uv", "get_uv"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "vertex_colors"), "set_vertex_colors", "get_vertex_colors"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons"), "set_polygons", "get_polygons"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_bones", "_get_bones"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "internal_vertex_count", PROPERTY_HINT_RANGE, "0,1000"), "set_internal_vertex_count", "get_internal_vertex_count"); } Polygon2D::Polygon2D() { @@ -667,4 +870,6 @@ Polygon2D::Polygon2D() { tex_scale = Vector2(1, 1); color = Color(1, 1, 1); rect_cache_dirty = true; + internal_vertices = 0; + current_skeleton_id = 0; } diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index 575f71d74a..f25b3885b0 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -40,7 +40,8 @@ class Polygon2D : public Node2D { PoolVector<Vector2> polygon; PoolVector<Vector2> uv; PoolVector<Color> vertex_colors; - PoolVector<int> splits; + Array polygons; + int internal_vertices; struct Bone { NodePath path; @@ -64,10 +65,13 @@ class Polygon2D : public Node2D { mutable Rect2 item_rect; NodePath skeleton; + ObjectID current_skeleton_id; Array _get_bones() const; void _set_bones(const Array &p_bones); + void _skeleton_bone_setup_changed(); + protected: void _notification(int p_what); static void _bind_methods(); @@ -87,11 +91,14 @@ public: void set_polygon(const PoolVector<Vector2> &p_polygon); PoolVector<Vector2> get_polygon() const; + void set_internal_vertex_count(int p_count); + int get_internal_vertex_count() const; + void set_uv(const PoolVector<Vector2> &p_uv); PoolVector<Vector2> get_uv() const; - void set_splits(const PoolVector<int> &p_uv); - PoolVector<int> get_splits() const; + void set_polygons(const Array &p_polygons); + Array get_polygons() const; void set_color(const Color &p_color); Color get_color() const; diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index 543314eefa..f0c46a5fb7 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -33,15 +33,19 @@ #include "core/engine.h" #include "scene/resources/texture.h" +const float DEFAULT_GIZMO_EXTENTS = 10.0; + void Position2D::_draw_cross() { - draw_line(Point2(-10, 0), Point2(+10, 0), Color(1, 0.5, 0.5)); - draw_line(Point2(0, -10), Point2(0, +10), Color(0.5, 1, 0.5)); + 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)); } Rect2 Position2D::_edit_get_rect() const { - return Rect2(Point2(-10, -10), Size2(20, 20)); + float extents = get_gizmo_extents(); + return Rect2(Point2(-extents, -extents), Size2(extents * 2, extents * 2)); } bool Position2D::_edit_use_rect() const { @@ -66,5 +70,31 @@ void Position2D::_notification(int p_what) { } } +void Position2D::set_gizmo_extents(float p_extents) { + if (p_extents == DEFAULT_GIZMO_EXTENTS) { + set_meta("_gizmo_extents_", Variant()); + } else { + set_meta("_gizmo_extents_", p_extents); + } + + update(); +} + +float Position2D::get_gizmo_extents() const { + if (has_meta("_gizmo_extents_")) { + return get_meta("_gizmo_extents_"); + } else { + return DEFAULT_GIZMO_EXTENTS; + } +} + +void Position2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_set_gizmo_extents", "extents"), &Position2D::set_gizmo_extents); + ClassDB::bind_method(D_METHOD("_get_gizmo_extents"), &Position2D::get_gizmo_extents); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "gizmo_extents", PROPERTY_HINT_RANGE, "0,1000,0.1,or_greater", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_gizmo_extents", "_get_gizmo_extents"); +} + Position2D::Position2D() { } diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h index bff474cccd..f5ec3ef01a 100644 --- a/scene/2d/position_2d.h +++ b/scene/2d/position_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -35,16 +35,21 @@ class Position2D : public Node2D { - GDCLASS(Position2D, Node2D) + GDCLASS(Position2D, Node2D); void _draw_cross(); protected: void _notification(int p_what); + static void _bind_methods(); public: virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; + + void set_gizmo_extents(float p_extents); + float get_gizmo_extents() const; + Position2D(); }; diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index f7c18a17df..57dfe5176d 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index a438be87b6..f53f3ff07b 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index f0274e5206..1c38a91877 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h index 3f395f820e..16a5417592 100644 --- a/scene/2d/remote_transform_2d.h +++ b/scene/2d/remote_transform_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 1c504d00fc..aa15255384 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -203,6 +203,7 @@ void Skeleton2D::_update_bone_setup() { transform_dirty = true; _update_transform(); + emit_signal("bone_setup_changed"); } void Skeleton2D::_make_transform_dirty() { @@ -291,6 +292,8 @@ void Skeleton2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone", "idx"), &Skeleton2D::get_bone); ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton); + + ADD_SIGNAL(MethodInfo("bone_setup_changed")); } Skeleton2D::Skeleton2D() { diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 9d0a061457..0f48b44387 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -36,9 +36,12 @@ class Skeleton2D; class Bone2D : public Node2D { - GDCLASS(Bone2D, Node2D) + GDCLASS(Bone2D, Node2D); friend class Skeleton2D; +#ifdef TOOLS_ENABLED + friend class AnimatedValuesBackup; +#endif Bone2D *parent_bone; Skeleton2D *skeleton; @@ -71,6 +74,9 @@ class Skeleton2D : public Node2D { GDCLASS(Skeleton2D, Node2D); friend class Bone2D; +#ifdef TOOLS_ENABLED + friend class AnimatedValuesBackup; +#endif struct Bone { bool operator<(const Bone &p_bone) const { diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index f4e6e2bdbb..a8c7622828 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -363,7 +363,7 @@ Rect2 Sprite::get_rect() const { Point2 ofs = offset; if (centered) - ofs -= s / 2; + ofs -= Size2(s) / 2; if (s == Size2(0, 0)) s = Size2(1, 1); diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h index ab444f89fc..e38db3a299 100644 --- a/scene/2d/sprite.h +++ b/scene/2d/sprite.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index ee76a90019..b3b6f3175d 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -75,15 +75,15 @@ void TileMap::_notification(int p_what) { Quadrant &q = E->get(); if (navigation) { - for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) { + for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) { - navigation->navpoly_remove(E->get().id); + navigation->navpoly_remove(F->get().id); } q.navpoly_ids.clear(); } - for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) { - VS::get_singleton()->free(E->get().id); + for (Map<PosKey, Quadrant::Occluder>::Element *F = q.occluder_instances.front(); F; F = F->next()) { + VS::get_singleton()->free(F->get().id); } q.occluder_instances.clear(); } @@ -129,14 +129,14 @@ void TileMap::_update_quadrant_transform() { Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform); if (navigation) { - for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) { + for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) { - navigation->navpoly_set_transform(E->get().id, nav_rel * E->get().xform); + navigation->navpoly_set_transform(F->get().id, nav_rel * F->get().xform); } } - for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) { - VS::get_singleton()->canvas_light_occluder_set_transform(E->get().id, global_transform * E->get().xform); + for (Map<PosKey, Quadrant::Occluder>::Element *F = q.occluder_instances.front(); F; F = F->next()) { + VS::get_singleton()->canvas_light_occluder_set_transform(F->get().id, global_transform * F->get().xform); } } } @@ -202,47 +202,27 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Size2 s = p_sc; Vector2 offset = p_offset; - if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) - offset.y += cell_size.y; - else if (tile_origin == TILE_ORIGIN_CENTER) { - offset += cell_size / 2; - } - - if (s.y > s.x) { - if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose)) - offset.y += s.y - s.x; - } else if (s.y < s.x) { - if ((p_cell.flip_v && (p_cell.flip_h || p_cell.transpose)) || (p_cell.flip_h && !p_cell.transpose)) - offset.x += s.x - s.y; - } - if (p_cell.transpose) { SWAP(xform.elements[0].x, xform.elements[0].y); SWAP(xform.elements[1].x, xform.elements[1].y); SWAP(offset.x, offset.y); SWAP(s.x, s.y); } + if (p_cell.flip_h) { xform.elements[0].x = -xform.elements[0].x; xform.elements[1].x = -xform.elements[1].x; - if (tile_origin == TILE_ORIGIN_TOP_LEFT || tile_origin == TILE_ORIGIN_BOTTOM_LEFT) - offset.x = s.x - offset.x; - else if (tile_origin == TILE_ORIGIN_CENTER) - offset.x = s.x - offset.x / 2; + offset.x = s.x - offset.x; } + if (p_cell.flip_v) { xform.elements[0].y = -xform.elements[0].y; xform.elements[1].y = -xform.elements[1].y; - if (tile_origin == TILE_ORIGIN_TOP_LEFT) - offset.y = s.y - offset.y; - else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - offset.y += s.y; - } else if (tile_origin == TILE_ORIGIN_CENTER) { - offset.y += s.y; - } + offset.y = s.y - offset.y; } - xform.elements[2].x += offset.x; - xform.elements[2].y += offset.y; + /* For a future CheckBox to Center Texture: + offset += cell_size / 2 - s / 2; */ + xform.elements[2] += offset; } void TileMap::update_dirty_quadrants() { @@ -377,13 +357,12 @@ void TileMap::update_dirty_quadrants() { r.size = tile_set->autotile_get_size(c.id); r.position += (r.size + Vector2(spacing, spacing)) * Vector2(c.autotile_coord_x, c.autotile_coord_y); } - Size2 s = tex->get_size(); + Size2 s; if (r == Rect2()) s = tex->get_size(); - else { + else s = r.size; - } Rect2 rect; rect.position = offset.floor(); @@ -391,64 +370,26 @@ void TileMap::update_dirty_quadrants() { rect.size.x += fp_adjust; rect.size.y += fp_adjust; - if (rect.size.y > rect.size.x) { - if ((c.flip_h && (c.flip_v || c.transpose)) || (c.flip_v && !c.transpose)) - tile_ofs.y += rect.size.y - rect.size.x; - } else if (rect.size.y < rect.size.x) { - if ((c.flip_v && (c.flip_h || c.transpose)) || (c.flip_h && !c.transpose)) - tile_ofs.x += rect.size.x - rect.size.y; - } - - /* rect.size.x+=fp_adjust; - rect.size.y+=fp_adjust;*/ - - if (c.transpose) + if (c.transpose) { SWAP(tile_ofs.x, tile_ofs.y); + /* For a future CheckBox to Center Texture: + rect.position.x += cell_size.x / 2 - rect.size.y / 2; + rect.position.y += cell_size.y / 2 - rect.size.x / 2; + } else { + rect.position += cell_size / 2 - rect.size / 2; */ + } if (c.flip_h) { rect.size.x = -rect.size.x; tile_ofs.x = -tile_ofs.x; } + if (c.flip_v) { rect.size.y = -rect.size.y; tile_ofs.y = -tile_ofs.y; } - Vector2 center_ofs; - - if (tile_origin == TILE_ORIGIN_TOP_LEFT) { - rect.position += tile_ofs; - - } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - - rect.position += tile_ofs; - - if (c.transpose) { - if (c.flip_h) - rect.position.x -= cell_size.x; - else - rect.position.x += cell_size.x; - } else { - if (c.flip_v) - rect.position.y -= cell_size.y; - else - rect.position.y += cell_size.y; - } - - } else if (tile_origin == TILE_ORIGIN_CENTER) { - - rect.position += tile_ofs; - - if (c.flip_h) - rect.position.x -= cell_size.x / 2; - else - rect.position.x += cell_size.x / 2; - - if (c.flip_v) - rect.position.y -= cell_size.y / 2; - else - rect.position.y += cell_size.y / 2; - } + rect.position += tile_ofs; Ref<Texture> normal_map = tile_set->tile_get_normal_map(c.id); Color modulate = tile_set->tile_get_modulate(c.id); @@ -463,27 +404,45 @@ void TileMap::update_dirty_quadrants() { Vector<TileSet::ShapeData> shapes = tile_set->tile_get_shapes(c.id); - for (int i = 0; i < shapes.size(); i++) { - Ref<Shape2D> shape = shapes[i].shape; + for (int j = 0; j < shapes.size(); j++) { + Ref<Shape2D> shape = shapes[j].shape; if (shape.is_valid()) { - if (tile_set->tile_get_tile_mode(c.id) == TileSet::SINGLE_TILE || (shapes[i].autotile_coord.x == c.autotile_coord_x && shapes[i].autotile_coord.y == c.autotile_coord_y)) { + if (tile_set->tile_get_tile_mode(c.id) == TileSet::SINGLE_TILE || (shapes[j].autotile_coord.x == c.autotile_coord_x && shapes[j].autotile_coord.y == c.autotile_coord_y)) { Transform2D xform; xform.set_origin(offset.floor()); - Vector2 shape_ofs = shapes[i].shape_transform.get_origin(); + Vector2 shape_ofs = shapes[j].shape_transform.get_origin(); - _fix_cell_transform(xform, c, shape_ofs + center_ofs, s); + _fix_cell_transform(xform, c, shape_ofs, s); - xform *= shapes[i].shape_transform.untranslated(); + xform *= shapes[j].shape_transform.untranslated(); if (debug_canvas_item.is_valid()) { vs->canvas_item_add_set_transform(debug_canvas_item, xform); shape->draw(debug_canvas_item, debug_collision_color); } - ps->body_add_shape(q.body, shape->get_rid(), xform); - ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y)); - ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[i].one_way_collision); - shape_idx++; + + if (shape->has_meta("decomposed")) { + Array _shapes = shape->get_meta("decomposed"); + for (int k = 0; k < _shapes.size(); k++) { + Ref<ConvexPolygonShape2D> convex = _shapes[k]; + if (convex.is_valid()) { + ps->body_add_shape(q.body, convex->get_rid(), xform); + ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y)); + ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[j].one_way_collision, shapes[j].one_way_collision_margin); + shape_idx++; +#ifdef DEBUG_ENABLED + } else { + print_error("The TileSet assigned to the TileMap " + get_name() + " has an invalid convex shape."); +#endif + } + } + } else { + ps->body_add_shape(q.body, shape->get_rid(), xform); + ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y)); + ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[j].one_way_collision, shapes[j].one_way_collision_margin); + shape_idx++; + } } } } @@ -506,7 +465,7 @@ void TileMap::update_dirty_quadrants() { if (navpoly.is_valid()) { Transform2D xform; xform.set_origin(offset.floor() + q.pos); - _fix_cell_transform(xform, c, npoly_ofs + center_ofs, s); + _fix_cell_transform(xform, c, npoly_ofs, s); int pid = navigation->navpoly_add(navpoly, nav_rel * xform); @@ -532,23 +491,23 @@ void TileMap::update_dirty_quadrants() { colors.resize(vsize); { PoolVector<Vector2>::Read vr = navigation_polygon_vertices.read(); - for (int i = 0; i < vsize; i++) { - vertices.write[i] = vr[i]; - colors.write[i] = debug_navigation_color; + for (int j = 0; j < vsize; j++) { + vertices.write[j] = vr[j]; + colors.write[j] = debug_navigation_color; } } Vector<int> indices; - for (int i = 0; i < navpoly->get_polygon_count(); i++) { - Vector<int> polygon = navpoly->get_polygon(i); + for (int j = 0; j < navpoly->get_polygon_count(); j++) { + Vector<int> polygon = navpoly->get_polygon(j); - for (int j = 2; j < polygon.size(); j++) { + for (int k = 2; k < polygon.size(); k++) { - int kofs[3] = { 0, j - 1, j }; - for (int k = 0; k < 3; k++) { + int kofs[3] = { 0, k - 1, k }; + for (int l = 0; l < 3; l++) { - int idx = polygon[kofs[k]]; + int idx = polygon[kofs[l]]; ERR_FAIL_INDEX(idx, vsize); indices.push_back(idx); } @@ -556,7 +515,7 @@ void TileMap::update_dirty_quadrants() { } Transform2D navxform; navxform.set_origin(offset.floor()); - _fix_cell_transform(navxform, c, npoly_ofs + center_ofs, s); + _fix_cell_transform(navxform, c, npoly_ofs, s); vs->canvas_item_set_transform(debug_navigation_item, navxform); vs->canvas_item_add_triangle_array(debug_navigation_item, indices, vertices, colors); @@ -576,7 +535,7 @@ void TileMap::update_dirty_quadrants() { Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id); Transform2D xform; xform.set_origin(offset.floor() + q.pos); - _fix_cell_transform(xform, c, occluder_ofs + center_ofs, s); + _fix_cell_transform(xform, c, occluder_ofs, s); RID orid = VS::get_singleton()->canvas_light_occluder_create(); VS::get_singleton()->canvas_light_occluder_set_transform(orid, get_global_transform() * xform); @@ -602,9 +561,9 @@ void TileMap::update_dirty_quadrants() { for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { Quadrant &q = E->get(); - for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) { + for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) { - VS::get_singleton()->canvas_item_set_draw_index(E->get(), index++); + VS::get_singleton()->canvas_item_set_draw_index(F->get(), index++); } } @@ -732,7 +691,10 @@ void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_ void TileMap::_set_celld(const Vector2 &p_pos, const Dictionary &p_data) { - set_cell(p_pos.x, p_pos.y, p_data["id"], p_data["flip_h"], p_data["flip_y"], p_data["transpose"], p_data["auto_coord"]); + Variant v_pos_x = p_pos.x, v_pos_y = p_pos.y, v_tile = p_data["id"], v_flip_h = p_data["flip_h"], v_flip_v = p_data["flip_y"], v_transpose = p_data["transpose"], v_autotile_coord = p_data["auto_coord"]; + const Variant *args[7] = { &v_pos_x, &v_pos_y, &v_tile, &v_flip_h, &v_flip_v, &v_transpose, &v_autotile_coord }; + Variant::CallError ce; + call("set_cell", args, 7, ce); } void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose, Vector2 p_autotile_coord) { @@ -756,6 +718,7 @@ void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_ else _make_quadrant_dirty(Q); + used_size_cache_dirty = true; return; } @@ -840,7 +803,7 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) { Map<PosKey, Cell>::Element *E = tile_map.find(p); if (E != NULL) { int id = get_cell(p_x, p_y); - if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) { + if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE) { uint16_t mask = 0; if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_2X2) { if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { @@ -904,9 +867,19 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) { PosKey qk(p_x / _get_quadrant_size(), p_y / _get_quadrant_size()); Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk); _make_quadrant_dirty(Q); - } else { + + } else if (tile_set->tile_get_tile_mode(id) == TileSet::SINGLE_TILE) { + E->get().autotile_coord_x = 0; E->get().autotile_coord_y = 0; + } else if (tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) { + + if (tile_set->autotile_get_bitmask(id, Vector2(p_x, p_y)) == TileSet::BIND_CENTER) { + Vector2 coord = tile_set->atlastile_get_subtile_by_priority(id, this, Vector2(p_x, p_y)); + + E->get().autotile_coord_x = (int)coord.x; + E->get().autotile_coord_y = (int)coord.y; + } } } } @@ -1053,9 +1026,9 @@ void TileMap::_update_all_items_material_state() { for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { Quadrant &q = E->get(); - for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) { + for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) { - _update_item_material_state(E->get()); + _update_item_material_state(F->get()); } } } @@ -1373,18 +1346,21 @@ Vector2 TileMap::_map_to_world(int p_x, int p_y, bool p_ignore_ofs) const { if (!p_ignore_ofs) { switch (half_offset) { - case HALF_OFFSET_X: { + case HALF_OFFSET_X: + case HALF_OFFSET_NEGATIVE_X: { if (ABS(p_y) & 1) { - ret += get_cell_transform()[0] * 0.5; + ret += get_cell_transform()[0] * (half_offset == HALF_OFFSET_X ? 0.5 : -0.5); } } break; - case HALF_OFFSET_Y: { + case HALF_OFFSET_Y: + case HALF_OFFSET_NEGATIVE_Y: { if (ABS(p_x) & 1) { - ret += get_cell_transform()[1] * 0.5; + ret += get_cell_transform()[1] * (half_offset == HALF_OFFSET_Y ? 0.5 : -0.5); } } break; - default: {} + default: { + } } } return ret; @@ -1444,16 +1420,27 @@ Vector2 TileMap::world_to_map(const Vector2 &p_pos) const { ret.x -= 0.5; } } break; + case HALF_OFFSET_NEGATIVE_X: { + if (ret.y > 0 ? int(ret.y) & 1 : (int(ret.y) - 1) & 1) { + ret.x += 0.5; + } + } break; case HALF_OFFSET_Y: { if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) { ret.y -= 0.5; } } break; - default: {} + case HALF_OFFSET_NEGATIVE_Y: { + if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) { + ret.y += 0.5; + } + } break; + default: { + } } // Account for precision errors on the border (GH-23250). - // 0.00005 is 5*CMP_EPSILON, results would start being unpredictible if + // 0.00005 is 5*CMP_EPSILON, results would start being unpredictable if // cell size is > 15,000, but we can hardly have more precision anyway with // floating point. ret += Vector2(0.00005, 0.00005); @@ -1630,6 +1617,8 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("is_cell_y_flipped", "x", "y"), &TileMap::is_cell_y_flipped); ClassDB::bind_method(D_METHOD("is_cell_transposed", "x", "y"), &TileMap::is_cell_transposed); + ClassDB::bind_method(D_METHOD("get_cell_autotile_coord", "x", "y"), &TileMap::get_cell_autotile_coord); + ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles); ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear); @@ -1657,7 +1646,7 @@ void TileMap::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size", PROPERTY_HINT_RANGE, "1,8192,1"), "set_cell_size", "get_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_quadrant_size", "get_quadrant_size"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "cell_custom_transform"), "set_custom_transform", "get_custom_transform"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled"), "set_half_offset", "get_half_offset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled,Offset Negative X,Offset Negative Y"), "set_half_offset", "get_half_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_tile_origin", PROPERTY_HINT_ENUM, "Top Left,Center,Bottom Left"), "set_tile_origin", "get_tile_origin"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_y_sort"), "set_y_sort_mode", "is_y_sort_mode_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_clip_uv"), "set_clip_uv", "get_clip_uv"); @@ -1683,6 +1672,8 @@ void TileMap::_bind_methods() { BIND_ENUM_CONSTANT(HALF_OFFSET_X); BIND_ENUM_CONSTANT(HALF_OFFSET_Y); BIND_ENUM_CONSTANT(HALF_OFFSET_DISABLED); + BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_X); + BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_Y); BIND_ENUM_CONSTANT(TILE_ORIGIN_TOP_LEFT); BIND_ENUM_CONSTANT(TILE_ORIGIN_CENTER); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 499c79b180..6a1467aa48 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -33,7 +33,7 @@ #include "core/self_list.h" #include "core/vset.h" -#include "scene/2d/navigation2d.h" +#include "scene/2d/navigation_2d.h" #include "scene/2d/node_2d.h" #include "scene/resources/tile_set.h" @@ -52,6 +52,8 @@ public: HALF_OFFSET_X, HALF_OFFSET_Y, HALF_OFFSET_DISABLED, + HALF_OFFSET_NEGATIVE_X, + HALF_OFFSET_NEGATIVE_Y, }; enum TileOrigin { diff --git a/scene/2d/screen_button.cpp b/scene/2d/touch_screen_button.cpp index 44a41328e8..9a1a759e72 100644 --- a/scene/2d/screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* screen_button.cpp */ +/* touch_screen_button.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,7 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "screen_button.h" +#include "touch_screen_button.h" + #include "core/input_map.h" #include "core/os/input.h" #include "core/os/os.h" diff --git a/scene/2d/screen_button.h b/scene/2d/touch_screen_button.h index 3e8adc2e5e..df54e5340b 100644 --- a/scene/2d/screen_button.h +++ b/scene/2d/touch_screen_button.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* screen_button.h */ +/* touch_screen_button.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SCREEN_BUTTON_H -#define SCREEN_BUTTON_H +#ifndef TOUCH_SCREEN_BUTTON_H +#define TOUCH_SCREEN_BUTTON_H #include "scene/2d/node_2d.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" #include "scene/resources/rectangle_shape_2d.h" #include "scene/resources/texture.h" @@ -112,4 +112,4 @@ public: VARIANT_ENUM_CAST(TouchScreenButton::VisibilityMode); -#endif // SCREEN_BUTTON_H +#endif // TOUCH_SCREEN_BUTTON_H diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index d656ba0f64..1cf037daf2 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h index 04084b609a..259368455b 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visibility_notifier_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/y_sort.cpp b/scene/2d/y_sort.cpp index d3997c13c3..d7e523e189 100644 --- a/scene/2d/y_sort.cpp +++ b/scene/2d/y_sort.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/2d/y_sort.h b/scene/2d/y_sort.h index 5ff12aa25a..1bf757720e 100644 --- a/scene/2d/y_sort.h +++ b/scene/2d/y_sort.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/SCsub b/scene/3d/SCsub index 35cc7479d8..200cf4316f 100644 --- a/scene/3d/SCsub +++ b/scene/3d/SCsub @@ -7,6 +7,6 @@ if env['disable_3d']: env.scene_sources.append("3d/skeleton.cpp") env.scene_sources.append("3d/particles.cpp") env.scene_sources.append("3d/visual_instance.cpp") - env.scene_sources.append("3d/scenario_fx.cpp") + env.scene_sources.append("3d/world_environment.cpp") else: env.add_source_files(env.scene_sources, "*.cpp") diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index ac77ddb7ce..4247266e3d 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -356,7 +356,9 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar Map<ObjectID, AreaState>::Element *E = area_map.find(objid); - ERR_FAIL_COND(!area_in && !E); + if (!area_in && !E) { + return; //likely removed from the tree + } locked = true; @@ -439,10 +441,10 @@ Array Area::get_overlapping_bodies() const { void Area::set_monitorable(bool p_enable) { - if (locked || PhysicsServer::get_singleton()->is_flushing_queries()) { + if (locked || (is_inside_tree() && PhysicsServer::get_singleton()->is_flushing_queries())) { ERR_EXPLAIN("Function blocked during in/out signal. Use set_deferred(\"monitorable\",true/false)"); + ERR_FAIL(); } - ERR_FAIL_COND(locked || PhysicsServer::get_singleton()->is_flushing_queries()); if (p_enable == monitorable) return; @@ -750,12 +752,12 @@ Area::Area() : gravity_is_point = false; gravity_distance_scale = 0; linear_damp = 0.1; - angular_damp = 1; + angular_damp = 0.1; priority = 0; monitoring = false; + monitorable = false; collision_mask = 1; collision_layer = 1; - set_ray_pickable(false); set_monitoring(true); set_monitorable(true); diff --git a/scene/3d/area.h b/scene/3d/area.h index e1ff1079e3..043d651e04 100644 --- a/scene/3d/area.h +++ b/scene/3d/area.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp index 7ea62678da..95eec41fb2 100644 --- a/scene/3d/arvr_nodes.cpp +++ b/scene/3d/arvr_nodes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -127,7 +127,7 @@ Point2 ARVRCamera::unproject_position(const Vector3 &p_pos) const { return res; }; -Vector3 ARVRCamera::project_position(const Point2 &p_point) const { +Vector3 ARVRCamera::project_position(const Point2 &p_point, float p_z_depth) const { // get our ARVRServer ARVRServer *arvr_server = ARVRServer::get_singleton(); ERR_FAIL_NULL_V(arvr_server, Vector3()); @@ -135,7 +135,7 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const { Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface(); if (arvr_interface.is_null()) { // we might be in the editor or have VR turned off, just call superclass - return Camera::project_position(p_point); + return Camera::project_position(p_point, p_z_depth); } if (!is_inside_tree()) { @@ -155,7 +155,7 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const { point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0; point *= vp_size; - Vector3 p(point.x, point.y, -get_znear()); + Vector3 p(point.x, point.y, -p_z_depth); return get_camera_transform().xform(p); }; @@ -233,6 +233,13 @@ void ARVRController::_notification(int p_what) { } else { button_states = 0; }; + + // check for an updated mesh + Ref<Mesh> trackerMesh = tracker->get_mesh(); + if (mesh != trackerMesh) { + mesh = trackerMesh; + emit_signal("mesh_updated", mesh); + } }; }; break; default: @@ -258,8 +265,11 @@ void ARVRController::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &ARVRController::set_rumble); ADD_PROPERTY(PropertyInfo(Variant::REAL, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble"); + ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRController::get_mesh); + ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button"))); ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button"))); + ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"))); }; void ARVRController::set_controller_id(int p_controller_id) { @@ -341,6 +351,10 @@ void ARVRController::set_rumble(real_t p_rumble) { }; }; +Ref<Mesh> ARVRController::get_mesh() const { + return mesh; +} + bool ARVRController::get_is_active() const { return is_active; }; @@ -365,18 +379,18 @@ String ARVRController::get_configuration_warning() const { // must be child node of ARVROrigin! ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent()); if (origin == NULL) { - return TTR("ARVRController must have an ARVROrigin node as its parent"); + return TTR("ARVRController must have an ARVROrigin node as its parent."); }; if (controller_id == 0) { - return TTR("The controller id must not be 0 or this controller will not be bound to an actual controller"); + return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."); }; return String(); }; ARVRController::ARVRController() { - controller_id = 0; + controller_id = 1; is_active = true; button_states = 0; }; @@ -423,6 +437,13 @@ void ARVRAnchor::_notification(int p_what) { // apply our reference frame and set our transform set_transform(arvr_server->get_reference_frame() * transform); + + // check for an updated mesh + Ref<Mesh> trackerMesh = tracker->get_mesh(); + if (mesh != trackerMesh) { + mesh = trackerMesh; + emit_signal("mesh_updated", mesh); + } }; }; break; default: @@ -441,6 +462,9 @@ void ARVRAnchor::_bind_methods() { ClassDB::bind_method(D_METHOD("get_size"), &ARVRAnchor::get_size); ClassDB::bind_method(D_METHOD("get_plane"), &ARVRAnchor::get_plane); + + ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRAnchor::get_mesh); + ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"))); }; void ARVRAnchor::set_anchor_id(int p_anchor_id) { @@ -482,11 +506,11 @@ String ARVRAnchor::get_configuration_warning() const { // must be child node of ARVROrigin! ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent()); if (origin == NULL) { - return TTR("ARVRAnchor must have an ARVROrigin node as its parent"); + return TTR("ARVRAnchor must have an ARVROrigin node as its parent."); }; if (anchor_id == 0) { - return TTR("The anchor id must not be 0 or this anchor will not be bound to an actual anchor"); + return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."); }; return String(); @@ -501,8 +525,12 @@ Plane ARVRAnchor::get_plane() const { return plane; }; +Ref<Mesh> ARVRAnchor::get_mesh() const { + return mesh; +} + ARVRAnchor::ARVRAnchor() { - anchor_id = 0; + anchor_id = 1; is_active = true; }; @@ -517,7 +545,7 @@ String ARVROrigin::get_configuration_warning() const { return String(); if (tracked_camera == NULL) - return TTR("ARVROrigin requires an ARVRCamera child node"); + return TTR("ARVROrigin requires an ARVRCamera child node."); return String(); }; @@ -555,6 +583,10 @@ void ARVROrigin::set_world_scale(float p_world_scale) { }; void ARVROrigin::_notification(int p_what) { + // get our ARVRServer + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + switch (p_what) { case NOTIFICATION_ENTER_TREE: { set_process_internal(true); @@ -563,10 +595,6 @@ void ARVROrigin::_notification(int p_what) { set_process_internal(false); }; break; case NOTIFICATION_INTERNAL_PROCESS: { - // get our ARVRServer - ARVRServer *arvr_server = ARVRServer::get_singleton(); - ERR_FAIL_NULL(arvr_server); - // set our world origin to our node transform arvr_server->set_world_origin(get_global_transform()); @@ -583,6 +611,14 @@ void ARVROrigin::_notification(int p_what) { default: break; }; + + // send our notification to all active ARVR interfaces, they may need to react to it also + for (int i = 0; i < arvr_server->get_interface_count(); i++) { + Ref<ARVRInterface> interface = arvr_server->get_interface(i); + if (interface.is_valid() && interface->is_initialized()) { + interface->notification(p_what); + } + } }; ARVROrigin::ARVROrigin() { diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h index d6690676cc..8e735f7110 100644 --- a/scene/3d/arvr_nodes.h +++ b/scene/3d/arvr_nodes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -33,6 +33,7 @@ #include "scene/3d/camera.h" #include "scene/3d/spatial.h" +#include "scene/resources/mesh.h" #include "servers/arvr/arvr_positional_tracker.h" /** @@ -54,7 +55,7 @@ public: virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; - virtual Vector3 project_position(const Point2 &p_point) const; + virtual Vector3 project_position(const Point2 &p_point, float p_z_depth = 0) const; virtual Vector<Plane> get_frustum() const; ARVRCamera(); @@ -75,6 +76,7 @@ private: int controller_id; bool is_active; int button_states; + Ref<Mesh> mesh; protected: void _notification(int p_what); @@ -95,6 +97,8 @@ public: bool get_is_active() const; ARVRPositionalTracker::TrackerHand get_hand() const; + Ref<Mesh> get_mesh(void) const; + String get_configuration_warning() const; ARVRController(); @@ -113,6 +117,7 @@ private: int anchor_id; bool is_active; Vector3 size; + Ref<Mesh> mesh; protected: void _notification(int p_what); @@ -128,6 +133,8 @@ public: Plane get_plane() const; + Ref<Mesh> get_mesh(void) const; + String get_configuration_warning() const; ARVRAnchor(); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index afd87deca6..ff8c218575 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,7 +32,9 @@ #include "core/engine.h" #include "scene/3d/area.h" #include "scene/3d/camera.h" +#include "scene/3d/listener.h" #include "scene/main/viewport.h" + void AudioStreamPlayer3D::_mix_audio() { if (!stream_playback.is_valid() || !active || @@ -206,16 +208,17 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const { float att = 0; switch (attenuation_model) { case ATTENUATION_INVERSE_DISTANCE: { - att = Math::linear2db(1.0 / ((p_distance / unit_size) + 000001)); + att = Math::linear2db(1.0 / ((p_distance / unit_size) + CMP_EPSILON)); } break; case ATTENUATION_INVERSE_SQUARE_DISTANCE: { float d = (p_distance / unit_size); d *= d; - att = Math::linear2db(1.0 / (d + 0.00001)); + att = Math::linear2db(1.0 / (d + CMP_EPSILON)); } break; case ATTENUATION_LOGARITHMIC: { - att = -20 * Math::log(p_distance / unit_size + 000001); + att = -20 * Math::log(p_distance / unit_size + CMP_EPSILON); } break; + case ATTENUATION_DISABLED: break; default: { ERR_PRINT("Unknown attenuation type"); break; @@ -323,16 +326,25 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (!vp->is_audio_listener()) continue; - Vector3 local_pos = camera->get_global_transform().orthonormalized().affine_inverse().xform(global_pos); + bool listener_is_camera = true; + Spatial *listener_node = camera; + + Listener *listener = vp->get_listener(); + if (listener) { + listener_node = listener; + listener_is_camera = false; + } + + Vector3 local_pos = listener_node->get_global_transform().orthonormalized().affine_inverse().xform(global_pos); float dist = local_pos.length(); Vector3 area_sound_pos; - Vector3 cam_area_pos; + Vector3 listener_area_pos; if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) { - area_sound_pos = space_state->get_closest_point_to_object_volume(area->get_rid(), camera->get_global_transform().origin); - cam_area_pos = camera->get_global_transform().affine_inverse().xform(area_sound_pos); + area_sound_pos = space_state->get_closest_point_to_object_volume(area->get_rid(), listener_node->get_global_transform().origin); + listener_area_pos = listener_node->get_global_transform().affine_inverse().xform(area_sound_pos); } if (max_distance > 0) { @@ -340,10 +352,10 @@ void AudioStreamPlayer3D::_notification(int p_what) { float total_max = max_distance; if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) { - total_max = MAX(total_max, cam_area_pos.length()); + total_max = MAX(total_max, listener_area_pos.length()); } if (total_max > max_distance) { - continue; //can't hear this sound in this camera + continue; //can't hear this sound in this listener } } @@ -360,8 +372,8 @@ void AudioStreamPlayer3D::_notification(int p_what) { float db_att = (1.0 - MIN(1.0, multiplier)) * attenuation_filter_db; if (emission_angle_enabled) { - Vector3 camtopos = global_pos - camera->get_global_transform().origin; - float c = camtopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative + Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin; + float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative float angle = Math::rad2deg(Math::acos(c)); if (angle > emission_angle) db_att -= -emission_angle_filter_attenuation_db; @@ -381,8 +393,8 @@ void AudioStreamPlayer3D::_notification(int p_what) { output.vol[0].l = 1.0 - c; output.vol[0].r = c; } else { - Vector3 camtopos = global_pos - camera->get_global_transform().origin; - float c = camtopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative + Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin; + float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative float angle = Math::rad2deg(Math::acos(c)); float av = angle * (flat_pos.x < 0 ? -1 : 1) / 180.0; @@ -405,20 +417,20 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (cc >= 3) { // Side pair - float sl = Math::abs(1.0 - Math::abs(-0.4 - av)); - float sr = Math::abs(1.0 - Math::abs(0.4 - av)); + float sleft = Math::abs(1.0 - Math::abs(-0.4 - av)); + float sright = Math::abs(1.0 - Math::abs(0.4 - av)); - output.vol[2].l = sl; - output.vol[2].r = sr; + output.vol[2].l = sleft; + output.vol[2].r = sright; } if (cc >= 4) { // Rear pair - float rl = Math::abs(1.0 - Math::abs(-0.2 - av)); - float rr = Math::abs(1.0 - Math::abs(0.2 - av)); + float rleft = Math::abs(1.0 - Math::abs(-0.2 - av)); + float rright = Math::abs(1.0 - Math::abs(0.2 - av)); - output.vol[3].l = rl; - output.vol[3].r = rr; + output.vol[3].l = rleft; + output.vol[3].r = rright; } } @@ -448,7 +460,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (uniformity > 0.0) { - float distance = cam_area_pos.length(); + float distance = listener_area_pos.length(); float attenuation = Math::db2linear(_get_attenuation_db(distance)); //float dist_att_db = -20 * Math::log(dist + 0.00001); //logarithmic attenuation, like in real life @@ -458,7 +470,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (attenuation < 1.0) { //pan the uniform sound - Vector3 rev_pos = cam_area_pos; + Vector3 rev_pos = listener_area_pos; rev_pos.y = 0; rev_pos.normalize(); @@ -517,9 +529,13 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { - Vector3 camera_velocity = camera->get_doppler_tracked_velocity(); + Vector3 listener_velocity; + + if (listener_is_camera) { + listener_velocity = camera->get_doppler_tracked_velocity(); + } - Vector3 local_velocity = camera->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - camera_velocity); + Vector3 local_velocity = listener_node->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - listener_velocity); if (local_velocity == Vector3()) { output.pitch_scale = 1.0; @@ -810,7 +826,7 @@ float AudioStreamPlayer3D::get_attenuation_filter_db() const { } void AudioStreamPlayer3D::set_attenuation_model(AttenuationModel p_model) { - ERR_FAIL_INDEX(p_model, 3); + ERR_FAIL_INDEX((int)p_model, 4); attenuation_model = p_model; } @@ -839,7 +855,9 @@ void AudioStreamPlayer3D::set_doppler_tracking(DopplerTracking p_tracking) { if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { set_notify_transform(true); velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP); - velocity_tracker->reset(get_global_transform().origin); + if (is_inside_tree()) { + velocity_tracker->reset(get_global_transform().origin); + } } else { set_notify_transform(false); } @@ -864,6 +882,10 @@ bool AudioStreamPlayer3D::get_stream_paused() const { return stream_paused; } +Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() { + return stream_playback; +} + void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream); @@ -930,10 +952,12 @@ void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer3D::set_stream_paused); ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer3D::get_stream_paused); + ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback); + ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer3D::_bus_layout_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,InverseSquare,Log"), "set_attenuation_model", "get_attenuation_model"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,InverseSquare,Log,Disabled"), "set_attenuation_model", "get_attenuation_model"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.1"), "set_unit_size", "get_unit_size"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db"); @@ -958,6 +982,7 @@ void AudioStreamPlayer3D::_bind_methods() { BIND_ENUM_CONSTANT(ATTENUATION_INVERSE_DISTANCE); BIND_ENUM_CONSTANT(ATTENUATION_INVERSE_SQUARE_DISTANCE); BIND_ENUM_CONSTANT(ATTENUATION_LOGARITHMIC); + BIND_ENUM_CONSTANT(ATTENUATION_DISABLED); BIND_ENUM_CONSTANT(OUT_OF_RANGE_MIX); BIND_ENUM_CONSTANT(OUT_OF_RANGE_PAUSE); diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 14413d0702..7a652ed65f 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -40,12 +40,14 @@ class Camera; class AudioStreamPlayer3D : public Spatial { - GDCLASS(AudioStreamPlayer3D, Spatial) + GDCLASS(AudioStreamPlayer3D, Spatial); + public: enum AttenuationModel { ATTENUATION_INVERSE_DISTANCE, ATTENUATION_INVERSE_SQUARE_DISTANCE, ATTENUATION_LOGARITHMIC, + ATTENUATION_DISABLED, }; enum OutOfRangeMode { @@ -205,6 +207,8 @@ public: void set_stream_paused(bool p_pause); bool get_stream_paused() const; + Ref<AudioStreamPlayback> get_stream_playback(); + AudioStreamPlayer3D(); ~AudioStreamPlayer3D(); }; diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 62589bd67e..2b12e78158 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -173,7 +173,7 @@ void BakedLightmapData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_subdiv", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_subdiv", "get_cell_subdiv"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy"); ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data"); } diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h index 60b62f74eb..bb3f84719a 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/baked_lightmap.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp index a875b65c22..0233029435 100644 --- a/scene/3d/bone_attachment.cpp +++ b/scene/3d/bone_attachment.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/bone_attachment.h b/scene/3d/bone_attachment.h index 81a225015e..051e2b4c56 100644 --- a/scene/3d/bone_attachment.h +++ b/scene/3d/bone_attachment.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 8ef64e2e80..c7d6919a2b 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -55,16 +55,23 @@ void Camera::_update_camera_mode() { case PROJECTION_ORTHOGONAL: { set_orthogonal(size, near, far); } break; + case PROJECTION_FRUSTUM: { + set_frustum(size, frustum_offset, near, far); + } break; } } void Camera::_validate_property(PropertyInfo &p_property) const { if (p_property.name == "fov") { - if (mode == PROJECTION_ORTHOGONAL) { + if (mode != PROJECTION_PERSPECTIVE) { p_property.usage = PROPERTY_USAGE_NOEDITOR; } } else if (p_property.name == "size") { - if (mode == PROJECTION_PERSPECTIVE) { + if (mode != PROJECTION_ORTHOGONAL && mode != PROJECTION_FRUSTUM) { + p_property.usage = PROPERTY_USAGE_NOEDITOR; + } + } else if (p_property.name == "frustum_offset") { + if (mode != PROJECTION_FRUSTUM) { p_property.usage = PROPERTY_USAGE_NOEDITOR; } } @@ -99,9 +106,15 @@ void Camera::_notification(int p_what) { case NOTIFICATION_ENTER_WORLD: { - bool first_camera = get_viewport()->_camera_add(this); - if (!get_tree()->is_node_being_edited(this) && (current || first_camera)) - make_current(); + // Needs to track the Viewport because it's needed on NOTIFICATION_EXIT_WORLD + // and Spatial will handle it first, including clearing its reference to the Viewport, + // therefore making it impossible to subclasses to access it + viewport = get_viewport(); + ERR_FAIL_COND(!viewport); + + bool first_camera = viewport->_camera_add(this); + if (current || first_camera) + viewport->_camera_set(this); } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -123,17 +136,20 @@ void Camera::_notification(int p_what) { } } - get_viewport()->_camera_remove(this); + if (viewport) { + viewport->_camera_remove(this); + viewport = NULL; + } } break; case NOTIFICATION_BECAME_CURRENT: { - if (get_world().is_valid()) { - get_world()->_register_camera(this); + if (viewport) { + viewport->find_world()->_register_camera(this); } } break; case NOTIFICATION_LOST_CURRENT: { - if (get_world().is_valid()) { - get_world()->_remove_camera(this); + if (viewport) { + viewport->find_world()->_remove_camera(this); } } break; } @@ -177,8 +193,24 @@ void Camera::set_orthogonal(float p_size, float p_z_near, float p_z_far) { update_gizmo(); } +void Camera::set_frustum(float p_size, Vector2 p_offset, float p_z_near, float p_z_far) { + if (!force_change && size == p_size && frustum_offset == p_offset && p_z_near == near && p_z_far == far && mode == PROJECTION_FRUSTUM) + return; + + size = p_size; + frustum_offset = p_offset; + + near = p_z_near; + far = p_z_far; + mode = PROJECTION_FRUSTUM; + force_change = false; + + VisualServer::get_singleton()->camera_set_frustum(camera, size, frustum_offset, near, far); + update_gizmo(); +} + void Camera::set_projection(Camera::Projection p_mode) { - if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL) { + if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) { mode = p_mode; _update_camera_mode(); _change_notify(); @@ -232,8 +264,6 @@ bool Camera::is_current() const { return get_viewport()->get_camera() == this; } else return current; - - return false; } bool Camera::_can_gizmo_scale() const { @@ -368,13 +398,17 @@ Point2 Camera::unproject_position(const Vector3 &p_pos) const { return res; } -Vector3 Camera::project_position(const Point2 &p_point) const { +Vector3 Camera::project_position(const Point2 &p_point, float p_z_depth) const { if (!is_inside_tree()) { ERR_EXPLAIN("Camera is not inside scene."); ERR_FAIL_COND_V(!is_inside_tree(), Vector3()); } + if (p_z_depth == 0) { + return get_global_transform().origin; + } + Size2 viewport_size = get_viewport()->get_visible_rect().size; CameraMatrix cm; @@ -392,7 +426,7 @@ Vector3 Camera::project_position(const Point2 &p_point) const { point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0; point *= vp_size; - Vector3 p(point.x, point.y, -near); + Vector3 p(point.x, point.y, -p_z_depth); return get_camera_transform().xform(p); } @@ -449,7 +483,9 @@ void Camera::set_doppler_tracking(DopplerTracking p_tracking) { doppler_tracking = p_tracking; if (p_tracking != DOPPLER_TRACKING_DISABLED) { velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP); - velocity_tracker->reset(get_global_transform().origin); + if (is_inside_tree()) { + velocity_tracker->reset(get_global_transform().origin); + } } _update_camera_mode(); } @@ -465,19 +501,22 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("project_ray_origin", "screen_point"), &Camera::project_ray_origin); ClassDB::bind_method(D_METHOD("unproject_position", "world_point"), &Camera::unproject_position); ClassDB::bind_method(D_METHOD("is_position_behind", "world_point"), &Camera::is_position_behind); - ClassDB::bind_method(D_METHOD("project_position", "screen_point"), &Camera::project_position); + ClassDB::bind_method(D_METHOD("project_position", "screen_point", "z_depth"), &Camera::project_position, DEFVAL(0)); ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective); ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal); + ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera::set_frustum); ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current); ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera::clear_current, DEFVAL(true)); ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current); ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current); ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform); ClassDB::bind_method(D_METHOD("get_fov"), &Camera::get_fov); + ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera::get_frustum_offset); ClassDB::bind_method(D_METHOD("get_size"), &Camera::get_size); ClassDB::bind_method(D_METHOD("get_zfar"), &Camera::get_zfar); ClassDB::bind_method(D_METHOD("get_znear"), &Camera::get_znear); ClassDB::bind_method(D_METHOD("set_fov"), &Camera::set_fov); + ClassDB::bind_method(D_METHOD("set_frustum_offset"), &Camera::set_frustum_offset); ClassDB::bind_method(D_METHOD("set_size"), &Camera::set_size); ClassDB::bind_method(D_METHOD("set_zfar"), &Camera::set_zfar); ClassDB::bind_method(D_METHOD("set_znear"), &Camera::set_znear); @@ -495,6 +534,8 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode); ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking); ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking); + ClassDB::bind_method(D_METHOD("get_frustum"), &Camera::get_frustum); + ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera::get_camera); ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit); ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit); @@ -507,15 +548,17 @@ void Camera::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal"), "set_projection", "get_projection"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar"); BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL); + BIND_ENUM_CONSTANT(PROJECTION_FRUSTUM); BIND_ENUM_CONSTANT(KEEP_WIDTH); BIND_ENUM_CONSTANT(KEEP_HEIGHT); @@ -540,6 +583,10 @@ float Camera::get_znear() const { return near; } +Vector2 Camera::get_frustum_offset() const { + return frustum_offset; +} + float Camera::get_zfar() const { return far; @@ -567,6 +614,11 @@ void Camera::set_znear(float p_znear) { _update_camera_mode(); } +void Camera::set_frustum_offset(Vector2 p_offset) { + frustum_offset = p_offset; + _update_camera_mode(); +} + void Camera::set_zfar(float p_zfar) { far = p_zfar; _update_camera_mode(); @@ -645,9 +697,11 @@ Camera::Camera() { camera = VisualServer::get_singleton()->camera_create(); size = 1; fov = 0; + frustum_offset = Vector2(); near = 0; far = 0; current = false; + viewport = NULL; force_change = false; mode = PROJECTION_PERSPECTIVE; set_perspective(70.0, 0.05, 100.0); @@ -681,8 +735,9 @@ void ClippedCamera::set_process_mode(ProcessMode p_mode) { if (process_mode == p_mode) { return; } - set_process_internal(p_mode == CLIP_PROCESS_IDLE); - set_physics_process_internal(p_mode == CLIP_PROCESS_PHYSICS); + process_mode = p_mode; + set_process_internal(process_mode == CLIP_PROCESS_IDLE); + set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS); } ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const { return process_mode; @@ -745,7 +800,7 @@ void ClippedCamera::_notification(int p_what) { float csafe, cunsafe; if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, csafe, cunsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) { - clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from).normalized() * csafe); + clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * csafe); } _update_camera(); @@ -814,6 +869,11 @@ void ClippedCamera::clear_exceptions() { exclude.clear(); } +float ClippedCamera::get_clip_offset() const { + + return clip_offset; +} + void ClippedCamera::set_clip_to_areas(bool p_clip) { clip_to_areas = p_clip; @@ -857,6 +917,8 @@ void ClippedCamera::_bind_methods() { ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera::set_clip_to_areas); ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera::is_clip_to_areas_enabled); + ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera::get_clip_offset); + ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera::set_clip_to_bodies); ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera::is_clip_to_bodies_enabled); diff --git a/scene/3d/camera.h b/scene/3d/camera.h index a35c9d6e7f..c0a4f77435 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -46,7 +46,8 @@ public: enum Projection { PROJECTION_PERSPECTIVE, - PROJECTION_ORTHOGONAL + PROJECTION_ORTHOGONAL, + PROJECTION_FRUSTUM }; enum KeepAspect { @@ -63,11 +64,13 @@ public: private: bool force_change; bool current; + Viewport *viewport; Projection mode; float fov; float size; + Vector2 frustum_offset; float near, far; float v_offset; float h_offset; @@ -110,6 +113,7 @@ public: void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far); void set_orthogonal(float p_size, float p_z_near, float p_z_far); + void set_frustum(float p_size, Vector2 p_offset, float p_near, float p_far); void set_projection(Camera::Projection p_mode); void make_current(); @@ -123,12 +127,15 @@ public: float get_size() const; float get_zfar() const; float get_znear() const; + Vector2 get_frustum_offset() const; + Projection get_projection() const; void set_fov(float p_fov); void set_size(float p_size); void set_zfar(float p_zfar); void set_znear(float p_znear); + void set_frustum_offset(Vector2 p_offset); virtual Transform get_camera_transform() const; @@ -137,7 +144,7 @@ public: virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; bool is_position_behind(const Vector3 &p_pos) const; - virtual Vector3 project_position(const Point2 &p_point) const; + virtual Vector3 project_position(const Point2 &p_point, float p_z_depth = 0) const; Vector<Vector3> get_near_plane_points() const; @@ -227,6 +234,8 @@ public: void remove_exception(const Object *p_object); void clear_exceptions(); + float get_clip_offset() const; + ClippedCamera(); ~ClippedCamera(); }; diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 99b8ce0567..fc46cf5bdb 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -52,7 +52,7 @@ void CollisionObject::_notification(int p_what) { _update_pickable(); //get space - }; + } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -259,9 +259,9 @@ void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> & s.index = total_subshapes; s.shape = p_shape; if (area) { - PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform); + PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled); } else { - PhysicsServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform); + PhysicsServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled); } sd.shapes.push_back(s); diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h index f8ef04b78f..90f370b6d4 100644 --- a/scene/3d/collision_object.h +++ b/scene/3d/collision_object.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp index 379dd21c39..db07059b32 100644 --- a/scene/3d/collision_polygon.cpp +++ b/scene/3d/collision_polygon.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h index f1f137c9c5..04c00fc70f 100644 --- a/scene/3d/collision_polygon.h +++ b/scene/3d/collision_polygon.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp index 4fd68fb47d..219ea56681 100644 --- a/scene/3d/collision_shape.cpp +++ b/scene/3d/collision_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -65,7 +65,6 @@ void CollisionShape::make_convex_from_brothers() { } void CollisionShape::_update_in_shape_owner(bool p_xform_only) { - parent->shape_owner_set_transform(owner_id, get_transform()); if (p_xform_only) return; @@ -91,7 +90,7 @@ void CollisionShape::_notification(int p_what) { _update_in_shape_owner(); } if (get_tree()->is_debugging_collisions_hint()) { - _create_debug_shape(); + _update_debug_shape(); } } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { @@ -124,6 +123,10 @@ String CollisionShape::get_configuration_warning() const { return TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it!"); } + if (shape->is_class("PlaneShape")) { + return TTR("Plane shapes don't work well and will be removed in future versions. Please don't use them."); + } + return String(); } @@ -138,17 +141,24 @@ void CollisionShape::_bind_methods() { ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape::make_convex_from_brothers); ClassDB::set_method_flags("CollisionShape", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape::_shape_changed); + ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape::_update_debug_shape); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); } void CollisionShape::set_shape(const Ref<Shape> &p_shape) { - if (!shape.is_null()) + if (!shape.is_null()) { shape->unregister_owner(this); + shape->disconnect("changed", this, "_shape_changed"); + } shape = p_shape; - if (!shape.is_null()) + if (!shape.is_null()) { shape->register_owner(this); + shape->connect("changed", this, "_shape_changed"); + } update_gizmo(); if (parent) { parent->shape_owner_clear_shapes(owner_id); @@ -157,6 +167,8 @@ void CollisionShape::set_shape(const Ref<Shape> &p_shape) { } } + if (is_inside_tree()) + _shape_changed(); update_configuration_warning(); } @@ -195,7 +207,8 @@ CollisionShape::~CollisionShape() { //VisualServer::get_singleton()->free(indicator); } -void CollisionShape::_create_debug_shape() { +void CollisionShape::_update_debug_shape() { + debug_shape_dirty = false; if (debug_shape) { debug_shape->queue_delete(); @@ -203,15 +216,24 @@ void CollisionShape::_create_debug_shape() { } Ref<Shape> s = get_shape(); - if (s.is_null()) return; Ref<Mesh> mesh = s->get_debug_mesh(); - MeshInstance *mi = memnew(MeshInstance); mi->set_mesh(mesh); - add_child(mi); debug_shape = mi; } + +void CollisionShape::_shape_changed() { + // If this is a heightfield shape our center may have changed + if (parent) { + _update_in_shape_owner(true); + } + + if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !debug_shape_dirty) { + debug_shape_dirty = true; + call_deferred("_update_debug_shape"); + } +} diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h index 6ca8e80ea1..98427b8590 100644 --- a/scene/3d/collision_shape.h +++ b/scene/3d/collision_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -45,12 +45,14 @@ class CollisionShape : public Spatial { CollisionObject *parent; Node *debug_shape; + bool debug_shape_dirty; void resource_changed(RES res); bool disabled; protected: - void _create_debug_shape(); + void _update_debug_shape(); + void _shape_changed(); void _update_in_shape_owner(bool p_xform_only = false); diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index b07848e02e..cff147ba74 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -47,20 +47,8 @@ PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const { void CPUParticles::set_emitting(bool p_emitting) { emitting = p_emitting; - if (!is_processing_internal()) { + if (emitting) set_process_internal(true); - if (is_inside_tree()) { -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true); - -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } - } } void CPUParticles::set_amount(int p_amount) { @@ -224,7 +212,7 @@ String CPUParticles::get_configuration_warning() const { get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) { if (warnings != String()) warnings += "\n"; - warnings += "- " + TTR("CPUParticles animation requires the usage of a SpatialMaterial with \"Billboard Particles\" enabled."); + warnings += "- " + TTR("CPUParticles animation requires the usage of a SpatialMaterial whose Billboard Mode is set to \"Particle Billboard\"."); } return warnings; @@ -314,9 +302,9 @@ void CPUParticles::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) case PARAM_ANGULAR_VELOCITY: { _adjust_curve_range(p_curve, -360, 360); } break; - /*case PARAM_ORBIT_VELOCITY: { + case PARAM_ORBIT_VELOCITY: { _adjust_curve_range(p_curve, -500, 500); - } break;*/ + } break; case PARAM_LINEAR_ACCEL: { _adjust_curve_range(p_curve, -200, 200); } break; @@ -343,7 +331,8 @@ void CPUParticles::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) } break; case PARAM_ANIM_OFFSET: { } break; - default: {} + default: { + } } } Ref<Curve> CPUParticles::get_param_curve(Parameter p_param) const { @@ -472,11 +461,10 @@ void CPUParticles::_validate_property(PropertyInfo &property) const { if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { property.usage = 0; } - /* + if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { property.usage = 0; } - */ } static uint32_t idhash(uint32_t x) { @@ -526,6 +514,8 @@ void CPUParticles::_particles_process(float p_delta) { velocity_xform = emission_xform.basis; } + float system_phase = time / lifetime; + for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; @@ -533,21 +523,26 @@ void CPUParticles::_particles_process(float p_delta) { if (!emitting && !p.active) continue; - float restart_time = (float(i) / float(pcount)) * lifetime; float local_delta = p_delta; + // The phase is a ratio between 0 (birth) and 1 (end of life) for each particle. + // While we use time in tests later on, for randomness we use the phase as done in the + // original shader code, and we later multiply by lifetime to get the time. + float restart_phase = float(i) / float(pcount); + if (randomness_ratio > 0.0) { uint32_t seed = cycle; - if (restart_time >= time) { + if (restart_phase >= system_phase) { seed -= uint32_t(1); } seed *= uint32_t(pcount); seed += uint32_t(i); float random = float(idhash(seed) % uint32_t(65536)) / 65536.0; - restart_time += randomness_ratio * random * 1.0 / float(pcount); + restart_phase += randomness_ratio * random * 1.0 / float(pcount); } - restart_time *= (1.0 - explosiveness_ratio); + restart_phase *= (1.0 - explosiveness_ratio); + float restart_time = restart_phase * lifetime; bool restart = false; if (time > prev_time) { @@ -556,7 +551,7 @@ void CPUParticles::_particles_process(float p_delta) { if (restart_time >= prev_time && restart_time < time) { restart = true; if (fractional_delta) { - local_delta = (time - restart_time) * lifetime; + local_delta = time - restart_time; } } @@ -564,13 +559,13 @@ void CPUParticles::_particles_process(float p_delta) { if (restart_time >= prev_time) { restart = true; if (fractional_delta) { - local_delta = (1.0 - restart_time + time) * lifetime; + local_delta = lifetime - restart_time + time; } } else if (restart_time < time) { restart = true; if (fractional_delta) { - local_delta = (time - restart_time) * lifetime; + local_delta = time - restart_time; } } } @@ -605,19 +600,14 @@ void CPUParticles::_particles_process(float p_delta) { p.hue_rot_rand = Math::randf(); p.anim_offset_rand = Math::randf(); - float angle1_rad; - float angle2_rad; - if (flags[FLAG_DISABLE_Z]) { - - angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; + float angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0); p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); - } else { //initiate velocity spread in 3D - angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; - angle2_rad = (Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * Math_PI * spread / 180.0; + float angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; + float angle2_rad = (Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * Math_PI * spread / 180.0; Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad)); Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad)); @@ -707,16 +697,14 @@ void CPUParticles::_particles_process(float p_delta) { if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]); } - /* - float tex_orbit_velocity = 0.0; + float tex_orbit_velocity = 0.0; if (flags[FLAG_DISABLE_Z]) { - - if (curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY].is_valid()) { - tex_orbit_velocity = curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY]->interpolate(p.custom[1]); + if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { + tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]); } } -*/ + float tex_angular_velocity = 0.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]); @@ -770,8 +758,9 @@ void CPUParticles::_particles_process(float p_delta) { //apply tangential acceleration; if (flags[FLAG_DISABLE_Z]) { - Vector3 yx = Vector3(diff.y, 0, diff.x); - force += yx.length() > 0.0 ? (yx * Vector3(-1.0, 0, 1.0)) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); + Vector2 yx = Vector2(diff.y, diff.x); + Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized(); + force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); } else { Vector3 crossDiff = diff.normalized().cross(gravity.normalized()); @@ -780,18 +769,18 @@ void CPUParticles::_particles_process(float p_delta) { //apply attractor forces p.velocity += force * local_delta; //orbit velocity -#if 0 if (flags[FLAG_DISABLE_Z]) { - - float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random); + float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); if (orbit_amount != 0.0) { - float ang = orbit_amount * DELTA * pi * 2.0; - mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang))); - TRANSFORM[3].xy -= diff.xy; - TRANSFORM[3].xy += rot * diff.xy; + float ang = orbit_amount * local_delta * Math_PI * 2.0; + // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, + // but we use -ang here to reproduce its behavior. + Transform2D rot = Transform2D(-ang, Vector2()); + Vector2 rotv = rot.basis_xform(Vector2(diff.x, diff.y)); + p.transform.origin -= Vector3(diff.x, diff.y, 0); + p.transform.origin += Vector3(rotv.x, rotv.y, 0); } } -#endif if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { p.velocity = p.velocity.normalized() * tex_linear_velocity; } @@ -926,11 +915,6 @@ void CPUParticles::_update_particle_data_buffer() { PoolVector<Particle>::Read r = particles.read(); float *ptr = w.ptr(); - Transform un_transform; - if (!local_coords) { - un_transform = get_global_transform().affine_inverse(); - } - if (draw_order != DRAW_ORDER_INDEX) { ow = particle_order.write(); order = ow.ptr(); @@ -948,7 +932,12 @@ void CPUParticles::_update_particle_data_buffer() { Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close if (local_coords) { - dir = un_transform.basis.xform(dir).normalized(); + + // will look different from Particles in editor as this is based on the camera in the scenetree + // and not the editor camera + dir = inv_emission_transform.xform(dir).normalized(); + } else { + dir = dir.normalized(); } SortArray<int, SortAxis> sorter; @@ -966,7 +955,7 @@ void CPUParticles::_update_particle_data_buffer() { Transform t = r[idx].transform; if (!local_coords) { - t = un_transform * t; + t = inv_emission_transform * t; } if (r[idx].active) { @@ -1009,6 +998,27 @@ void CPUParticles::_update_particle_data_buffer() { #endif } +void CPUParticles::_set_redraw(bool p_redraw) { + if (redraw == p_redraw) + return; + redraw = p_redraw; +#ifndef NO_THREADS + update_mutex->lock(); +#endif + if (redraw) { + VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true); + VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1); + } else { + VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false); + VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0); + } +#ifndef NO_THREADS + update_mutex->unlock(); +#endif +} + void CPUParticles::_update_render_thread() { #ifndef NO_THREADS @@ -1027,31 +1037,11 @@ void CPUParticles::_update_render_thread() { void CPUParticles::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - if (is_processing_internal()) { - -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } + set_process_internal(emitting); } if (p_what == NOTIFICATION_EXIT_TREE) { - if (is_processing_internal()) { - -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } + _set_redraw(false); } if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { @@ -1059,26 +1049,20 @@ void CPUParticles::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (particles.size() == 0 || !is_visible_in_tree()) + if (particles.size() == 0 || !is_visible_in_tree()) { + _set_redraw(false); return; + } float delta = get_process_delta_time(); if (emitting) { - inactive_time = 0; } else { inactive_time += delta; if (inactive_time > lifetime * 1.2) { set_process_internal(false); -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false); + _set_redraw(false); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif //reset variables time = 0; inactive_time = 0; @@ -1087,6 +1071,7 @@ void CPUParticles::_notification(int p_what) { return; } } + _set_redraw(true); bool processed = false; @@ -1136,6 +1121,46 @@ void CPUParticles::_notification(int p_what) { _update_particle_data_buffer(); } } + + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + + inv_emission_transform = get_global_transform().affine_inverse(); + + if (!local_coords) { + + int pc = particles.size(); + + PoolVector<float>::Write w = particle_data.write(); + PoolVector<Particle>::Read r = particles.read(); + float *ptr = w.ptr(); + + for (int i = 0; i < pc; i++) { + + Transform t = inv_emission_transform * r[i].transform; + + if (r[i].active) { + ptr[0] = t.basis.elements[0][0]; + ptr[1] = t.basis.elements[0][1]; + ptr[2] = t.basis.elements[0][2]; + ptr[3] = t.origin.x; + ptr[4] = t.basis.elements[1][0]; + ptr[5] = t.basis.elements[1][1]; + ptr[6] = t.basis.elements[1][2]; + ptr[7] = t.origin.y; + ptr[8] = t.basis.elements[2][0]; + ptr[9] = t.basis.elements[2][1]; + ptr[10] = t.basis.elements[2][2]; + ptr[11] = t.origin.z; + } else { + zeromem(ptr, sizeof(float) * 12); + } + + ptr += 17; + } + + can_update = true; + } + } } void CPUParticles::convert_from_particles(Node *p_particles) { @@ -1191,7 +1216,7 @@ void CPUParticles::convert_from_particles(Node *p_particles) { CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); - // CONVERT_PARAM(PARAM_ORBIT_VELOCITY); + CONVERT_PARAM(PARAM_ORBIT_VELOCITY); CONVERT_PARAM(PARAM_LINEAR_ACCEL); CONVERT_PARAM(PARAM_RADIAL_ACCEL); CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL); @@ -1243,7 +1268,7 @@ void CPUParticles::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); @@ -1334,12 +1359,10 @@ void CPUParticles::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY); - /* ADD_GROUP("Orbit Velocity", "orbit_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY); -*/ ADD_GROUP("Linear Accel", "linear_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); @@ -1382,7 +1405,7 @@ void CPUParticles::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); - //BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL); BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL); BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL); @@ -1396,6 +1419,7 @@ void CPUParticles::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); + BIND_ENUM_CONSTANT(FLAG_DISABLE_Z); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); @@ -1411,8 +1435,12 @@ CPUParticles::CPUParticles() { inactive_time = 0; frame_remainder = 0; cycle = 0; + redraw = false; + + set_notify_transform(true); multimesh = VisualServer::get_singleton()->multimesh_create(); + VisualServer::get_singleton()->multimesh_set_visible_instances(multimesh, 0); set_base(multimesh); set_emitting(true); @@ -1432,7 +1460,7 @@ CPUParticles::CPUParticles() { set_spread(45); set_flatness(0); set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); - //set_param(PARAM_ORBIT_VELOCITY, 0); + set_param(PARAM_ORBIT_VELOCITY, 0); set_param(PARAM_LINEAR_ACCEL, 0); set_param(PARAM_RADIAL_ACCEL, 0); set_param(PARAM_TANGENTIAL_ACCEL, 0); diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h index 2e83924dfc..6f267102fa 100644 --- a/scene/3d/cpu_particles.h +++ b/scene/3d/cpu_particles.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -53,7 +53,7 @@ public: PARAM_INITIAL_LINEAR_VELOCITY, PARAM_ANGULAR_VELOCITY, - //PARAM_ORBIT_VELOCITY, + PARAM_ORBIT_VELOCITY, PARAM_LINEAR_ACCEL, PARAM_RADIAL_ACCEL, PARAM_TANGENTIAL_ACCEL, @@ -104,6 +104,7 @@ private: float inactive_time; float frame_remainder; int cycle; + bool redraw; RID multimesh; @@ -115,7 +116,7 @@ private: const Particle *particles; bool operator()(int p_a, int p_b) const { - return particles[p_a].time < particles[p_b].time; + return particles[p_a].time > particles[p_b].time; } }; @@ -141,6 +142,8 @@ private: int fixed_fps; bool fractional_delta; + Transform inv_emission_transform; + volatile bool can_update; DrawOrder draw_order; @@ -178,6 +181,8 @@ private: void _update_render_thread(); + void _set_redraw(bool p_redraw); + protected: static void _bind_methods(); void _notification(int p_what); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 6276d02eff..414e932f61 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -30,6 +30,8 @@ #include "gi_probe.h" +#include "core/os/os.h" + #include "mesh_instance.h" #include "voxel_light_baker.h" @@ -490,6 +492,14 @@ PoolVector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const { return PoolVector<Face3>(); } +String GIProbe::get_configuration_warning() const { + + if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + return TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."); + } + return String(); +} + void GIProbe::_bind_methods() { ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &GIProbe::set_probe_data); @@ -529,7 +539,7 @@ void GIProbe::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_range", PROPERTY_HINT_RANGE, "1,16,1"), "set_dynamic_range", "get_dynamic_range"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0,4,0.001"), "set_bias", "get_bias"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "normal_bias", PROPERTY_HINT_RANGE, "0,4,0.001"), "set_normal_bias", "get_normal_bias"); diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index af4b646590..4badabbadf 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -168,6 +168,8 @@ public: virtual AABB get_aabb() const; virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual String get_configuration_warning() const; + GIProbe(); ~GIProbe(); }; diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp index 14a0b0505d..a555106bd8 100644 --- a/scene/3d/immediate_geometry.cpp +++ b/scene/3d/immediate_geometry.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/immediate_geometry.h b/scene/3d/immediate_geometry.h index f7201b4bba..3467663dff 100644 --- a/scene/3d/immediate_geometry.h +++ b/scene/3d/immediate_geometry.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp index 93832f8e00..d720dd117c 100644 --- a/scene/3d/interpolated_camera.cpp +++ b/scene/3d/interpolated_camera.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/interpolated_camera.h b/scene/3d/interpolated_camera.h index b025112295..97100c9501 100644 --- a/scene/3d/interpolated_camera.h +++ b/scene/3d/interpolated_camera.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 11d61315ba..2e64872616 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -152,6 +152,7 @@ PoolVector<Face3> Light::get_faces(uint32_t p_usage_flags) const { void Light::set_bake_mode(BakeMode p_mode) { bake_mode = p_mode; + VS::get_singleton()->light_set_use_gi(light, p_mode != BAKE_DISABLED); } Light::BakeMode Light::get_bake_mode() const { @@ -210,6 +211,13 @@ bool Light::is_editor_only() const { return editor_only; } +void Light::_validate_property(PropertyInfo &property) const { + + if (VisualServer::get_singleton()->is_low_end() && property.name == "shadow_contact") { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } +} + void Light::_bind_methods() { ClassDB::bind_method(D_METHOD("set_editor_only", "editor_only"), &Light::set_editor_only); @@ -241,8 +249,8 @@ void Light::_bind_methods() { ADD_GROUP("Light", "light_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_ENERGY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode"); @@ -286,7 +294,8 @@ Light::Light(VisualServer::LightType p_type) { case VS::LIGHT_DIRECTIONAL: light = VisualServer::get_singleton()->directional_light_create(); break; case VS::LIGHT_OMNI: light = VisualServer::get_singleton()->omni_light_create(); break; case VS::LIGHT_SPOT: light = VisualServer::get_singleton()->spot_light_create(); break; - default: {}; + default: { + }; } VS::get_singleton()->instance_set_base(get_instance(), light); diff --git a/scene/3d/light.h b/scene/3d/light.h index b35b397ced..ddd5bc6b3a 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -92,6 +92,7 @@ protected: static void _bind_methods(); void _notification(int p_what); + virtual void _validate_property(PropertyInfo &property) const; Light(VisualServer::LightType p_type); diff --git a/scene/3d/listener.cpp b/scene/3d/listener.cpp index 439c1f8c45..85e65e23f2 100644 --- a/scene/3d/listener.cpp +++ b/scene/3d/listener.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/listener.h b/scene/3d/listener.h index 9901f7635c..86451e7d99 100644 --- a/scene/3d/listener.h +++ b/scene/3d/listener.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index cf0317cd58..89072519d5 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -96,7 +96,7 @@ void MeshInstance::_get_property_list(List<PropertyInfo> *p_list) const { ls.sort(); for (List<String>::Element *E = ls.front(); E; E = E->next()) { - p_list->push_back(PropertyInfo(Variant::REAL, E->get(), PROPERTY_HINT_RANGE, "0,1,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, E->get(), PROPERTY_HINT_RANGE, "0,1,0.00001")); } if (mesh.is_valid()) { @@ -138,6 +138,8 @@ void MeshInstance::set_mesh(const Ref<Mesh> &p_mesh) { set_base(RID()); } + update_gizmo(); + _change_notify(); } Ref<Mesh> MeshInstance::get_mesh() const { diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h index 0b5b4b9e7b..022ef15aad 100644 --- a/scene/3d/mesh_instance.h +++ b/scene/3d/mesh_instance.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/multimesh_instance.cpp b/scene/3d/multimesh_instance.cpp index 4cbd1df64a..d744a74859 100644 --- a/scene/3d/multimesh_instance.cpp +++ b/scene/3d/multimesh_instance.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/multimesh_instance.h b/scene/3d/multimesh_instance.h index 1cd077a0a5..8f41aa8fd2 100644 --- a/scene/3d/multimesh_instance.h +++ b/scene/3d/multimesh_instance.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 6e7b372647..612d91c6e1 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -340,16 +340,12 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector }; Vector3 entry = Geometry::get_closest_point_to_segment(begin_poly->entry, edge); - begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry); + begin_poly->edges[i].C->distance = begin_point.distance_to(entry); begin_poly->edges[i].C->entry = entry; #else begin_poly->edges[i].C->distance = begin_poly->center.distance_to(begin_poly->edges[i].C->center); #endif open_list.push_back(begin_poly->edges[i].C); - - if (begin_poly->edges[i].C == end_poly) { - found_route = true; - } } } @@ -370,28 +366,7 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector float cost = p->distance; #ifdef USE_ENTRY_POINT - int es = p->edges.size(); - - float shortest_distance = 1e30; - - for (int i = 0; i < es; i++) { - Polygon::Edge &e = p->edges.write[i]; - - if (!e.C) - continue; - - Vector3 edge[2] = { - _get_vertex(p->edges[i].point), - _get_vertex(p->edges[(i + 1) % es].point) - }; - - Vector3 edge_point = Geometry::get_closest_point_to_segment(p->entry, edge); - float dist = p->entry.distance_to(edge_point); - if (dist < shortest_distance) - shortest_distance = dist; - } - - cost += shortest_distance; + cost += p->entry.distance_to(end_point); #else cost += p->center.distance_to(end_point); #endif @@ -404,6 +379,12 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector Polygon *p = least_cost_poly->get(); //open the neighbours for search + if (p == end_poly) { + //oh my reached end! stop algorithm + found_route = true; + break; + } + for (int i = 0; i < p->edges.size(); i++) { Polygon::Edge &e = p->edges.write[i]; @@ -411,7 +392,17 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector if (!e.C) continue; +#ifdef USE_ENTRY_POINT + Vector3 edge[2] = { + _get_vertex(p->edges[i].point), + _get_vertex(p->edges[(i + 1) % p->edges.size()].point) + }; + + Vector3 entry = Geometry::get_closest_point_to_segment(p->entry, edge); + float distance = p->entry.distance_to(entry) + p->distance; +#else float distance = p->center.distance_to(e.C->center) + p->distance; +#endif if (e.C->prev_edge != -1) { //oh this was visited already, can we win the cost? @@ -420,25 +411,22 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector e.C->prev_edge = e.C_edge; e.C->distance = distance; +#ifdef USE_ENTRY_POINT + e.C->entry = entry; +#endif } } else { //add to open neighbours e.C->prev_edge = e.C_edge; e.C->distance = distance; +#ifdef USE_ENTRY_POINT + e.C->entry = entry; +#endif open_list.push_back(e.C); - - if (e.C == end_poly) { - //oh my reached end! stop algorithm - found_route = true; - break; - } } } - if (found_route) - break; - open_list.erase(least_cost_poly); } @@ -539,8 +527,12 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector path.push_back(end_point); while (true) { int prev = p->prev_edge; +#ifdef USE_ENTRY_POINT + Vector3 point = p->entry; +#else int prev_n = (p->prev_edge + 1) % p->edges.size(); Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point)) * 0.5; +#endif path.push_back(point); p = p->edges[prev].C; if (p == begin_poly) diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h index 8f200997cd..f920d1d7f6 100644 --- a/scene/3d/navigation.h +++ b/scene/3d/navigation.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 99680b7273..f82543b789 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -73,6 +73,41 @@ int NavigationMesh::get_sample_partition_type() const { return static_cast<int>(partition_type); } +void NavigationMesh::set_parsed_geometry_type(int p_value) { + ERR_FAIL_COND(p_value >= PARSED_GEOMETRY_MAX); + parsed_geometry_type = static_cast<ParsedGeometryType>(p_value); + _change_notify(); +} + +int NavigationMesh::get_parsed_geometry_type() const { + return parsed_geometry_type; +} + +void NavigationMesh::set_collision_mask(uint32_t p_mask) { + + collision_mask = p_mask; +} + +uint32_t NavigationMesh::get_collision_mask() const { + + return collision_mask; +} + +void NavigationMesh::set_collision_mask_bit(int p_bit, bool p_value) { + + uint32_t mask = get_collision_mask(); + if (p_value) + mask |= 1 << p_bit; + else + mask &= ~(1 << p_bit); + set_collision_mask(mask); +} + +bool NavigationMesh::get_collision_mask_bit(int p_bit) const { + + return get_collision_mask() & (1 << p_bit); +} + void NavigationMesh::set_cell_size(float p_value) { cell_size = p_value; } @@ -204,6 +239,7 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const { void NavigationMesh::set_vertices(const PoolVector<Vector3> &p_vertices) { vertices = p_vertices; + _change_notify(); } PoolVector<Vector3> NavigationMesh::get_vertices() const { @@ -217,6 +253,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) { for (int i = 0; i < p_array.size(); i++) { polygons.write[i].indices = p_array[i]; } + _change_notify(); } Array NavigationMesh::_get_polygons() const { @@ -235,6 +272,7 @@ void NavigationMesh::add_polygon(const Vector<int> &p_polygon) { Polygon polygon; polygon.indices = p_polygon; polygons.push_back(polygon); + _change_notify(); } int NavigationMesh::get_polygon_count() const { @@ -292,11 +330,11 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() { if (ek.from < ek.to) SWAP(ek.from, ek.to); - Map<_EdgeKey, bool>::Element *E = edge_map.find(ek); + Map<_EdgeKey, bool>::Element *F = edge_map.find(ek); - if (E) { + if (F) { - E->get() = false; + F->get() = false; } else { @@ -340,6 +378,15 @@ void NavigationMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type); ClassDB::bind_method(D_METHOD("get_sample_partition_type"), &NavigationMesh::get_sample_partition_type); + ClassDB::bind_method(D_METHOD("set_parsed_geometry_type", "geometry_type"), &NavigationMesh::set_parsed_geometry_type); + ClassDB::bind_method(D_METHOD("get_parsed_geometry_type"), &NavigationMesh::get_parsed_geometry_type); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &NavigationMesh::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &NavigationMesh::get_collision_mask); + + ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &NavigationMesh::set_collision_mask_bit); + ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &NavigationMesh::get_collision_mask_bit); + ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationMesh::set_cell_size); ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_cell_size); @@ -405,30 +452,45 @@ void NavigationMesh::_bind_methods() { BIND_CONSTANT(SAMPLE_PARTITION_MONOTONE); BIND_CONSTANT(SAMPLE_PARTITION_LAYERS); + BIND_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES); + BIND_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS); + BIND_CONSTANT(PARSED_GEOMETRY_BOTH); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type"); - - ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01"), "set_cell_size", "get_cell_size"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01"), "set_cell_height", "get_cell_height"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/height", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_height", "get_agent_height"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/radius", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_radius", "get_agent_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_climb", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_max_climb", "get_agent_max_climb"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/height", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_height", "get_agent_height"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/radius", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_radius", "get_agent_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_climb", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_max_climb", "get_agent_max_climb"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_slope", PROPERTY_HINT_RANGE, "0.0,90.0,0.1"), "set_agent_max_slope", "get_agent_max_slope"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01"), "set_region_min_size", "get_region_min_size"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01"), "set_region_merge_size", "get_region_merge_size"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01"), "set_edge_max_length", "get_edge_max_length"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01"), "set_edge_max_error", "get_edge_max_error"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0"), "set_verts_per_poly", "get_verts_per_poly"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.0,16.0,0.01"), "set_detail_sample_distance", "get_detail_sample_distance"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01"), "set_detail_sample_max_error", "get_detail_sample_max_error"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater"), "set_edge_max_length", "get_edge_max_length"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater"), "set_edge_max_error", "get_edge_max_error"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_max_error", "get_detail_sample_max_error"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans"); } +void NavigationMesh::_validate_property(PropertyInfo &property) const { + if (property.name == "geometry/collision_mask") { + if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) { + property.usage = 0; + return; + } + } +} + NavigationMesh::NavigationMesh() { cell_size = 0.3f; cell_height = 0.2f; @@ -445,7 +507,8 @@ NavigationMesh::NavigationMesh() { detail_sample_max_error = 1.0f; partition_type = SAMPLE_PARTITION_WATERSHED; - + parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES; + collision_mask = 0xFFFFFFFF; filter_low_hanging_obstacles = false; filter_ledge_spans = false; filter_walkable_low_height_spans = false; @@ -566,8 +629,17 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_na navigation->navmesh_remove(nav_id); nav_id = -1; } + + if (navmesh.is_valid()) { + navmesh->remove_change_receptor(this); + } + navmesh = p_navmesh; + if (navmesh.is_valid()) { + navmesh->add_change_receptor(this); + } + if (navigation && navmesh.is_valid() && enabled) { nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); } @@ -617,6 +689,11 @@ void NavigationMeshInstance::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); } +void NavigationMeshInstance::_changed_callback(Object *p_changed, const char *p_prop) { + update_gizmo(); + update_configuration_warning(); +} + NavigationMeshInstance::NavigationMeshInstance() { debug_view = NULL; @@ -625,3 +702,8 @@ NavigationMeshInstance::NavigationMeshInstance() { enabled = true; set_notify_transform(true); } + +NavigationMeshInstance::~NavigationMeshInstance() { + if (navmesh.is_valid()) + navmesh->remove_change_receptor(this); +} diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h index 753ad76edc..5fbf3998ff 100644 --- a/scene/3d/navigation_mesh.h +++ b/scene/3d/navigation_mesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -57,6 +57,7 @@ class NavigationMesh : public Resource { protected: static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const; void _set_polygons(const Array &p_array); Array _get_polygons() const; @@ -69,6 +70,13 @@ public: SAMPLE_PARTITION_MAX }; + enum ParsedGeometryType { + PARSED_GEOMETRY_MESH_INSTANCES = 0, + PARSED_GEOMETRY_STATIC_COLLIDERS, + PARSED_GEOMETRY_BOTH, + PARSED_GEOMETRY_MAX + }; + protected: float cell_size; float cell_height; @@ -85,6 +93,8 @@ protected: float detail_sample_max_error; SamplePartitionType partition_type; + ParsedGeometryType parsed_geometry_type; + uint32_t collision_mask; bool filter_low_hanging_obstacles; bool filter_ledge_spans; @@ -95,6 +105,15 @@ public: void set_sample_partition_type(int p_value); int get_sample_partition_type() const; + void set_parsed_geometry_type(int p_value); + int get_parsed_geometry_type() const; + + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; + + void set_collision_mask_bit(int p_bit, bool p_value); + bool get_collision_mask_bit(int p_bit) const; + void set_cell_size(float p_value); float get_cell_size() const; @@ -174,6 +193,7 @@ class NavigationMeshInstance : public Spatial { protected: void _notification(int p_what); static void _bind_methods(); + void _changed_callback(Object *p_changed, const char *p_prop); public: void set_enabled(bool p_enabled); @@ -185,6 +205,7 @@ public: String get_configuration_warning() const; NavigationMeshInstance(); + ~NavigationMeshInstance(); }; #endif // NAVIGATION_MESH_H diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 3fff42aa78..156560f802 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,6 +29,8 @@ /*************************************************************************/ #include "particles.h" + +#include "core/os/os.h" #include "scene/resources/particles_material.h" #include "servers/visual_server.h" @@ -224,6 +226,10 @@ bool Particles::get_fractional_delta() const { String Particles::get_configuration_warning() const { + if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles node instead. You can use the \"Convert to CPUParticles\" option for this purpose."); + } + String warnings; bool meshes_found = false; @@ -262,7 +268,7 @@ String Particles::get_configuration_warning() const { process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { if (warnings != String()) warnings += "\n"; - warnings += "- " + TTR("Particles animation requires the usage of a SpatialMaterial with \"Billboard Particles\" enabled."); + warnings += "- " + TTR("Particles animation requires the usage of a SpatialMaterial whose Billboard Mode is set to \"Particle Billboard\"."); } } @@ -348,7 +354,7 @@ void Particles::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); diff --git a/scene/3d/particles.h b/scene/3d/particles.h index 72241c5c89..42c68010db 100644 --- a/scene/3d/particles.h +++ b/scene/3d/particles.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index b732c3b8b7..84078911cb 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -44,10 +44,11 @@ void Path::_curve_changed() { emit_signal("curve_changed"); } - // update the configuration warnings of all children of type OrientedPathFollows + // update the configuration warnings of all children of type PathFollow + // previously used for PathFollowOriented (now enforced orientation is done in PathFollow) if (is_inside_tree()) { for (int i = 0; i < get_child_count(); i++) { - OrientedPathFollow *child = Object::cast_to<OrientedPathFollow>(get_child(i)); + PathFollow *child = Object::cast_to<PathFollow>(get_child(i)); if (child) { child->update_configuration_warning(); } @@ -105,24 +106,66 @@ void PathFollow::_update_transform() { return; } + float bl = c->get_baked_length(); + if (bl == 0.0) { + return; + } + float bi = c->get_bake_interval(); float o = offset; + float o_next = offset + bi; if (loop) { - o = Math::fposmod(o, c->get_baked_length()); + o = Math::fposmod(o, bl); + o_next = Math::fposmod(o_next, bl); + } else if (rotation_mode == ROTATION_ORIENTED && o_next >= bl) { + o = bl - bi; + o_next = bl; } Vector3 pos = c->interpolate_baked(o, cubic); Transform t = get_transform(); + // Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases + // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used + + if (rotation_mode == ROTATION_ORIENTED) { + + Vector3 forward = c->interpolate_baked(o_next, cubic) - pos; + + if (forward.length_squared() < CMP_EPSILON2) + forward = Vector3(0, 0, 1); + else + forward.normalize(); - t.origin = pos; - Vector3 pos_offset = Vector3(h_offset, v_offset, 0); + Vector3 up = c->interpolate_baked_up_vector(o, true); - if (rotation_mode != ROTATION_NONE) { + if (o_next < o) { + Vector3 up1 = c->interpolate_baked_up_vector(o_next, true); + Vector3 axis = up.cross(up1); + + if (axis.length_squared() < CMP_EPSILON2) + axis = forward; + else + axis.normalize(); + + up.rotate(axis, up.angle_to(up1) * 0.5f); + } + + Vector3 scale = t.basis.get_scale(); + Vector3 sideways = up.cross(forward).normalized(); + up = forward.cross(sideways).normalized(); + + t.basis.set(sideways, up, forward); + t.basis.scale_local(scale); + + t.origin = pos + sideways * h_offset + up * v_offset; + } else if (rotation_mode != ROTATION_NONE) { // perform parallel transport // // see C. Dougan, The Parallel Transport Frame, Game Programming Gems 2 for example // for a discussion about why not Frenet frame. + t.origin = pos; + Vector3 t_prev = (pos - c->interpolate_baked(o - delta_offset, cubic)).normalized(); Vector3 t_cur = (c->interpolate_baked(o + delta_offset, cubic) - pos).normalized(); @@ -130,7 +173,7 @@ void PathFollow::_update_transform() { float dot = t_prev.dot(t_cur); float angle = Math::acos(CLAMP(dot, -1, 1)); - if (likely(Math::abs(angle) > CMP_EPSILON)) { + if (likely(!Math::is_zero_approx(angle))) { if (rotation_mode == ROTATION_Y) { // assuming we're referring to global Y-axis. is this correct? axis.x = 0; @@ -141,7 +184,7 @@ void PathFollow::_update_transform() { // all components are allowed } - if (likely(axis.length() > CMP_EPSILON)) { + if (likely(!Math::is_zero_approx(axis.length()))) { t.rotate_basis(axis.normalized(), angle); } } @@ -150,7 +193,7 @@ void PathFollow::_update_transform() { float tilt_angle = c->interpolate_baked_tilt(o); Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct?? - if (likely(Math::abs(tilt_angle) > CMP_EPSILON)) { + if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) { if (rotation_mode == ROTATION_Y) { tilt_axis.x = 0; tilt_axis.z = 0; @@ -160,14 +203,14 @@ void PathFollow::_update_transform() { // all components are allowed } - if (likely(tilt_axis.length() > CMP_EPSILON)) { + if (likely(!Math::is_zero_approx(tilt_axis.length()))) { t.rotate_basis(tilt_axis.normalized(), tilt_angle); } } - t.translate(pos_offset); + t.translate(Vector3(h_offset, v_offset, 0)); } else { - t.origin += pos_offset; + t.origin = pos + Vector3(h_offset, v_offset, 0); } set_transform(t); @@ -213,7 +256,7 @@ void PathFollow::_validate_property(PropertyInfo &property) const { if (path && path->get_curve().is_valid()) max = path->get_curve()->get_baked_length(); - property.hint_string = "0," + rtos(max) + ",0.01"; + property.hint_string = "0," + rtos(max) + ",0.01,or_greater"; } } @@ -224,6 +267,11 @@ String PathFollow::get_configuration_warning() const { if (!Object::cast_to<Path>(get_parent())) { return TTR("PathFollow only works when set as a child of a Path node."); + } else { + Path *path = Object::cast_to<Path>(get_parent()); + if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) { + return TTR("PathFollow ROTATION_ORIENTED requires \"Up Vector\" enabled in its parent Path's Curve resource."); + } } return String(); @@ -253,10 +301,10 @@ void PathFollow::_bind_methods() { ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow::has_loop); ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ"), "set_rotation_mode", "get_rotation_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); @@ -264,6 +312,7 @@ void PathFollow::_bind_methods() { BIND_ENUM_CONSTANT(ROTATION_Y); BIND_ENUM_CONSTANT(ROTATION_XY); BIND_ENUM_CONSTANT(ROTATION_XYZ); + BIND_ENUM_CONSTANT(ROTATION_ORIENTED); } void PathFollow::set_offset(float p_offset) { @@ -322,6 +371,8 @@ float PathFollow::get_unit_offset() const { void PathFollow::set_rotation_mode(RotationMode p_rotation_mode) { rotation_mode = p_rotation_mode; + + update_configuration_warning(); _update_transform(); } @@ -351,236 +402,3 @@ PathFollow::PathFollow() { cubic = true; loop = true; } - -////////////// - -void OrientedPathFollow::_update_transform() { - - if (!path) - return; - - Ref<Curve3D> c = path->get_curve(); - if (!c.is_valid()) - return; - - int count = c->get_point_count(); - if (count < 2) - return; - - if (delta_offset == 0) { - return; - } - - float offset = get_offset(); - float bl = c->get_baked_length(); - float bi = c->get_bake_interval(); - float o = offset; - float o_next = offset + bi; - - if (has_loop()) { - o = Math::fposmod(o, bl); - o_next = Math::fposmod(o_next, bl); - } else if (o_next >= bl) { - o = bl - bi; - o_next = bl; - } - - bool cubic = get_cubic_interpolation(); - Vector3 pos = c->interpolate_baked(o, cubic); - Vector3 forward = c->interpolate_baked(o_next, cubic) - pos; - - if (forward.length_squared() < CMP_EPSILON2) - forward = Vector3(0, 0, 1); - else - forward.normalize(); - - Vector3 up = c->interpolate_baked_up_vector(o, true); - - if (o_next < o) { - Vector3 up1 = c->interpolate_baked_up_vector(o_next, true); - Vector3 axis = up.cross(up1); - - if (axis.length_squared() < CMP_EPSILON2) - axis = forward; - else - axis.normalize(); - - up.rotate(axis, up.angle_to(up1) * 0.5f); - } - - Transform t = get_transform(); - Vector3 scale = t.basis.get_scale(); - - Vector3 sideways = up.cross(forward).normalized(); - up = forward.cross(sideways).normalized(); - - t.basis.set(sideways, up, forward); - t.basis.scale_local(scale); - - t.origin = pos + sideways * get_h_offset() + up * get_v_offset(); - - set_transform(t); -} - -void OrientedPathFollow::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_ENTER_TREE: { - - Node *parent = get_parent(); - if (parent) { - path = Object::cast_to<Path>(parent); - if (path) { - _update_transform(); - } - } - - } break; - case NOTIFICATION_EXIT_TREE: { - - path = NULL; - } break; - } -} - -void OrientedPathFollow::set_cubic_interpolation(bool p_enable) { - - cubic = p_enable; -} - -bool OrientedPathFollow::get_cubic_interpolation() const { - - return cubic; -} - -void OrientedPathFollow::_validate_property(PropertyInfo &property) const { - - if (property.name == "offset") { - - float max = 10000; - if (path && path->get_curve().is_valid()) - max = path->get_curve()->get_baked_length(); - - property.hint_string = "0," + rtos(max) + ",0.01"; - } -} - -String OrientedPathFollow::get_configuration_warning() const { - - if (!is_visible_in_tree() || !is_inside_tree()) - return String(); - - if (!Object::cast_to<Path>(get_parent())) { - return TTR("OrientedPathFollow only works when set as a child of a Path node."); - } else { - Path *path = Object::cast_to<Path>(get_parent()); - if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled()) { - return TTR("OrientedPathFollow requires \"Up Vector\" enabled in its parent Path's Curve resource."); - } - } - - return String(); -} - -void OrientedPathFollow::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_offset", "offset"), &OrientedPathFollow::set_offset); - ClassDB::bind_method(D_METHOD("get_offset"), &OrientedPathFollow::get_offset); - - ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &OrientedPathFollow::set_h_offset); - ClassDB::bind_method(D_METHOD("get_h_offset"), &OrientedPathFollow::get_h_offset); - - ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &OrientedPathFollow::set_v_offset); - ClassDB::bind_method(D_METHOD("get_v_offset"), &OrientedPathFollow::get_v_offset); - - ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &OrientedPathFollow::set_unit_offset); - ClassDB::bind_method(D_METHOD("get_unit_offset"), &OrientedPathFollow::get_unit_offset); - - ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &OrientedPathFollow::set_cubic_interpolation); - ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &OrientedPathFollow::get_cubic_interpolation); - - ClassDB::bind_method(D_METHOD("set_loop", "loop"), &OrientedPathFollow::set_loop); - ClassDB::bind_method(D_METHOD("has_loop"), &OrientedPathFollow::has_loop); - - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); -} - -void OrientedPathFollow::set_offset(float p_offset) { - delta_offset = p_offset - offset; - offset = p_offset; - - if (path) - _update_transform(); - _change_notify("offset"); - _change_notify("unit_offset"); -} - -void OrientedPathFollow::set_h_offset(float p_h_offset) { - - h_offset = p_h_offset; - if (path) - _update_transform(); -} - -float OrientedPathFollow::get_h_offset() const { - - return h_offset; -} - -void OrientedPathFollow::set_v_offset(float p_v_offset) { - - v_offset = p_v_offset; - if (path) - _update_transform(); -} - -float OrientedPathFollow::get_v_offset() const { - - return v_offset; -} - -float OrientedPathFollow::get_offset() const { - - return offset; -} - -void OrientedPathFollow::set_unit_offset(float p_unit_offset) { - - if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) - set_offset(p_unit_offset * path->get_curve()->get_baked_length()); -} - -float OrientedPathFollow::get_unit_offset() const { - - if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) - return get_offset() / path->get_curve()->get_baked_length(); - else - return 0; -} - -void OrientedPathFollow::set_loop(bool p_loop) { - - loop = p_loop; -} - -bool OrientedPathFollow::has_loop() const { - - return loop; -} - -OrientedPathFollow::OrientedPathFollow() { - - offset = 0; - delta_offset = 0; - h_offset = 0; - v_offset = 0; - path = NULL; - cubic = true; - loop = true; -} diff --git a/scene/3d/path.h b/scene/3d/path.h index beb37d9714..2a12c4a826 100644 --- a/scene/3d/path.h +++ b/scene/3d/path.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -63,7 +63,8 @@ public: ROTATION_NONE, ROTATION_Y, ROTATION_XY, - ROTATION_XYZ + ROTATION_XYZ, + ROTATION_ORIENTED }; private: @@ -113,49 +114,4 @@ public: VARIANT_ENUM_CAST(PathFollow::RotationMode); -class OrientedPathFollow : public Spatial { - - GDCLASS(OrientedPathFollow, Spatial); - -private: - Path *path; - real_t delta_offset; // change in offset since last _update_transform - real_t offset; - real_t h_offset; - real_t v_offset; - bool cubic; - bool loop; - - void _update_transform(); - -protected: - virtual void _validate_property(PropertyInfo &property) const; - - void _notification(int p_what); - static void _bind_methods(); - -public: - void set_offset(float p_offset); - float get_offset() const; - - void set_h_offset(float p_h_offset); - float get_h_offset() const; - - void set_v_offset(float p_v_offset); - float get_v_offset() const; - - void set_unit_offset(float p_unit_offset); - float get_unit_offset() const; - - void set_loop(bool p_loop); - bool has_loop() const; - - void set_cubic_interpolation(bool p_enable); - bool get_cubic_interpolation() const; - - String get_configuration_warning() const; - - OrientedPathFollow(); -}; - #endif // PATH_H diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index bcfcf33e57..3624e04434 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -188,12 +188,12 @@ PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : #ifndef DISABLE_DEPRECATED void StaticBody::set_friction(real_t p_friction) { - if (p_friction == 1.0) { // default value, don't create an override for that + if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } - ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_friction < 0 || p_friction > 1); @@ -206,8 +206,8 @@ void StaticBody::set_friction(real_t p_friction) { real_t StaticBody::get_friction() const { - ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 1; @@ -218,12 +218,12 @@ real_t StaticBody::get_friction() const { void StaticBody::set_bounce(real_t p_bounce) { - if (p_bounce == 0.0) { // default value, don't create an override for that + if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } - ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); @@ -236,8 +236,8 @@ void StaticBody::set_bounce(real_t p_bounce) { real_t StaticBody::get_bounce() const { - ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 0; @@ -632,12 +632,12 @@ real_t RigidBody::get_weight() const { #ifndef DISABLE_DEPRECATED void RigidBody::set_friction(real_t p_friction) { - if (p_friction == 1.0) { // default value, don't create an override for that + if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } - ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_friction < 0 || p_friction > 1); @@ -649,8 +649,8 @@ void RigidBody::set_friction(real_t p_friction) { } real_t RigidBody::get_friction() const { - ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 1; @@ -661,12 +661,12 @@ real_t RigidBody::get_friction() const { void RigidBody::set_bounce(real_t p_bounce) { - if (p_bounce == 0.0) { // default value, don't create an override for that + if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } - ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); @@ -677,8 +677,8 @@ void RigidBody::set_bounce(real_t p_bounce) { physics_material_override->set_bounce(p_bounce); } real_t RigidBody::get_bounce() const { - ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 0; } @@ -1104,10 +1104,10 @@ void RigidBody::_reload_physics_characteristics() { ////////////////////////////////////////////////////// ////////////////////////// -Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_test_only) { +Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) { Collision col; - if (move_and_collide(p_motion, p_infinite_inertia, col, p_test_only)) { + if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) { if (motion_cache.is_null()) { motion_cache.instance(); motion_cache->owner = this; @@ -1121,11 +1121,11 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_inf return Ref<KinematicCollision>(); } -bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_test_only) { +bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) { Transform gt = get_global_transform(); PhysicsServer::MotionResult result; - bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result); + bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes); if (colliding) { r_collision.collider_metadata = result.collider_metadata; @@ -1181,19 +1181,16 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve while (p_max_slides) { Collision collision; - bool found_collision = false; - int test_type = 0; - - do { + for (int i = 0; i < 2; ++i) { bool collided; - if (test_type == 0) { //collide + if (i == 0) { //collide collided = move_and_collide(motion, p_infinite_inertia, collision); if (!collided) { motion = Vector3(); //clear because no collision happened and motion completed } - } else { + } else { //separate raycasts (if any) collided = separate_raycast_shapes(p_infinite_inertia, collision); if (collided) { collision.remainder = motion; //keep @@ -1203,9 +1200,6 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve if (collided) { found_collision = true; - } - - if (collided) { colliders.push_back(collision); motion = collision.remainder; @@ -1222,7 +1216,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve floor_velocity = collision.collider_vel; if (p_stop_on_slope) { - if (Vector3() == lv_n + p_floor_direction) { + if ((lv_n + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) { Transform gt = get_global_transform(); gt.origin -= collision.travel; set_global_transform(gt); @@ -1248,15 +1242,13 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve lv = lv.slide(n); } - for (int i = 0; i < 3; i++) { - if (locked_axis & (1 << i)) { - lv[i] = 0; + for (int j = 0; j < 3; j++) { + if (locked_axis & (1 << j)) { + lv[j] = 0; } } } - - ++test_type; - } while (!p_stop_on_slope && test_type < 2); + } if (!found_collision || motion == Vector3()) break; @@ -1279,14 +1271,27 @@ Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity Collision col; Transform gt = get_global_transform(); - if (move_and_collide(p_snap, p_infinite_inertia, col, true)) { - gt.origin += col.travel; - if (p_floor_direction != Vector3() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { - on_floor = true; - on_floor_body = col.collider_rid; - floor_velocity = col.collider_vel; + if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { + + bool apply = true; + if (p_floor_direction != Vector3()) { + if (Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { + on_floor = true; + on_floor_body = col.collider_rid; + floor_velocity = col.collider_vel; + if (p_stop_on_slope) { + // move and collide may stray the object a bit because of pre un-stucking, + // so only ensure that motion happens on floor direction in this case. + col.travel = p_floor_direction * p_floor_direction.dot(col.travel); + } + } else { + apply = false; //snapped with floor direction, but did not snap to a floor, do not snap. + } + } + if (apply) { + gt.origin += col.travel; + set_global_transform(gt); } - set_global_transform(gt); } return ret; @@ -1401,7 +1406,7 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) { void KinematicBody::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 5474290c07..aa6030d44e 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -310,14 +310,14 @@ private: _FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const; - Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_test_only = false); + Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false); Ref<KinematicCollision> _get_slide_collision(int p_bounce); protected: static void _bind_methods(); public: - bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collisionz, bool p_test_only = false); + bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false); bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia); bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision); diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index 8fd86c940c..c261ed3aeb 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h index 753795da90..f6df920314 100644 --- a/scene/3d/physics_joint.h +++ b/scene/3d/physics_joint.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/portal.cpp b/scene/3d/portal.cpp index 137338d79e..f5163dfcdd 100644 --- a/scene/3d/portal.cpp +++ b/scene/3d/portal.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/portal.h b/scene/3d/portal.h index cb3f208072..f053867917 100644 --- a/scene/3d/portal.h +++ b/scene/3d/portal.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/position_3d.cpp b/scene/3d/position_3d.cpp index 3ae04f491f..18de105eee 100644 --- a/scene/3d/position_3d.cpp +++ b/scene/3d/position_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/position_3d.h b/scene/3d/position_3d.h index 2bc69eff9b..21361592d1 100644 --- a/scene/3d/position_3d.h +++ b/scene/3d/position_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp index f56f728d99..96dc3304f2 100644 --- a/scene/3d/proximity_group.cpp +++ b/scene/3d/proximity_group.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -204,6 +204,7 @@ ProximityGroup::ProximityGroup() { group_version = 0; dispatch_mode = MODE_PROXY; + cell_size = 1.0; grid_radius = Vector3(1, 1, 1); set_notify_transform(true); }; diff --git a/scene/3d/proximity_group.h b/scene/3d/proximity_group.h index 448f30bf80..bd11e31031 100644 --- a/scene/3d/proximity_group.h +++ b/scene/3d/proximity_group.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index 17f069bbc8..10f92058e0 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h index e95382e1fe..43d55adb98 100644 --- a/scene/3d/ray_cast.h +++ b/scene/3d/ray_cast.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index fe522bbe97..c34771d9f1 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h index 13ae1c81f6..48d65b79f7 100644 --- a/scene/3d/reflection_probe.h +++ b/scene/3d/reflection_probe.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,7 +32,7 @@ #define REFLECTIONPROBE_H #include "scene/3d/visual_instance.h" -#include "scene/resources/sky_box.h" +#include "scene/resources/sky.h" #include "scene/resources/texture.h" #include "servers/visual_server.h" diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp index 490fcf24fd..add77e0272 100644 --- a/scene/3d/remote_transform.cpp +++ b/scene/3d/remote_transform.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/remote_transform.h b/scene/3d/remote_transform.h index 6b788a2d75..b737a4f858 100644 --- a/scene/3d/remote_transform.h +++ b/scene/3d/remote_transform.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/room_instance.cpp b/scene/3d/room_instance.cpp index 3914d7190e..073fe4f1da 100644 --- a/scene/3d/room_instance.cpp +++ b/scene/3d/room_instance.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/room_instance.h b/scene/3d/room_instance.h index ff388e606c..9ee140d522 100644 --- a/scene/3d/room_instance.h +++ b/scene/3d/room_instance.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index db82ef2a5c..e192e040f2 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -70,9 +70,9 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) { for (int i = 0; i < children.size(); i++) { - NodePath path = children[i]; - ERR_CONTINUE(path.operator String() == ""); - Node *node = get_node(path); + NodePath npath = children[i]; + ERR_CONTINUE(npath.operator String() == ""); + Node *node = get_node(npath); ERR_CONTINUE(!node); bind_child_node_to_bone(which, node); } @@ -115,8 +115,8 @@ bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const { ERR_CONTINUE(!obj); Node *node = Object::cast_to<Node>(obj); ERR_CONTINUE(!node); - NodePath path = get_path_to(node); - children.push_back(path); + NodePath npath = get_path_to(node); + children.push_back(npath); } r_ret = children; @@ -162,7 +162,7 @@ void Skeleton::_update_process_order() { //now check process order int pass_count = 0; while (pass_count < len * len) { - //using bubblesort because of simplicity, it wont run every frame though. + //using bubblesort because of simplicity, it won't run every frame though. //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic bool swapped = false; for (int i = 0; i < len; i++) { @@ -198,11 +198,7 @@ void Skeleton::_notification(int p_what) { case NOTIFICATION_ENTER_WORLD: { - if (dirty) { - - dirty = false; - _make_dirty(); // property make it dirty - } + VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform()); } break; case NOTIFICATION_EXIT_WORLD: { @@ -210,21 +206,7 @@ void Skeleton::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - if (dirty) - break; //will be eventually updated - - //if moved, just update transforms - VisualServer *vs = VisualServer::get_singleton(); - const Bone *bonesptr = bones.ptr(); - int len = bones.size(); - Transform global_transform = get_global_transform(); - Transform global_transform_inverse = global_transform.affine_inverse(); - - for (int i = 0; i < len; i++) { - - const Bone &b = bonesptr[i]; - vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse)); - } + VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform()); } break; case NOTIFICATION_UPDATE_SKELETON: { @@ -232,7 +214,7 @@ void Skeleton::_notification(int p_what) { Bone *bonesptr = bones.ptrw(); int len = bones.size(); - vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens + vs->skeleton_allocate(skeleton, len); // if same size, nothing really happens _update_process_order(); @@ -257,9 +239,6 @@ void Skeleton::_notification(int p_what) { rest_global_inverse_dirty = false; } - Transform global_transform = get_global_transform(); - Transform global_transform_inverse = global_transform.affine_inverse(); - for (int i = 0; i < len; i++) { Bone &b = bonesptr[order[i]]; @@ -320,7 +299,7 @@ void Skeleton::_notification(int p_what) { } b.transform_final = b.pose_global * b.rest_global_inverse; - vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse)); + vs->skeleton_bone_set_transform(skeleton, order[i], b.transform_final); for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) { @@ -561,10 +540,11 @@ void Skeleton::clear_bones() { void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) { ERR_FAIL_INDEX(p_bone, bones.size()); - ERR_FAIL_COND(!is_inside_tree()); bones.write[p_bone].pose = p_pose; - _make_dirty(); + if (is_inside_tree()) { + _make_dirty(); + } } Transform Skeleton::get_bone_pose(int p_bone) const { @@ -594,10 +574,6 @@ void Skeleton::_make_dirty() { if (dirty) return; - if (!is_inside_tree()) { - dirty = true; - return; - } MessageQueue::get_singleton()->push_notification(this, NOTIFICATION_UPDATE_SKELETON); dirty = true; } @@ -771,6 +747,16 @@ void Skeleton::physical_bones_remove_collision_exception(RID p_exception) { #endif // _3D_DISABLED +void Skeleton::set_use_bones_in_world_transform(bool p_enable) { + use_bones_in_world_transform = p_enable; + if (is_inside_tree()) { + VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform()); + } +} +bool Skeleton::is_using_bones_in_world_transform() const { + return use_bones_in_world_transform; +} + void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone); @@ -787,6 +773,8 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton::get_bone_rest); ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton::set_bone_rest); + ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests); + ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest); ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton::is_bone_rest_disabled); @@ -807,6 +795,9 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform); + ClassDB::bind_method(D_METHOD("set_use_bones_in_world_transform", "enable"), &Skeleton::set_use_bones_in_world_transform); + ClassDB::bind_method(D_METHOD("is_using_bones_in_world_transform"), &Skeleton::is_using_bones_in_world_transform); + #ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation); @@ -818,6 +809,7 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones_in_world_transform"), "set_use_bones_in_world_transform", "is_using_bones_in_world_transform"); BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); } @@ -828,6 +820,7 @@ Skeleton::Skeleton() { process_order_dirty = true; skeleton = VisualServer::get_singleton()->skeleton_create(); set_notify_transform(true); + use_bones_in_world_transform = false; } Skeleton::~Skeleton() { diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index 07abdc1fe7..5f43b3c6c3 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -100,6 +100,7 @@ class Skeleton : public Spatial { void _make_dirty(); bool dirty; + bool use_bones_in_world_transform; // bind helpers Array _get_bound_child_nodes_to_bone(int p_bone) const { @@ -179,6 +180,9 @@ public: void localize_rests(); // used for loaders and tools int get_process_order(int p_idx); + void set_use_bones_in_world_transform(bool p_enable); + bool is_using_bones_in_world_transform() const; + #ifndef _3D_DISABLED // Physical bone API diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp index 835a874323..909d4fda34 100644 --- a/scene/3d/soft_body.cpp +++ b/scene/3d/soft_body.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -104,6 +104,14 @@ SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) { offset = obj_tocopy.offset; } +SoftBody::PinnedPoint SoftBody::PinnedPoint::operator=(const PinnedPoint &obj) { + point_index = obj.point_index; + spatial_attachment_path = obj.spatial_attachment_path; + spatial_attachment = obj.spatial_attachment; + offset = obj.offset; + return *this; +} + void SoftBody::_update_pickable() { if (!is_inside_tree()) return; @@ -397,7 +405,7 @@ String SoftBody::get_configuration_warning() const { if (!warning.empty()) warning += "\n\n"; - warning += TTR("This body will be ignored until you set a mesh"); + warning += TTR("This body will be ignored until you set a mesh."); } Transform t = get_transform(); diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h index b1e699e839..ee455f8dab 100644 --- a/scene/3d/soft_body.h +++ b/scene/3d/soft_body.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -75,6 +75,7 @@ public: PinnedPoint(); PinnedPoint(const PinnedPoint &obj_tocopy); + PinnedPoint operator=(const PinnedPoint &obj); }; private: diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index dc09392713..efd418e3c7 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,6 +32,7 @@ #include "core/engine.h" #include "core/message_queue.h" +#include "scene/main/scene_tree.h" #include "scene/main/viewport.h" #include "scene/scene_string_names.h" @@ -177,7 +178,7 @@ void Spatial::_notification(int p_what) { get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, NULL, 0); } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this); get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); @@ -223,7 +224,8 @@ void Spatial::_notification(int p_what) { #endif } break; - default: {} + default: { + } } } @@ -401,6 +403,8 @@ void Spatial::update_gizmo() { if (!is_inside_world()) return; if (!data.gizmo.is_valid()) + get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); + if (!data.gizmo.is_valid()) return; if (data.gizmo_dirty) return; @@ -672,26 +676,29 @@ void Spatial::set_identity() { void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) { - Transform lookat; - lookat.origin = get_global_transform().origin; - if (lookat.origin == p_target) { + Vector3 origin(get_global_transform().origin); + look_at_from_position(origin, p_target, p_up); +} + +void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { + + if (p_pos == p_target) { ERR_EXPLAIN("Node origin and target are in the same position, look_at() failed"); ERR_FAIL(); } - if (p_up.cross(p_target - lookat.origin) == Vector3()) { + if (p_up.cross(p_target - p_pos) == Vector3()) { ERR_EXPLAIN("Up vector and direction between node origin and target are aligned, look_at() failed"); ERR_FAIL(); } - lookat = lookat.looking_at(p_target, p_up); - set_global_transform(lookat); -} - -void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { Transform lookat; lookat.origin = p_pos; + + Vector3 original_scale(get_global_transform().basis.get_scale()); lookat = lookat.looking_at(p_target, p_up); + // as basis was normalized, we just need to apply original scale back + lookat.basis.scale(original_scale); set_global_transform(lookat); } diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 815ca16bc5..18a4a5b54d 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/spatial_velocity_tracker.cpp b/scene/3d/spatial_velocity_tracker.cpp index 3850a0c7e6..97517be53b 100644 --- a/scene/3d/spatial_velocity_tracker.cpp +++ b/scene/3d/spatial_velocity_tracker.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/spatial_velocity_tracker.h b/scene/3d/spatial_velocity_tracker.h index a8278a4fb5..8260cf3f06 100644 --- a/scene/3d/spatial_velocity_tracker.h +++ b/scene/3d/spatial_velocity_tracker.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,7 @@ #include "scene/3d/spatial.h" class SpatialVelocityTracker : public Reference { - GDCLASS(SpatialVelocityTracker, Reference) + GDCLASS(SpatialVelocityTracker, Reference); struct PositionHistory { uint64_t frame; diff --git a/scene/3d/spring_arm.cpp b/scene/3d/spring_arm.cpp index f74784c2f9..f3665d251b 100644 --- a/scene/3d/spring_arm.cpp +++ b/scene/3d/spring_arm.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/spring_arm.h b/scene/3d/spring_arm.h index e0c3f2992d..35df56f06e 100644 --- a/scene/3d/spring_arm.h +++ b/scene/3d/spring_arm.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 7b4c7de029..6b70eef662 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -382,36 +382,30 @@ void Sprite3D::_draw() { VS::get_singleton()->immediate_clear(immediate); if (!texture.is_valid()) - return; //no texuture no life + return; Vector2 tsize = texture->get_size(); if (tsize.x == 0 || tsize.y == 0) return; - Size2i s; - Rect2 src_rect; - - if (region) { - - s = region_rect.size; - src_rect = region_rect; - } else { - s = texture->get_size(); - s = s / Size2(hframes, vframes); + Rect2 base_rect; + if (region) + base_rect = region_rect; + else + base_rect = Rect2(0, 0, texture->get_width(), texture->get_height()); - src_rect.size = s; - src_rect.position.x += (frame % hframes) * s.x; - src_rect.position.y += (frame / hframes) * s.y; - } + Size2 frame_size = base_rect.size / Size2(hframes, vframes); + Point2 frame_offset = Point2(frame % hframes, frame / hframes); + frame_offset *= frame_size; - Point2 ofs = get_offset(); + Point2 dest_offset = get_offset(); if (is_centered()) - ofs -= s / 2; - - Rect2 dst_rect(ofs, s); + dest_offset -= frame_size / 2; + Rect2 src_rect(base_rect.position + frame_offset, frame_size); + Rect2 final_dst_rect(dest_offset, frame_size); Rect2 final_rect; Rect2 final_src_rect; - if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect)) + if (!texture->get_rect_region(final_dst_rect, src_rect, final_rect, final_src_rect)) return; if (final_rect.size.x == 0 || final_rect.size.y == 0) diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index a4705a8970..0e086ef31e 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index 56a86b6a17..32b8219ee0 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -270,6 +270,8 @@ void VehicleWheel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_skidinfo"), &VehicleWheel::get_skidinfo); + ClassDB::bind_method(D_METHOD("get_rpm"), &VehicleWheel::get_rpm); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering"); ADD_GROUP("Wheel", "wheel_"); @@ -311,6 +313,11 @@ float VehicleWheel::get_skidinfo() const { return m_skidInfo; } +float VehicleWheel::get_rpm() const { + + return m_rpm; +} + VehicleWheel::VehicleWheel() { steers = false; @@ -716,7 +723,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { real_t rollingFriction = 0.f; if (wheelInfo.m_raycastInfo.m_isInContact) { - if (engine_force != 0.f) { + if (engine_force != 0.f && wheelInfo.engine_traction != false) { rollingFriction = -engine_force * s->get_step(); } else { real_t defaultRollingFrictionImpulse = 0.f; @@ -865,12 +872,11 @@ void VehicleBody::_direct_state_changed(Object *p_state) { real_t proj2 = fwd.dot(vel); wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius); - wheel.m_rotation += wheel.m_deltaRotation; - - } else { - wheel.m_rotation += wheel.m_deltaRotation; } + wheel.m_rotation += wheel.m_deltaRotation; + wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math_TAU; + wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact } diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h index 68fbf8d873..9e3fe72282 100644 --- a/scene/3d/vehicle_body.h +++ b/scene/3d/vehicle_body.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -68,6 +68,7 @@ class VehicleWheel : public Spatial { real_t m_steering; real_t m_rotation; real_t m_deltaRotation; + real_t m_rpm; real_t m_rollInfluence; //real_t m_engineForce; real_t m_brake; @@ -134,6 +135,8 @@ public: float get_skidinfo() const; + float get_rpm() const; + String get_configuration_warning() const; VehicleWheel(); diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp index 9a0832b27a..3014432d59 100644 --- a/scene/3d/visibility_notifier.cpp +++ b/scene/3d/visibility_notifier.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/visibility_notifier.h b/scene/3d/visibility_notifier.h index 2cf685a92c..ff4424300c 100644 --- a/scene/3d/visibility_notifier.h +++ b/scene/3d/visibility_notifier.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 6dc821c3f5..99c86f0406 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -123,6 +123,8 @@ void VisualInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance::_get_visual_instance_rid); ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance::set_base); + ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance::get_base); + ClassDB::bind_method(D_METHOD("get_instance"), &VisualInstance::get_instance); ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance::set_layer_mask); ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance::get_layer_mask); ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance::set_layer_mask_bit); @@ -136,6 +138,12 @@ void VisualInstance::_bind_methods() { void VisualInstance::set_base(const RID &p_base) { VisualServer::get_singleton()->instance_set_base(instance, p_base); + base = p_base; +} + +RID VisualInstance::get_base() const { + + return base; } VisualInstance::VisualInstance() { @@ -263,6 +271,11 @@ float GeometryInstance::get_extra_cull_margin() const { return extra_cull_margin; } +void GeometryInstance::set_custom_aabb(AABB aabb) { + + VS::get_singleton()->instance_set_custom_aabb(get_instance(), aabb); +} + void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance::set_material_override); @@ -289,6 +302,8 @@ void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance::set_extra_cull_margin); ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin); + ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance::set_custom_aabb); + ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb); ADD_GROUP("Geometry", ""); diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index 784f2a358a..3b924e0454 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -43,6 +43,7 @@ class VisualInstance : public Spatial { GDCLASS(VisualInstance, Spatial); OBJ_CATEGORY("3D Visual Nodes"); + RID base; RID instance; uint32_t layers; @@ -69,6 +70,7 @@ public: virtual AABB get_transformed_aabb() const; // helper void set_base(const RID &p_base); + RID get_base() const; void set_layer_mask(uint32_t p_mask); uint32_t get_layer_mask() const; @@ -87,6 +89,7 @@ class GeometryInstance : public VisualInstance { public: enum Flags { FLAG_USE_BAKED_LIGHT = VS::INSTANCE_FLAG_USE_BAKED_LIGHT, + FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, FLAG_MAX = VS::INSTANCE_FLAG_MAX, }; @@ -137,6 +140,8 @@ public: void set_extra_cull_margin(float p_margin); float get_extra_cull_margin() const; + void set_custom_aabb(AABB aabb); + GeometryInstance(); }; diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index 0eccbbc8f9..75b419ca58 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -342,8 +342,8 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p if (lnormal == Vector3()) //just in case normal as nor provided lnormal = normal; - int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); - int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); + int uv_x = CLAMP(int(Math::fposmod(uv.x, 1.0f) * bake_texture_size), 0, bake_texture_size - 1); + int uv_y = CLAMP(int(Math::fposmod(uv.y, 1.0f) * bake_texture_size), 0, bake_texture_size - 1); int ofs = uv_y * bake_texture_size + uv_x; albedo_accum.r += p_material.albedo[ofs].r; @@ -835,7 +835,7 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C for (int i = 0; i < 3; i++) { - if (ABS(light_axis[i]) < CMP_EPSILON) + if (Math::is_zero_approx(light_axis[i])) continue; clip[clip_planes].normal[i] = 1.0; @@ -887,7 +887,7 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C distance -= distance_adv; } - if (result == idx) { + if (result == (uint32_t)idx) { //cell hit itself! hooray! Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]); @@ -978,7 +978,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color for (int c = 0; c < 3; c++) { - if (ABS(light_axis[c]) < CMP_EPSILON) + if (Math::is_zero_approx(light_axis[c])) continue; clip[clip_planes].normal[c] = 1.0; @@ -1018,7 +1018,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color distance -= distance_adv; } - if (result == idx) { + if (result == (uint32_t)idx) { //cell hit itself! hooray! if (normal == Vector3()) { @@ -1113,7 +1113,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi for (int c = 0; c < 3; c++) { - if (ABS(light_axis[c]) < CMP_EPSILON) + if (Math::is_zero_approx(light_axis[c])) continue; clip[clip_planes].normal[c] = 1.0; @@ -1152,7 +1152,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi distance -= distance_adv; } - if (result == idx) { + if (result == (uint32_t)idx) { //cell hit itself! hooray! if (normal == Vector3()) { @@ -1730,7 +1730,7 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V //int level_limit = max_level; cell = 0; //start from root - for (int i = 0; i < max_level; i++) { + for (int j = 0; j < max_level; j++) { const Cell *bc = &cells[cell]; @@ -1759,14 +1759,14 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V } if (unlikely(cell != CHILD_EMPTY)) { - for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6; j++) { //anisotropic read light - float amount = direction.dot(aniso_normal[i]); + float amount = direction.dot(aniso_normal[j]); if (amount <= 0) continue; - accum.x += light[cell].accum[i][0] * amount; - accum.y += light[cell].accum[i][1] * amount; - accum.z += light[cell].accum[i][2] * amount; + accum.x += light[cell].accum[j][0] * amount; + accum.y += light[cell].accum[j][1] * amount; + accum.z += light[cell].accum[j][2] * amount; } accum.x += cells[cell].emission[0]; accum.y += cells[cell].emission[1]; @@ -1833,16 +1833,16 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh } int faces = ic ? ic / 3 : vc / 3; - for (int i = 0; i < faces; i++) { + for (int j = 0; j < faces; j++) { Vector3 vertex[3]; Vector3 normal[3]; Vector2 uv[3]; - for (int j = 0; j < 3; j++) { - int idx = ic ? ir[i * 3 + j] : i * 3 + j; - vertex[j] = xform.xform(vr[idx]); - normal[j] = xform.basis.xform(nr[idx]).normalized(); - uv[j] = u2r[idx]; + for (int k = 0; k < 3; k++) { + int idx = ic ? ir[j * 3 + k] : j * 3 + k; + vertex[k] = xform.xform(vr[idx]); + normal[k] = xform.basis.xform(nr[idx]).normalized(); + uv[k] = u2r[idx]; } _plot_triangle(uv, vertex, normal, lightmap.ptrw(), width, height); @@ -1931,7 +1931,6 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh //add directional light (do this after blur) { - LightMap *lightmap_ptr = lightmap.ptrw(); const Cell *cells = bake_cells.ptr(); const Light *light = bake_light.ptr(); #ifdef _OPENMP @@ -2209,7 +2208,7 @@ PoolVector<int> VoxelLightBaker::create_gi_probe_data() { } { - uint16_t alpha = CLAMP(uint32_t(bake_cells[i].alpha * 65535.0), 0, 65535); + uint16_t alpha = MIN(uint32_t(bake_cells[i].alpha * 65535.0), 65535); uint16_t level = bake_cells[i].level; w32[ofs++] = (uint32_t(level) << 16) | uint32_t(alpha); @@ -2253,7 +2252,7 @@ void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Re uint32_t child = bake_cells[p_idx].children[i]; - if (child == CHILD_EMPTY || child >= max_original_cells) + if (child == CHILD_EMPTY || child >= (uint32_t)max_original_cells) continue; AABB aabb = p_aabb; diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h index 3d55c053f3..295e099d47 100644 --- a/scene/3d/voxel_light_baker.h +++ b/scene/3d/voxel_light_baker.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/world_environment.cpp index 26cbfc0b11..3cd43cbf5b 100644 --- a/scene/3d/scenario_fx.cpp +++ b/scene/3d/world_environment.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* scenario_fx.cpp */ +/* world_environment.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "scenario_fx.h" +#include "world_environment.h" #include "scene/main/viewport.h" void WorldEnvironment::_notification(int p_what) { diff --git a/scene/3d/scenario_fx.h b/scene/3d/world_environment.h index 7a8e2b548f..bf36a0a532 100644 --- a/scene/3d/scenario_fx.h +++ b/scene/3d/world_environment.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* scenario_fx.h */ +/* world_environment.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index 76de39c3e6..dded44b990 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -110,7 +110,7 @@ void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_ if (p_at_index == -1 || p_at_index == blend_points_used) { p_at_index = blend_points_used; } else { - for (int i = blend_points_used - 1; i > p_at_index; i++) { + for (int i = blend_points_used - 1; i > p_at_index; i--) { blend_points[i] = blend_points[i - 1]; } } diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h index a83a813744..2e2d848450 100644 --- a/scene/animation/animation_blend_space_1d.h +++ b/scene/animation/animation_blend_space_1d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,7 @@ #include "scene/animation/animation_tree.h" class AnimationNodeBlendSpace1D : public AnimationRootNode { - GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode) + GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode); enum { MAX_BLEND_POINTS = 64 diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index 866b85c4c7..95d4644004 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -80,18 +80,15 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_ blend_points[p_at_index].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED); blend_points_used++; - if (auto_triangles) { - trianges_dirty = true; - } + _queue_auto_triangles(); + emit_signal("tree_changed"); } void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) { ERR_FAIL_INDEX(p_point, blend_points_used); blend_points[p_point].position = p_position; - if (auto_triangles) { - trianges_dirty = true; - } + _queue_auto_triangles(); } void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node) { ERR_FAIL_INDEX(p_point, blend_points_used); @@ -309,6 +306,15 @@ Vector<int> AnimationNodeBlendSpace2D::_get_triangles() const { return t; } +void AnimationNodeBlendSpace2D::_queue_auto_triangles() { + if (!auto_triangles || trianges_dirty) { + return; + } + + trianges_dirty = true; + call_deferred("_update_triangles"); +} + void AnimationNodeBlendSpace2D::_update_triangles() { if (!auto_triangles || !trianges_dirty) @@ -316,8 +322,10 @@ void AnimationNodeBlendSpace2D::_update_triangles() { trianges_dirty = false; triangles.clear(); - if (blend_points_used < 3) + if (blend_points_used < 3) { + emit_signal("triangles_updated"); return; + } Vector<Vector2> points; points.resize(blend_points_used); @@ -330,6 +338,7 @@ void AnimationNodeBlendSpace2D::_update_triangles() { for (int i = 0; i < triangles.size(); i++) { add_triangle(triangles[i].points[0], triangles[i].points[1], triangles[i].points[2]); } + emit_signal("triangles_updated"); } Vector2 AnimationNodeBlendSpace2D::get_closest_point(const Vector2 &p_point) { @@ -452,9 +461,9 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { points[j], points[(j + 1) % 3] }; - Vector2 closest = Geometry::get_closest_point_to_segment_2d(blend_pos, s); - if (first || closest.distance_to(blend_pos) < best_point.distance_to(blend_pos)) { - best_point = closest; + Vector2 closest2 = Geometry::get_closest_point_to_segment_2d(blend_pos, s); + if (first || closest2.distance_to(blend_pos) < best_point.distance_to(blend_pos)) { + best_point = closest2; blend_triangle = i; first = false; float d = s[0].distance_to(s[1]); @@ -463,7 +472,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { blend_weights[(j + 1) % 3] = 0.0; blend_weights[(j + 2) % 3] = 0.0; } else { - float c = s[0].distance_to(closest) / d; + float c = s[0].distance_to(closest2) / d; blend_weights[j] = 1.0 - c; blend_weights[(j + 1) % 3] = c; @@ -546,6 +555,10 @@ String AnimationNodeBlendSpace2D::get_caption() const { } void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &property) const { + + if (auto_triangles && property.name == "triangles") { + property.usage = 0; + } if (property.name.begins_with("blend_point_")) { String left = property.name.get_slicec('/', 0); int idx = left.get_slicec('_', 2).to_int(); @@ -557,10 +570,12 @@ void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &property) const } void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) { - auto_triangles = p_enable; - if (auto_triangles) { - trianges_dirty = true; + if (auto_triangles == p_enable) { + return; } + + auto_triangles = p_enable; + _queue_auto_triangles(); } bool AnimationNodeBlendSpace2D::get_auto_triangles() const { @@ -625,6 +640,7 @@ void AnimationNodeBlendSpace2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace2D::get_blend_mode); ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace2D::_tree_changed); + ClassDB::bind_method(D_METHOD("_update_triangles"), &AnimationNodeBlendSpace2D::_update_triangles); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles"); @@ -642,6 +658,7 @@ void AnimationNodeBlendSpace2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_y_label", "get_y_label"); ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NOEDITOR), "set_blend_mode", "get_blend_mode"); + ADD_SIGNAL(MethodInfo("triangles_updated")); BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED); BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE); BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY); diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h index 60671f1816..66ba9b0db7 100644 --- a/scene/animation/animation_blend_space_2d.h +++ b/scene/animation/animation_blend_space_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,8 @@ #include "scene/animation/animation_tree.h" class AnimationNodeBlendSpace2D : public AnimationRootNode { - GDCLASS(AnimationNodeBlendSpace2D, AnimationRootNode) + GDCLASS(AnimationNodeBlendSpace2D, AnimationRootNode); + public: enum BlendMode { BLEND_MODE_INTERPOLATED, @@ -82,6 +83,7 @@ protected: bool trianges_dirty; void _update_triangles(); + void _queue_auto_triangles(); void _tree_changed(); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 5b413737a9..20a09696e1 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -141,10 +141,14 @@ void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", 0)); r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0)); r_list->push_back(PropertyInfo(Variant::REAL, remaining, PROPERTY_HINT_NONE, "", 0)); + r_list->push_back(PropertyInfo(Variant::REAL, time_to_restart, PROPERTY_HINT_NONE, "", 0)); } + Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const { if (p_parameter == active || p_parameter == prev_active) { return false; + } else if (p_parameter == time_to_restart) { + return -1; } else { return 0.0; } @@ -218,13 +222,26 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) { bool prev_active = get_parameter(this->prev_active); float time = get_parameter(this->time); float remaining = get_parameter(this->remaining); + float time_to_restart = get_parameter(this->time_to_restart); if (!active) { //make it as if this node doesn't exist, pass input 0 by. if (prev_active) { set_parameter(this->prev_active, false); } - return blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); + if (time_to_restart >= 0.0 && !p_seek) { + time_to_restart -= p_time; + if (time_to_restart < 0) { + //restart + set_parameter(this->active, true); + active = true; + } + set_parameter(this->time_to_restart, time_to_restart); + } + + if (!active) { + return blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); + } } bool os_seek = p_seek; @@ -276,6 +293,10 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) { if (remaining <= 0) { set_parameter(this->active, false); set_parameter(this->prev_active, false); + if (autorestart) { + float restart_sec = autorestart_delay + Math::randf() * autorestart_random_delay; + set_parameter(this->time_to_restart, restart_sec); + } } } @@ -342,6 +363,7 @@ AnimationNodeOneShot::AnimationNodeOneShot() { fade_out = 0.1; autorestart = false; autorestart_delay = 1; + autorestart_random_delay = 0; mix = MIX_MODE_BLEND; sync = false; @@ -350,6 +372,7 @@ AnimationNodeOneShot::AnimationNodeOneShot() { prev_active = "prev_active"; time = "time"; remaining = "remaining"; + time_to_restart = "time_to_restart"; } //////////////////////////////////////////////// @@ -835,12 +858,12 @@ AnimationNodeTransition::AnimationNodeTransition() { time = "time"; current = "current"; prev_current = "prev_current"; - ; + xfade = 0.0; enabled_inputs = 0; for (int i = 0; i < MAX_INPUTS; i++) { inputs[i].auto_advance = false; - inputs[i].name = itos(i + 1); + inputs[i].name = "state " + itos(i); } } @@ -1026,7 +1049,7 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node return CONNECTION_ERROR_NO_INPUT; } - if (!nodes.has(p_input_node)) { + if (p_input_node == p_output_node) { return CONNECTION_ERROR_SAME_NODE; } diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index 5adb7fd71a..a6ef78d82e 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -91,6 +91,7 @@ private: StringName prev_active; StringName time; StringName remaining; + StringName time_to_restart; protected: static void _bind_methods(); @@ -321,7 +322,8 @@ public: }; class AnimationNodeOutput : public AnimationNode { - GDCLASS(AnimationNodeOutput, AnimationNode) + GDCLASS(AnimationNodeOutput, AnimationNode); + public: virtual String get_caption() const; virtual float process(float p_time, bool p_seek); @@ -331,7 +333,7 @@ public: ///// class AnimationNodeBlendTree : public AnimationRootNode { - GDCLASS(AnimationNodeBlendTree, AnimationRootNode) + GDCLASS(AnimationNodeBlendTree, AnimationRootNode); struct Node { Ref<AnimationNode> node; diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp index 756907c41c..84b3f103c5 100644 --- a/scene/animation/animation_cache.cpp +++ b/scene/animation/animation_cache.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -133,19 +133,19 @@ void AnimationCache::_update_cache() { } else { if (np.get_subname_count() > 0) { - RES res; + RES res2; Vector<StringName> leftover_subpath; // We don't want to cache the last resource unless it is a method call bool is_method = animation->track_get_type(i) == Animation::TYPE_METHOD; - root->get_node_and_resource(np, res, leftover_subpath, is_method); + root->get_node_and_resource(np, res2, leftover_subpath, is_method); - if (res.is_valid()) { - path.resource = res; + if (res2.is_valid()) { + path.resource = res2; } else { path.node = node; } - path.object = res.is_valid() ? res.ptr() : (Object *)node; + path.object = res2.is_valid() ? res2.ptr() : (Object *)node; path.subpath = leftover_subpath; } else { @@ -309,7 +309,8 @@ void AnimationCache::set_all(float p_time, float p_delta) { } } break; - default: {} + default: { + } } } } diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h index cf28236376..ac668b7796 100644 --- a/scene/animation/animation_cache.h +++ b/scene/animation/animation_cache.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index f67ef8164a..a2411743d4 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -314,8 +314,9 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, if (start_request_travel) { if (!playing) { + String node_name = start_request; start_request = StringName(); - ERR_EXPLAIN("Can't travel to '" + String(start_request) + "' if state machine is not active."); + ERR_EXPLAIN("Can't travel to '" + node_name + "' if state machine is not playing."); ERR_FAIL_V(0); } @@ -373,7 +374,7 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, if (fading_from != StringName()) { - sm->blend_node(current, sm->states[fading_from].node, p_time, p_seek, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, false); + sm->blend_node(fading_from, sm->states[fading_from].node, p_time, p_seek, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, false); } //guess playback position @@ -421,7 +422,8 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, if (sm->transitions[i].from == current && auto_advance) { - if (sm->transitions[i].transition->get_priority() < priority_best) { + if (sm->transitions[i].transition->get_priority() <= priority_best) { + priority_best = sm->transitions[i].transition->get_priority(); auto_advance_to = i; } } @@ -439,13 +441,13 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, bool goto_next = false; - if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE) { - goto_next = fading_from == StringName(); - } else { + if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) { goto_next = next_xfade >= (len_current - pos_current) || loops_current > 0; if (loops_current > 0) { next_xfade = 0; } + } else { + goto_next = fading_from == StringName(); } if (goto_next) { //loops should be used because fade time may be too small or zero and animation may have looped @@ -597,6 +599,9 @@ void AnimationNodeStateMachine::remove_node(const StringName &p_name) { { Ref<AnimationNode> node = states[p_name].node; + + ERR_FAIL_COND(node.is_null()); + node->disconnect("tree_changed", this, "_tree_changed"); } @@ -959,7 +964,7 @@ void AnimationNodeStateMachine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_end_node", "name"), &AnimationNodeStateMachine::set_end_node); ClassDB::bind_method(D_METHOD("get_end_node"), &AnimationNodeStateMachine::get_end_node); - ClassDB::bind_method(D_METHOD("set_graph_offset", "name"), &AnimationNodeStateMachine::set_graph_offset); + ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeStateMachine::set_graph_offset); ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeStateMachine::get_graph_offset); ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeStateMachine::_tree_changed); diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index a88b3eb482..26909a326e 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,8 @@ #include "scene/animation/animation_tree.h" class AnimationNodeStateMachineTransition : public Resource { - GDCLASS(AnimationNodeStateMachineTransition, Resource) + GDCLASS(AnimationNodeStateMachineTransition, Resource); + public: enum SwitchMode { SWITCH_MODE_IMMEDIATE, diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index cfc3b2f4ce..75088c79fe 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,12 +34,23 @@ #include "core/message_queue.h" #include "scene/scene_string_names.h" #include "servers/audio/audio_stream.h" + #ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#include "scene/2d/skeleton_2d.h" + void AnimatedValuesBackup::update_skeletons() { for (int i = 0; i < entries.size(); i++) { if (entries[i].bone_idx != -1) { + // 3D bone Object::cast_to<Skeleton>(entries[i].object)->notification(Skeleton::NOTIFICATION_UPDATE_SKELETON); + } else { + Bone2D *bone = Object::cast_to<Bone2D>(entries[i].object); + if (bone && bone->skeleton) { + // 2D bone + bone->skeleton->_update_transform(); + } } } } @@ -287,7 +298,6 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) { // broken track (nonexistent bone) p_anim->node_cache[i]->skeleton = NULL; p_anim->node_cache[i]->spatial = NULL; - printf("bone is %ls\n", String(bone_name).c_str()); ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0); } } else { @@ -344,10 +354,16 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float for (int i = 0; i < a->get_track_count(); i++) { + // If an animation changes this animation (or it animates itself) + // we need to recreate our animation cache + if (p_anim->node_cache.size() != a->get_track_count()) { + _ensure_node_caches(p_anim); + } + TrackNodeCache *nc = p_anim->node_cache[i]; - if (!nc) // no node cache for this track, skip it - continue; + if (!nc) + continue; // no node cache for this track, skip it if (!a->track_is_enabled(i)) continue; // do nothing if the track is disabled @@ -985,25 +1001,12 @@ void AnimationPlayer::remove_animation(const StringName &p_name) { void AnimationPlayer::_ref_anim(const Ref<Animation> &p_anim) { - if (used_anims.has(p_anim)) - used_anims[p_anim]++; - else { - used_anims[p_anim] = 1; - Ref<Animation>(p_anim)->connect("changed", this, "_animation_changed"); - } + Ref<Animation>(p_anim)->connect(SceneStringNames::get_singleton()->tracks_changed, this, "_animation_changed", varray(), CONNECT_REFERENCE_COUNTED); } void AnimationPlayer::_unref_anim(const Ref<Animation> &p_anim) { - ERR_FAIL_COND(!used_anims.has(p_anim)); - - int &n = used_anims[p_anim]; - n--; - if (n == 0) { - - Ref<Animation>(p_anim)->disconnect("changed", this, "_animation_changed"); - used_anims.erase(p_anim); - } + Ref<Animation>(p_anim)->disconnect(SceneStringNames::get_singleton()->tracks_changed, this, "_animation_changed"); } void AnimationPlayer::rename_animation(const StringName &p_name, const StringName &p_new_name) { @@ -1140,8 +1143,6 @@ void AnimationPlayer::play_backwards(const StringName &p_name, float p_custom_bl void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float p_custom_scale, bool p_from_end) { - //printf("animation is %ls\n", String(p_name).c_str()); - //ERR_FAIL_COND(!is_inside_scene()); StringName name = p_name; if (String(name) == "") @@ -1199,9 +1200,21 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float _stop_playing_caches(); c.current.from = &animation_set[name]; - c.current.pos = p_from_end ? c.current.from->animation->get_length() : 0; + + if (c.assigned != name) { // reset + c.current.pos = p_from_end ? c.current.from->animation->get_length() : 0; + } else { + if (p_from_end && c.current.pos == 0) { + // Animation reset BUT played backwards, set position to the end + c.current.pos = c.current.from->animation->get_length(); + } else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) { + // Animation resumed but already ended, set position to the beginning + c.current.pos = 0; + } + } + c.current.speed_scale = p_custom_scale; - c.assigned = p_name; + c.assigned = name; c.seeked = false; c.started = true; @@ -1280,6 +1293,7 @@ void AnimationPlayer::stop(bool p_reset) { if (p_reset) { c.current.from = NULL; c.current.speed_scale = 1; + c.current.pos = 0; } _set_process(false); queued.clear(); @@ -1507,13 +1521,19 @@ NodePath AnimationPlayer::get_root() const { void AnimationPlayer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { +#ifdef TOOLS_ENABLED + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\""; +#else + const String quote_style = "\""; +#endif + String pf = p_function; if (p_function == "play" || p_function == "play_backwards" || p_function == "remove_animation" || p_function == "has_animation" || p_function == "queue") { List<StringName> al; get_animation_list(&al); for (List<StringName>::Element *E = al.front(); E; E = E->next()) { - r_options->push_back("\"" + String(E->get()) + "\""); + r_options->push_back(quote_style + String(E->get()) + quote_style); } } Node::get_argument_options(p_function, p_idx, r_options); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index b3bf8b1e22..fea4819821 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -114,10 +114,12 @@ private: Variant value_accum; uint64_t accum_pass; Variant capture; - PropertyAnim() { - accum_pass = 0; - object = NULL; - } + + PropertyAnim() : + owner(NULL), + special(SP_NONE), + object(NULL), + accum_pass(0) {} }; Map<StringName, PropertyAnim> property_anim; @@ -129,25 +131,28 @@ private: float bezier_accum; Object *object; uint64_t accum_pass; - BezierAnim() { - accum_pass = 0; - bezier_accum = 0; - object = NULL; - } + + BezierAnim() : + owner(NULL), + bezier_accum(0.0), + object(NULL), + accum_pass(0) {} }; Map<StringName, BezierAnim> bezier_anim; - TrackNodeCache() { - skeleton = NULL; - spatial = NULL; - node = NULL; - accum_pass = 0; - bone_idx = -1; - node_2d = NULL; - audio_playing = false; - animation_playing = false; - } + TrackNodeCache() : + id(0), + node(NULL), + spatial(NULL), + node_2d(NULL), + skeleton(NULL), + bone_idx(-1), + accum_pass(0), + audio_playing(false), + audio_start(0.0), + audio_len(0.0), + animation_playing(false) {} }; struct TrackNodeCacheKey { @@ -176,8 +181,6 @@ private: int cache_update_bezier_size; Set<TrackNodeCache *> playing_caches; - Map<Ref<Animation>, int> used_anims; - uint64_t accum_pass; float speed_scale; float default_blend_time; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 2c8cbbdbd1..54f0fdc26a 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -316,7 +316,7 @@ String AnimationNode::get_caption() const { void AnimationNode::add_input(const String &p_name) { //root nodes can't add inputs - ERR_FAIL_COND(Object::cast_to<AnimationRootNode>(this) != NULL) + ERR_FAIL_COND(Object::cast_to<AnimationRootNode>(this) != NULL); Input input; ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1); input.name = p_name; @@ -685,6 +685,10 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { track = track_animation; } break; + default: { + ERR_PRINT("Animation corrupted (invalid track type)"); + continue; + } } track_cache[path] = track; @@ -853,6 +857,9 @@ void AnimationTree::_process_graph(float p_delta) { for (int i = 0; i < a->get_track_count(); i++) { NodePath path = a->track_get_path(i); + + ERR_CONTINUE(!track_cache.has(path)); + TrackCache *track = track_cache[path]; if (track->type != a->track_get_type(i)) { continue; //may happen should not @@ -876,16 +883,16 @@ void AnimationTree::_process_graph(float p_delta) { TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); - if (t->process_pass != process_pass) { + if (track->root_motion) { - t->process_pass = process_pass; - t->loc = Vector3(); - t->rot = Quat(); - t->rot_blend_accum = 0; - t->scale = Vector3(); - } + if (t->process_pass != process_pass) { - if (track->root_motion) { + t->process_pass = process_pass; + t->loc = Vector3(); + t->rot = Quat(); + t->rot_blend_accum = 0; + t->scale = Vector3(1, 1, 1); + } float prev_time = time - delta; if (prev_time < 0) { @@ -939,7 +946,14 @@ void AnimationTree::_process_graph(float p_delta) { Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); //ERR_CONTINUE(err!=OK); //used for testing, should be removed - scale -= Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes + if (t->process_pass != process_pass) { + + t->process_pass = process_pass; + t->loc = loc; + t->rot = rot; + t->rot_blend_accum = 0; + t->scale = scale; + } if (err != OK) continue; @@ -971,8 +985,7 @@ void AnimationTree::_process_graph(float p_delta) { continue; if (t->process_pass != process_pass) { - Variant::CallError ce; - t->value = Variant::construct(value.get_type(), NULL, 0, ce); //reset + t->value = value; t->process_pass = process_pass; } @@ -1002,10 +1015,10 @@ void AnimationTree::_process_graph(float p_delta) { a->method_track_get_key_indices(i, time, delta, &indices); - for (List<int>::Element *E = indices.front(); E; E = E->next()) { + for (List<int>::Element *F = indices.front(); F; F = F->next()) { - StringName method = a->method_track_get_name(i, E->get()); - Vector<Variant> params = a->method_track_get_params(i, E->get()); + StringName method = a->method_track_get_name(i, F->get()); + Vector<Variant> params = a->method_track_get_params(i, F->get()); int s = params.size(); @@ -1029,7 +1042,7 @@ void AnimationTree::_process_graph(float p_delta) { float bezier = a->bezier_track_interpolate(i, time); if (t->process_pass != process_pass) { - t->value = 0; + t->value = bezier; t->process_pass = process_pass; } @@ -1144,9 +1157,9 @@ void AnimationTree::_process_graph(float p_delta) { TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track); - AnimationPlayer *player = Object::cast_to<AnimationPlayer>(t->object); + AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object); - if (!player) + if (!player2) continue; if (delta == 0 || seeked) { @@ -1158,10 +1171,10 @@ void AnimationTree::_process_graph(float p_delta) { float pos = a->track_get_key_time(i, idx); StringName anim_name = a->animation_track_get_key_animation(i, idx); - if (String(anim_name) == "[stop]" || !player->has_animation(anim_name)) + if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) continue; - Ref<Animation> anim = player->get_animation(anim_name); + Ref<Animation> anim = player2->get_animation(anim_name); float at_anim_pos; @@ -1171,14 +1184,14 @@ void AnimationTree::_process_graph(float p_delta) { at_anim_pos = MAX(anim->get_length(), time - pos); //seek to end } - if (player->is_playing() || seeked) { - player->play(anim_name); - player->seek(at_anim_pos); + if (player2->is_playing() || seeked) { + player2->play(anim_name); + player2->seek(at_anim_pos); t->playing = true; playing_caches.insert(t); } else { - player->set_assigned_animation(anim_name); - player->seek(at_anim_pos, true); + player2->set_assigned_animation(anim_name); + player2->seek(at_anim_pos, true); } } else { //find stuff to play @@ -1188,15 +1201,15 @@ void AnimationTree::_process_graph(float p_delta) { int idx = to_play.back()->get(); StringName anim_name = a->animation_track_get_key_animation(i, idx); - if (String(anim_name) == "[stop]" || !player->has_animation(anim_name)) { + if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) { if (playing_caches.has(t)) { playing_caches.erase(t); - player->stop(); + player2->stop(); t->playing = false; } } else { - player->play(anim_name); + player2->play(anim_name); t->playing = true; playing_caches.insert(t); } @@ -1226,8 +1239,6 @@ void AnimationTree::_process_graph(float p_delta) { Transform xform; xform.origin = t->loc; - t->scale += Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes and root motion - xform.basis.set_quat_scale(t->rot, t->scale); if (t->root_motion) { @@ -1261,7 +1272,8 @@ void AnimationTree::_process_graph(float p_delta) { t->object->set_indexed(t->subpath, t->value); } break; - default: {} //the rest don't matter + default: { + } //the rest don't matter } } } @@ -1286,9 +1298,17 @@ void AnimationTree::_notification(int p_what) { _clear_caches(); if (last_animation_player) { - Object *old_player = ObjectDB::get_instance(last_animation_player); - if (old_player) { - old_player->disconnect("caches_cleared", this, "_clear_caches"); + Object *player = ObjectDB::get_instance(last_animation_player); + if (player) { + player->disconnect("caches_cleared", this, "_clear_caches"); + } + } + } else if (p_what == NOTIFICATION_ENTER_TREE) { + if (last_animation_player) { + + Object *player = ObjectDB::get_instance(last_animation_player); + if (player) { + player->connect("caches_cleared", this, "_clear_caches"); } } } @@ -1560,6 +1580,7 @@ AnimationTree::AnimationTree() { active = false; cache_valid = false; setup_pass = 1; + process_pass = 1; started = true; properties_dirty = true; last_animation_player = 0; diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index cda7f8ae74..e22d6e4c2d 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -41,7 +41,8 @@ class AnimationPlayer; class AnimationTree; class AnimationNode : public Resource { - GDCLASS(AnimationNode, Resource) + GDCLASS(AnimationNode, Resource); + public: enum FilterAction { FILTER_IGNORE, @@ -155,13 +156,15 @@ VARIANT_ENUM_CAST(AnimationNode::FilterAction) //root node does not allow inputs class AnimationRootNode : public AnimationNode { - GDCLASS(AnimationRootNode, AnimationNode) + GDCLASS(AnimationRootNode, AnimationNode); + public: AnimationRootNode() {} }; class AnimationTree : public Node { - GDCLASS(AnimationTree, Node) + GDCLASS(AnimationTree, Node); + public: enum AnimationProcessMode { ANIMATION_PROCESS_PHYSICS, diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 6adfb94695..5c3e123ac3 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -136,9 +136,9 @@ bool AnimationTreePlayer::_set(const StringName &p_name, const Variant &p_value) else animation_node_set_animation(id, node.get_valid("animation")); Array filters = node.get_valid("filter"); - for (int i = 0; i < filters.size(); i++) { + for (int j = 0; j < filters.size(); j++) { - animation_node_set_filter_path(id, filters[i], true); + animation_node_set_filter_path(id, filters[j], true); } } break; case NODE_ONESHOT: { @@ -150,9 +150,9 @@ bool AnimationTreePlayer::_set(const StringName &p_name, const Variant &p_value) oneshot_node_set_autorestart_delay(id, node.get_valid("autorestart_delay")); oneshot_node_set_autorestart_random_delay(id, node.get_valid("autorestart_random_delay")); Array filters = node.get_valid("filter"); - for (int i = 0; i < filters.size(); i++) { + for (int j = 0; j < filters.size(); j++) { - oneshot_node_set_filter_path(id, filters[i], true); + oneshot_node_set_filter_path(id, filters[j], true); } } break; @@ -162,9 +162,9 @@ bool AnimationTreePlayer::_set(const StringName &p_name, const Variant &p_value) case NODE_BLEND2: { blend2_node_set_amount(id, node.get_valid("blend")); Array filters = node.get_valid("filter"); - for (int i = 0; i < filters.size(); i++) { + for (int j = 0; j < filters.size(); j++) { - blend2_node_set_filter_path(id, filters[i], true); + blend2_node_set_filter_path(id, filters[j], true); } } break; case NODE_BLEND3: { @@ -193,7 +193,8 @@ bool AnimationTreePlayer::_set(const StringName &p_name, const Variant &p_value) } } break; - default: {}; + default: { + }; } } @@ -278,8 +279,8 @@ bool AnimationTreePlayer::_get(const StringName &p_name, Variant &r_ret) const { an->filter.get_key_list(&keys); k.resize(keys.size()); int i = 0; - for (List<NodePath>::Element *E = keys.front(); E; E = E->next()) { - k[i++] = E->get(); + for (List<NodePath>::Element *F = keys.front(); F; F = F->next()) { + k[i++] = F->get(); } node["filter"] = k; } break; @@ -297,8 +298,8 @@ bool AnimationTreePlayer::_get(const StringName &p_name, Variant &r_ret) const { osn->filter.get_key_list(&keys); k.resize(keys.size()); int i = 0; - for (List<NodePath>::Element *E = keys.front(); E; E = E->next()) { - k[i++] = E->get(); + for (List<NodePath>::Element *F = keys.front(); F; F = F->next()) { + k[i++] = F->get(); } node["filter"] = k; @@ -315,8 +316,8 @@ bool AnimationTreePlayer::_get(const StringName &p_name, Variant &r_ret) const { bn->filter.get_key_list(&keys); k.resize(keys.size()); int i = 0; - for (List<NodePath>::Element *E = keys.front(); E; E = E->next()) { - k[i++] = E->get(); + for (List<NodePath>::Element *F = keys.front(); F; F = F->next()) { + k[i++] = F->get(); } node["filter"] = k; @@ -352,7 +353,8 @@ bool AnimationTreePlayer::_get(const StringName &p_name, Variant &r_ret) const { node["transitions"] = transitions; } break; - default: {}; + default: { + }; } nodes.push_back(node); @@ -402,7 +404,7 @@ void AnimationTreePlayer::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { ERR_EXPLAIN("AnimationTreePlayer has been deprecated. Use AnimationTree instead."); - WARN_DEPRECATED + WARN_DEPRECATED; if (!processing) { //make sure that a previous process state was not saved @@ -772,7 +774,8 @@ float AnimationTreePlayer::_process_node(const StringName &p_node, AnimationNode } } break; - default: {} + default: { + } } return 0; @@ -874,15 +877,16 @@ void AnimationTreePlayer::_process_animation(float p_delta) { List<int> indices; a->method_track_get_key_indices(tr.local_track, anim_list->time, anim_list->step, &indices); - for (List<int>::Element *E = indices.front(); E; E = E->next()) { + for (List<int>::Element *F = indices.front(); F; F = F->next()) { - StringName method = a->method_track_get_name(tr.local_track, E->get()); - Vector<Variant> args = a->method_track_get_params(tr.local_track, E->get()); + StringName method = a->method_track_get_name(tr.local_track, F->get()); + Vector<Variant> args = a->method_track_get_params(tr.local_track, F->get()); args.resize(VARIANT_ARG_MAX); tr.track->object->call(method, args[0], args[1], args[2], args[3], args[4]); } } break; - default: {} + default: { + } } } } @@ -969,7 +973,8 @@ void AnimationTreePlayer::add_node(NodeType p_type, const StringName &p_node) { n = memnew(TransitionNode); } break; - default: {} + default: { + } } //n->name+=" "+itos(p_node); diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h index 4e4c876e87..9ec6325969 100644 --- a/scene/animation/animation_tree_player.h +++ b/scene/animation/animation_tree_player.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -109,6 +109,14 @@ private: Variant value; bool skip; + + Track() : + id(0), + object(NULL), + spatial(NULL), + skeleton(NULL), + bone_idx(-1), + skip(false) {} }; typedef Map<TrackKey, Track> TrackMap; diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp index 01a10dbc2b..646a39d063 100644 --- a/scene/animation/root_motion_view.cpp +++ b/scene/animation/root_motion_view.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h index 5198ab21aa..07f51165a7 100644 --- a/scene/animation/root_motion_view.h +++ b/scene/animation/root_motion_view.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,8 @@ #include "scene/3d/visual_instance.h" class RootMotionView : public VisualInstance { - GDCLASS(RootMotionView, VisualInstance) + GDCLASS(RootMotionView, VisualInstance); + public: RID immediate; NodePath path; diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index 3119e29586..06d6806f03 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,20 +37,20 @@ #ifndef _3D_DISABLED FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) { - for (int i = childs.size() - 1; 0 <= i; --i) { - if (p_bone_id == childs[i].bone) { - return &childs.write[i]; + for (int i = children.size() - 1; 0 <= i; --i) { + if (p_bone_id == children[i].bone) { + return &children.write[i]; } } return NULL; } FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child(const BoneId p_bone_id) { - const int infant_child_id = childs.size(); - childs.resize(infant_child_id + 1); - childs.write[infant_child_id].bone = p_bone_id; - childs.write[infant_child_id].parent_item = this; - return &childs.write[infant_child_id]; + const int infant_child_id = children.size(); + children.resize(infant_child_id + 1); + children.write[infant_child_id].bone = p_bone_id; + children.write[infant_child_id].parent_item = this; + return &children.write[infant_child_id]; } /// Build a chain that starts from the root to tip @@ -144,8 +144,8 @@ void FabrikInverseKinematic::update_chain(const Skeleton *p_sk, ChainItem *p_cha p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone); p_chain_item->current_pos = p_chain_item->initial_transform.origin; - for (int i = p_chain_item->childs.size() - 1; 0 <= i; --i) { - update_chain(p_sk, &p_chain_item->childs.write[i]); + for (int i = p_chain_item->children.size() - 1; 0 <= i; --i) { + update_chain(p_sk, &p_chain_item->children.write[i]); } } @@ -210,9 +210,9 @@ void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_ while (sub_chain_root) { // Reach the tip sub_chain_root->current_pos = origin; - if (!sub_chain_root->childs.empty()) { + if (!sub_chain_root->children.empty()) { - ChainItem &child(sub_chain_root->childs.write[0]); + ChainItem &child(sub_chain_root->children.write[0]); // Is not tip // So calculate next origin location @@ -302,10 +302,10 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove Transform new_bone_pose(ci->initial_transform); new_bone_pose.origin = ci->current_pos; - if (!ci->childs.empty()) { + if (!ci->children.empty()) { /// Rotate basis - const Vector3 initial_ori((ci->childs[0].initial_transform.origin - ci->initial_transform.origin).normalized()); + const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized()); const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized()); if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) { @@ -322,8 +322,8 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose); - if (!ci->childs.empty()) - ci = &ci->childs.write[0]; + if (!ci->children.empty()) + ci = &ci->children.write[0]; else ci = NULL; } @@ -335,7 +335,7 @@ void SkeletonIK::_validate_property(PropertyInfo &property) const { if (skeleton) { - String names; + String names("--,"); for (int i = 0; i < skeleton->get_bone_count(); i++) { if (i > 0) names += ","; diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h index b9628c479c..5d48b7be33 100644 --- a/scene/animation/skeleton_ik.h +++ b/scene/animation/skeleton_ik.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -49,7 +49,7 @@ class FabrikInverseKinematic { struct ChainItem { - Vector<ChainItem> childs; + Vector<ChainItem> children; ChainItem *parent_item; // Bone info diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 3521782417..c70e58564f 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,10 +34,14 @@ void Tween::_add_pending_command(StringName p_key, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8, const Variant &p_arg9, const Variant &p_arg10) { + // Add a new pending command and reference it pending_commands.push_back(PendingCommand()); PendingCommand &cmd = pending_commands.back()->get(); + // Update the command with the target key cmd.key = p_key; + + // Determine command argument count int &count = cmd.args; if (p_arg10.get_type() != Variant::NIL) count = 10; @@ -59,6 +63,9 @@ void Tween::_add_pending_command(StringName p_key, const Variant &p_arg1, const count = 2; else if (p_arg1.get_type() != Variant::NIL) count = 1; + + // Add the specified arguments to the command + // TODO: Make this a switch statement? if (count > 0) cmd.arg[0] = p_arg1; if (count > 1) @@ -83,10 +90,14 @@ void Tween::_add_pending_command(StringName p_key, const Variant &p_arg1, const void Tween::_process_pending_commands() { + // For each pending command... for (List<PendingCommand>::Element *E = pending_commands.front(); E; E = E->next()) { + // Get the command PendingCommand &cmd = E->get(); Variant::CallError err; + + // Grab all of the arguments for the command Variant *arg[10] = { &cmd.arg[0], &cmd.arg[1], @@ -99,16 +110,20 @@ void Tween::_process_pending_commands() { &cmd.arg[8], &cmd.arg[9], }; + + // Execute the command (and retrieve any errors) this->call(cmd.key, (const Variant **)arg, cmd.args, err); } + + // Clear the pending commands pending_commands.clear(); } bool Tween::_set(const StringName &p_name, const Variant &p_value) { + // Set the correct attribute based on the given name String name = p_name; - - if (name == "playback/speed" || name == "speed") { //bw compatibility + if (name == "playback/speed" || name == "speed") { // Backwards compatibility set_speed_scale(p_value); } else if (name == "playback/active") { @@ -122,69 +137,78 @@ bool Tween::_set(const StringName &p_name, const Variant &p_value) { bool Tween::_get(const StringName &p_name, Variant &r_ret) const { + // Get the correct attribute based on the given name String name = p_name; - - if (name == "playback/speed") { //bw compatibility - + if (name == "playback/speed") { // Backwards compatibility r_ret = speed_scale; - } else if (name == "playback/active") { + } else if (name == "playback/active") { r_ret = is_active(); - } else if (name == "playback/repeat") { + } else if (name == "playback/repeat") { r_ret = is_repeat(); } - return true; } void Tween::_get_property_list(List<PropertyInfo> *p_list) const { - + // Add the property info for the Tween object p_list->push_back(PropertyInfo(Variant::BOOL, "playback/active", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::BOOL, "playback/repeat", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::REAL, "playback/speed", PROPERTY_HINT_RANGE, "-64,64,0.01")); } void Tween::_notification(int p_what) { - + // What notification did we receive? switch (p_what) { case NOTIFICATION_ENTER_TREE: { - + // Are we not already active? if (!is_active()) { - //make sure that a previous process state was not saved - //only process if "processing" is set + // Make sure that a previous process state was not saved + // Only process if "processing" is set set_physics_process_internal(false); set_process_internal(false); } } break; - case NOTIFICATION_READY: { + case NOTIFICATION_READY: { + // Do nothing } break; + case NOTIFICATION_INTERNAL_PROCESS: { + // Are we processing during physics time? if (tween_process_mode == TWEEN_PROCESS_PHYSICS) + // Do nothing since we aren't aligned with physics when we should be break; + // Should we update? if (is_active()) + // Update the tweens _tween_process(get_process_delta_time()); } break; - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + // Are we processing during 'regular' time? if (tween_process_mode == TWEEN_PROCESS_IDLE) + // Do nothing since we whould only process during idle time break; + // Should we update? if (is_active()) + // Update the tweens _tween_process(get_physics_process_delta_time()); } break; - case NOTIFICATION_EXIT_TREE: { + case NOTIFICATION_EXIT_TREE: { + // We've left the tree. Stop all tweens stop_all(); } break; } } void Tween::_bind_methods() { - + // Bind getters and setters ClassDB::bind_method(D_METHOD("is_active"), &Tween::is_active); ClassDB::bind_method(D_METHOD("set_active", "active"), &Tween::set_active); @@ -197,6 +221,7 @@ void Tween::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tween_process_mode", "mode"), &Tween::set_tween_process_mode); ClassDB::bind_method(D_METHOD("get_tween_process_mode"), &Tween::get_tween_process_mode); + // Bind the various Tween control methods ClassDB::bind_method(D_METHOD("start"), &Tween::start); ClassDB::bind_method(D_METHOD("reset", "object", "key"), &Tween::reset, DEFVAL("")); ClassDB::bind_method(D_METHOD("reset_all"), &Tween::reset_all); @@ -211,6 +236,7 @@ void Tween::_bind_methods() { ClassDB::bind_method(D_METHOD("tell"), &Tween::tell); ClassDB::bind_method(D_METHOD("get_runtime"), &Tween::get_runtime); + // Bind interpolation and follow methods ClassDB::bind_method(D_METHOD("interpolate_property", "object", "property", "initial_val", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::interpolate_property, DEFVAL(0)); ClassDB::bind_method(D_METHOD("interpolate_method", "object", "method", "initial_val", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::interpolate_method, DEFVAL(0)); ClassDB::bind_method(D_METHOD("interpolate_callback", "object", "duration", "callback", "arg1", "arg2", "arg3", "arg4", "arg5"), &Tween::interpolate_callback, DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant())); @@ -220,17 +246,22 @@ void Tween::_bind_methods() { ClassDB::bind_method(D_METHOD("targeting_property", "object", "property", "initial", "initial_val", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::targeting_property, DEFVAL(0)); ClassDB::bind_method(D_METHOD("targeting_method", "object", "method", "initial", "initial_method", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::targeting_method, DEFVAL(0)); + // Add the Tween signals ADD_SIGNAL(MethodInfo("tween_started", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"))); ADD_SIGNAL(MethodInfo("tween_step", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"), PropertyInfo(Variant::REAL, "elapsed"), PropertyInfo(Variant::OBJECT, "value"))); ADD_SIGNAL(MethodInfo("tween_completed", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"))); + ADD_SIGNAL(MethodInfo("tween_all_completed")); + // Add the properties and tie them to the getters and setters ADD_PROPERTY(PropertyInfo(Variant::BOOL, "repeat"), "set_repeat", "is_repeat"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_tween_process_mode", "get_tween_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale"); + // Bind Idle vs Physics process BIND_ENUM_CONSTANT(TWEEN_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(TWEEN_PROCESS_IDLE); + // Bind the Transition type constants BIND_ENUM_CONSTANT(TRANS_LINEAR); BIND_ENUM_CONSTANT(TRANS_SINE); BIND_ENUM_CONSTANT(TRANS_QUINT); @@ -243,6 +274,7 @@ void Tween::_bind_methods() { BIND_ENUM_CONSTANT(TRANS_BOUNCE); BIND_ENUM_CONSTANT(TRANS_BACK); + // Bind the easing constants BIND_ENUM_CONSTANT(EASE_IN); BIND_ENUM_CONSTANT(EASE_OUT); BIND_ENUM_CONSTANT(EASE_IN_OUT); @@ -251,27 +283,30 @@ void Tween::_bind_methods() { Variant &Tween::_get_initial_val(InterpolateData &p_data) { + // What type of data are we interpolating? switch (p_data.type) { case INTER_PROPERTY: case INTER_METHOD: case FOLLOW_PROPERTY: case FOLLOW_METHOD: + // Simply use the given initial value return p_data.initial_val; case TARGETING_PROPERTY: case TARGETING_METHOD: { - + // Get the object that is being targeted Object *object = ObjectDB::get_instance(p_data.target_id); ERR_FAIL_COND_V(object == NULL, p_data.initial_val); + // Are we targeting a property or a method? static Variant initial_val; if (p_data.type == TARGETING_PROPERTY) { - + // Get the property from the target object bool valid = false; initial_val = object->get_indexed(p_data.target_key, &valid); ERR_FAIL_COND_V(!valid, p_data.initial_val); } else { - + // Call the method and get the initial value from it Variant::CallError error; initial_val = object->call(p_data.target_key[0], NULL, 0, error); ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, p_data.initial_val); @@ -280,64 +315,75 @@ Variant &Tween::_get_initial_val(InterpolateData &p_data) { } case INTER_CALLBACK: + // Callback does not have a special initial value break; } + // If we've made it here, just return the delta value as the initial value return p_data.delta_val; } Variant &Tween::_get_delta_val(InterpolateData &p_data) { + // What kind of data are we interpolating? switch (p_data.type) { case INTER_PROPERTY: case INTER_METHOD: + // Simply return the given delta value return p_data.delta_val; case FOLLOW_PROPERTY: case FOLLOW_METHOD: { - + // We're following an object, so grab that instance Object *target = ObjectDB::get_instance(p_data.target_id); ERR_FAIL_COND_V(target == NULL, p_data.initial_val); + // We want to figure out the final value Variant final_val; - if (p_data.type == FOLLOW_PROPERTY) { - + // Read the property as-is bool valid = false; final_val = target->get_indexed(p_data.target_key, &valid); ERR_FAIL_COND_V(!valid, p_data.initial_val); } else { - + // We're looking at a method. Call the method on the target object Variant::CallError error; final_val = target->call(p_data.target_key[0], NULL, 0, error); ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, p_data.initial_val); } - // convert INT to REAL is better for interpolaters + // If we're looking at an INT value, instead convert it to a REAL + // This is better for interpolation if (final_val.get_type() == Variant::INT) final_val = final_val.operator real_t(); + + // Calculate the delta based on the initial value and the final value _calc_delta_val(p_data.initial_val, final_val, p_data.delta_val); return p_data.delta_val; } case TARGETING_PROPERTY: case TARGETING_METHOD: { - + // Grab the initial value from the data to calculate delta Variant initial_val = _get_initial_val(p_data); - // convert INT to REAL is better for interpolaters + + // If we're looking at an INT value, instead convert it to a REAL + // This is better for interpolation if (initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t(); - //_calc_delta_val(p_data.initial_val, p_data.final_val, p_data.delta_val); + // Calculate the delta based on the initial value and the final value _calc_delta_val(initial_val, p_data.final_val, p_data.delta_val); return p_data.delta_val; } case INTER_CALLBACK: + // Callbacks have no special delta break; } + // If we've made it here, use the initial value as the delta return p_data.initial_val; } Variant Tween::_run_equation(InterpolateData &p_data) { - + // Get the initial and delta values from the data Variant &initial_val = _get_initial_val(p_data); Variant &delta_val = _get_delta_val(p_data); Variant result; @@ -345,48 +391,59 @@ Variant Tween::_run_equation(InterpolateData &p_data) { #define APPLY_EQUATION(element) \ r.element = _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, i.element, d.element, p_data.duration); + // What type of data are we interpolating? switch (initial_val.get_type()) { case Variant::BOOL: + // Run the boolean specific equation (checking if it is at least 0.5) result = (_run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, initial_val, delta_val, p_data.duration)) >= 0.5; break; case Variant::INT: + // Run the integer specific equation result = (int)_run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int)initial_val, (int)delta_val, p_data.duration); break; case Variant::REAL: + // Run the REAL specific equation result = _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (real_t)initial_val, (real_t)delta_val, p_data.duration); break; case Variant::VECTOR2: { + // Get vectors for initial and delta values Vector2 i = initial_val; Vector2 d = delta_val; Vector2 r; + // Execute the equation and mutate the r vector + // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(x); APPLY_EQUATION(y); - result = r; } break; case Variant::VECTOR3: { + // Get vectors for initial and delta values Vector3 i = initial_val; Vector3 d = delta_val; Vector3 r; + // Execute the equation and mutate the r vector + // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(x); APPLY_EQUATION(y); APPLY_EQUATION(z); - result = r; } break; case Variant::BASIS: { + // Get the basis for initial and delta values Basis i = initial_val; Basis d = delta_val; Basis r; + // Execute the equation on all the basis and mutate the r basis + // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(elements[0][0]); APPLY_EQUATION(elements[0][1]); APPLY_EQUATION(elements[0][2]); @@ -396,55 +453,63 @@ Variant Tween::_run_equation(InterpolateData &p_data) { APPLY_EQUATION(elements[2][0]); APPLY_EQUATION(elements[2][1]); APPLY_EQUATION(elements[2][2]); - result = r; } break; case Variant::TRANSFORM2D: { + // Get the transforms for initial and delta values Transform2D i = initial_val; Transform2D d = delta_val; Transform2D r; + // Execute the equation on the transforms and mutate the r transform + // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(elements[0][0]); APPLY_EQUATION(elements[0][1]); APPLY_EQUATION(elements[1][0]); APPLY_EQUATION(elements[1][1]); APPLY_EQUATION(elements[2][0]); APPLY_EQUATION(elements[2][1]); - result = r; } break; case Variant::QUAT: { + // Get the quaternian for the initial and delta values Quat i = initial_val; Quat d = delta_val; Quat r; + // Execute the equation on the quaternian values and mutate the r quaternian + // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(x); APPLY_EQUATION(y); APPLY_EQUATION(z); APPLY_EQUATION(w); - result = r; } break; case Variant::AABB: { + // Get the AABB's for the initial and delta values AABB i = initial_val; AABB d = delta_val; AABB r; + // Execute the equation for the position and size of the AABB's and mutate the r AABB + // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(position.x); APPLY_EQUATION(position.y); APPLY_EQUATION(position.z); APPLY_EQUATION(size.x); APPLY_EQUATION(size.y); APPLY_EQUATION(size.z); - result = r; } break; case Variant::TRANSFORM: { + // Get the transforms for the initial and delta values Transform i = initial_val; Transform d = delta_val; Transform r; + // Execute the equation for each of the transforms and their origin and mutate the r transform + // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(basis.elements[0][0]); APPLY_EQUATION(basis.elements[0][1]); APPLY_EQUATION(basis.elements[0][2]); @@ -457,40 +522,45 @@ Variant Tween::_run_equation(InterpolateData &p_data) { APPLY_EQUATION(origin.x); APPLY_EQUATION(origin.y); APPLY_EQUATION(origin.z); - result = r; } break; case Variant::COLOR: { + // Get the Color for initial and delta value Color i = initial_val; Color d = delta_val; Color r; + // Apply the equation on the Color RGBA, and mutate the r color + // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(r); APPLY_EQUATION(g); APPLY_EQUATION(b); APPLY_EQUATION(a); - result = r; } break; default: { + // If unknown, just return the initial value result = initial_val; } break; }; #undef APPLY_EQUATION - + // Return the result that was computed return result; } bool Tween::_apply_tween_value(InterpolateData &p_data, Variant &value) { + // Get the object we want to apply the new value to Object *object = ObjectDB::get_instance(p_data.id); ERR_FAIL_COND_V(object == NULL, false); + // What kind of data are we mutating? switch (p_data.type) { case INTER_PROPERTY: case FOLLOW_PROPERTY: case TARGETING_PROPERTY: { + // Simply set the property on the object bool valid = false; object->set_indexed(p_data.key, value, &valid); return valid; @@ -499,85 +569,112 @@ bool Tween::_apply_tween_value(InterpolateData &p_data, Variant &value) { case INTER_METHOD: case FOLLOW_METHOD: case TARGETING_METHOD: { + // We want to call the method on the target object Variant::CallError error; + + // Do we have a non-nil value passed in? if (value.get_type() != Variant::NIL) { + // Pass it as an argument to the function call Variant *arg[1] = { &value }; object->call(p_data.key[0], (const Variant **)arg, 1, error); } else { + // Don't pass any argument object->call(p_data.key[0], NULL, 0, error); } + // Did we get an error from the function call? if (error.error == Variant::CallError::CALL_OK) return true; return false; } case INTER_CALLBACK: + // Nothing to apply for a callback break; }; + // No issues found! return true; } void Tween::_tween_process(float p_delta) { - + // Process all of the pending commands _process_pending_commands(); + // If the scale is 0, make no progress on the tweens if (speed_scale == 0) return; - p_delta *= speed_scale; + // Update the delta and whether we are pending an update + p_delta *= speed_scale; pending_update++; - // if repeat and all interpolates was finished then reset all interpolates - bool all_finished = true; - if (repeat) { + // Are we repeating the interpolations? + if (repeat) { + // For each interpolation... + bool repeats_finished = true; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Get the data from it InterpolateData &data = E->get(); + // Is not finished? if (!data.finish) { - all_finished = false; + // We aren't finished yet, no need to check the rest + repeats_finished = false; break; } } - if (all_finished) + // If we are all finished, we can reset all of the tweens + if (repeats_finished) reset_all(); } - all_finished = true; + // Are all of the tweens complete? + bool all_finished = true; + + // For each tween we wish to interpolate... for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { + // Get the data from it InterpolateData &data = E->get(); + + // Track if we hit one that isn't finished yet all_finished = all_finished && data.finish; + // Is the data not active or already finished? No need to go any further if (!data.active || data.finish) continue; + // Get the target object for this interpolation Object *object = ObjectDB::get_instance(data.id); if (object == NULL) continue; + // Are we still delaying this tween? bool prev_delaying = data.elapsed <= data.delay; data.elapsed += p_delta; if (data.elapsed < data.delay) continue; else if (prev_delaying) { - + // We can apply the tween's value to the data and emit that the tween has started _apply_tween_value(data, data.initial_val); emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false)); } + // Are we at the end of the tween? if (data.elapsed > (data.delay + data.duration)) { - + // Set the elapsed time to the end and mark this one as finished data.elapsed = data.delay + data.duration; data.finish = true; } + // Are we interpolating a callback? if (data.type == INTER_CALLBACK) { + // Is the tween completed? if (data.finish) { + // Are we calling this callback deferred or immediately? if (data.call_deferred) { - + // Run the deferred function callback, applying the correct number of arguments switch (data.args) { case 0: object->call_deferred(data.key[0]); @@ -599,6 +696,7 @@ void Tween::_tween_process(float p_delta) { break; } } else { + // Call the function directly with the arguments Variant::CallError error; Variant *arg[5] = { &data.arg[0], @@ -611,98 +709,111 @@ void Tween::_tween_process(float p_delta) { } } } else { + // We can apply the value directly Variant result = _run_equation(data); _apply_tween_value(data, result); + + // Emit that the tween has taken a step emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result); } + // Is the tween now finished? if (data.finish) { + // Set it to the final value directly _apply_tween_value(data, data.final_val); + + // Mark the tween as completed and emit the signal data.elapsed = 0; emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false)); - // not repeat mode, remove completed action + + // If we are not repeating the tween, remove it if (!repeat) call_deferred("_remove_by_uid", data.uid); - } else if (!repeat) + } else if (!repeat) { + // Check whether all tweens are finished all_finished = all_finished && data.finish; + } } + // One less update left to go pending_update--; - if (all_finished) + // If all tweens are completed, we no longer need to be active + if (all_finished) { set_active(false); + emit_signal("tween_all_completed"); + } } void Tween::set_tween_process_mode(TweenProcessMode p_mode) { - tween_process_mode = p_mode; } Tween::TweenProcessMode Tween::get_tween_process_mode() const { - return tween_process_mode; } bool Tween::is_active() const { - return is_processing_internal() || is_physics_processing_internal(); } void Tween::set_active(bool p_active) { - + // Do nothing if it's the same active mode that we currently are if (is_active() == p_active) return; + // Depending on physics or idle, set processing switch (tween_process_mode) { - case TWEEN_PROCESS_IDLE: set_process_internal(p_active); break; case TWEEN_PROCESS_PHYSICS: set_physics_process_internal(p_active); break; } } bool Tween::is_repeat() const { - return repeat; } void Tween::set_repeat(bool p_repeat) { - repeat = p_repeat; } void Tween::set_speed_scale(float p_speed) { - speed_scale = p_speed; } float Tween::get_speed_scale() const { - return speed_scale; } bool Tween::start() { + // Are there any pending updates? if (pending_update != 0) { + // Start the tweens after deferring call_deferred("start"); return true; } + // We want to be activated set_active(true); return true; } bool Tween::reset(Object *p_object, StringName p_key) { - + // Find all interpolations that use the same object and target string pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Get the target object InterpolateData &data = E->get(); Object *object = ObjectDB::get_instance(data.id); if (object == NULL) continue; + // Do we have the correct object and key? if (object == p_object && (data.concatenated_key == p_key || p_key == "")) { - + // Reset the tween to the initial state data.elapsed = 0; data.finish = false; + + // Also apply the initial state if there isn't a delay if (data.delay == 0) _apply_tween_value(data, data.initial_val); } @@ -712,13 +823,15 @@ bool Tween::reset(Object *p_object, StringName p_key) { } bool Tween::reset_all() { - + // Go through all interpolations pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Get the target data and set it back to the initial state InterpolateData &data = E->get(); data.elapsed = 0; data.finish = false; + + // If there isn't a delay, apply the value to the object if (data.delay == 0) _apply_tween_value(data, data.initial_val); } @@ -727,15 +840,19 @@ bool Tween::reset_all() { } bool Tween::stop(Object *p_object, StringName p_key) { - + // Find the tween that has the given target object and string key pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { + // Get the object the tween is targeting InterpolateData &data = E->get(); Object *object = ObjectDB::get_instance(data.id); if (object == NULL) continue; + + // Is this the correct object and does it have the given key? if (object == p_object && (data.concatenated_key == p_key || p_key == "")) + // Disable the tween data.active = false; } pending_update--; @@ -743,12 +860,13 @@ bool Tween::stop(Object *p_object, StringName p_key) { } bool Tween::stop_all() { - + // We no longer need to be active since all tweens have been stopped set_active(false); + // For each interpolation... pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Simply set it inactive InterpolateData &data = E->get(); data.active = false; } @@ -757,16 +875,20 @@ bool Tween::stop_all() { } bool Tween::resume(Object *p_object, StringName p_key) { - + // We need to be activated + // TODO: What if no tween is found?? set_active(true); + // Find the tween that uses the given target object and string key pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Grab the object InterpolateData &data = E->get(); Object *object = ObjectDB::get_instance(data.id); if (object == NULL) continue; + + // If the object and string key match, activate it if (object == p_object && (data.concatenated_key == p_key || p_key == "")) data.active = true; } @@ -775,12 +897,14 @@ bool Tween::resume(Object *p_object, StringName p_key) { } bool Tween::resume_all() { - + // Set ourselves active so we can process tweens + // TODO: What if there are no tweens? We get set to active for no reason! set_active(true); + // For each interpolation... pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Simply grab it and set it to active InterpolateData &data = E->get(); data.active = true; } @@ -789,35 +913,46 @@ bool Tween::resume_all() { } bool Tween::remove(Object *p_object, StringName p_key) { + // If we are still updating, call this function again later if (pending_update != 0) { call_deferred("remove", p_object, p_key); return true; } + + // For each interpolation... List<List<InterpolateData>::Element *> for_removal; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Get the target object InterpolateData &data = E->get(); Object *object = ObjectDB::get_instance(data.id); if (object == NULL) continue; + + // If the target object and string key match, queue it for removal if (object == p_object && (data.concatenated_key == p_key || p_key == "")) { for_removal.push_back(E); } } + + // For each interpolation we wish to remove... for (List<List<InterpolateData>::Element *>::Element *E = for_removal.front(); E; E = E->next()) { + // Erase it interpolates.erase(E->get()); } return true; } void Tween::_remove_by_uid(int uid) { + // If we are still updating, call this function again later if (pending_update != 0) { call_deferred("_remove_by_uid", uid); return; } + // Find the interpolation that matches the given UID for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { if (uid == E->get().uid) { + // It matches, erase it and stop looking E->erase(); break; } @@ -826,49 +961,61 @@ void Tween::_remove_by_uid(int uid) { void Tween::_push_interpolate_data(InterpolateData &p_data) { pending_update++; + + // Add the new interpolation p_data.uid = ++uid; interpolates.push_back(p_data); + pending_update--; } bool Tween::remove_all() { - + // If we are still updating, call this function again later if (pending_update != 0) { call_deferred("remove_all"); return true; } + // We no longer need to be active set_active(false); + + // Clear out all interpolations and reset the uid interpolates.clear(); uid = 0; + return true; } bool Tween::seek(real_t p_time) { - + // Go through each interpolation... pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Get the target data InterpolateData &data = E->get(); + // Update the elapsed data to be set to the target time data.elapsed = p_time; - if (data.elapsed < data.delay) { + // Are we at the end? + if (data.elapsed < data.delay) { + // There is still time left to go data.finish = false; continue; } else if (data.elapsed >= (data.delay + data.duration)) { - - data.finish = true; + // We are past the end of it, set the elapsed time to the end and mark as finished data.elapsed = (data.delay + data.duration); + data.finish = true; } else { + // We are not finished with this interpolation yet data.finish = false; } + // If we are a callback, do nothing special if (data.type == INTER_CALLBACK) { continue; } + // Run the equation on the data and apply the value Variant result = _run_equation(data); - _apply_tween_value(data, result); } pending_update--; @@ -876,13 +1023,16 @@ bool Tween::seek(real_t p_time) { } real_t Tween::tell() const { - + // We want to grab the position of the furthest along tween pending_update++; real_t pos = 0; - for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { + // For each interpolation... + for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { + // Get the data and figure out if it's position is further along than the previous ones const InterpolateData &data = E->get(); if (data.elapsed > pos) + // Save it if so pos = data.elapsed; } pending_update--; @@ -890,55 +1040,63 @@ real_t Tween::tell() const { } real_t Tween::get_runtime() const { - + // If the tween isn't moving, it'll last forever if (speed_scale == 0) { return INFINITY; } pending_update++; + + // For each interpolation... real_t runtime = 0; for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - + // Get the tween data and see if it's runtime is greater than the previous tweens const InterpolateData &data = E->get(); real_t t = data.delay + data.duration; if (t > runtime) + // This is the longest running tween runtime = t; } pending_update--; + // Adjust the runtime for the current speed scale return runtime / speed_scale; } bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final_val, Variant &p_delta_val) { + // Get the initial, final, and delta values const Variant &initial_val = p_initial_val; const Variant &final_val = p_final_val; Variant &delta_val = p_delta_val; + // What kind of data are we interpolating? switch (initial_val.get_type()) { case Variant::BOOL: - //delta_val = p_final_val; - delta_val = (int)p_final_val - (int)p_initial_val; - break; - + // We'll treat booleans just like integers case Variant::INT: + // Compute the integer delta delta_val = (int)final_val - (int)initial_val; break; case Variant::REAL: + // Convert to REAL and find the delta delta_val = (real_t)final_val - (real_t)initial_val; break; case Variant::VECTOR2: + // Convert to Vectors and find the delta delta_val = final_val.operator Vector2() - initial_val.operator Vector2(); break; case Variant::VECTOR3: + // Convert to Vectors and find the delta delta_val = final_val.operator Vector3() - initial_val.operator Vector3(); break; case Variant::BASIS: { + // Build a new basis which is the delta between the initial and final values Basis i = initial_val; Basis f = final_val; delta_val = Basis(f.elements[0][0] - i.elements[0][0], @@ -953,6 +1111,7 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final } break; case Variant::TRANSFORM2D: { + // Build a new transform which is the difference between the initial and final values Transform2D i = initial_val; Transform2D f = final_val; Transform2D d = Transform2D(); @@ -964,15 +1123,21 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final d[2][1] = f.elements[2][1] - i.elements[2][1]; delta_val = d; } break; + case Variant::QUAT: + // Convert to quaternianls and find the delta delta_val = final_val.operator Quat() - initial_val.operator Quat(); break; + case Variant::AABB: { + // Build a new AABB and use the new position and sizes to make a delta AABB i = initial_val; AABB f = final_val; delta_val = AABB(f.position - i.position, f.size - i.size); } break; + case Variant::TRANSFORM: { + // Build a new transform which is the difference between the initial and final values Transform i = initial_val; Transform f = final_val; Transform d; @@ -991,124 +1156,157 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final delta_val = d; } break; + case Variant::COLOR: { + // Make a new color which is the difference between each the color's RGBA attributes Color i = initial_val; Color f = final_val; delta_val = Color(f.r - i.r, f.g - i.g, f.b - i.b, f.a - i.a); } break; default: + // TODO: Should move away from a 'magic string'? ERR_PRINT("Invalid param type, except(int/real/vector2/vector/matrix/matrix32/quat/aabb/transform/color)"); return false; }; return true; } -bool Tween::interpolate_property(Object *p_object, NodePath p_property, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - if (pending_update != 0) { - _add_pending_command("interpolate_property", p_object, p_property, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); - return true; - } - p_property = p_property.get_as_property_path(); - - if (p_initial_val.get_type() == Variant::NIL) p_initial_val = p_object->get_indexed(p_property.get_subnames()); - - // convert INT to REAL is better for interpolaters - if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); - if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - - ERR_FAIL_COND_V(p_object == NULL, false); - ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); - ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false); - ERR_FAIL_COND_V(p_duration <= 0, false); - ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); - ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); - ERR_FAIL_COND_V(p_delay < 0, false); +bool Tween::_build_interpolation(InterpolateType p_interpolation_type, Object *p_object, NodePath *p_property, StringName *p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - bool prop_valid = false; - p_object->get_indexed(p_property.get_subnames(), &prop_valid); - ERR_FAIL_COND_V(!prop_valid, false); + // TODO: Add initialization+implementation for remaining interpolation types + // TODO: Fix this method's organization to take advantage of the type + // Make a new interpolation data InterpolateData data; data.active = true; - data.type = INTER_PROPERTY; + data.type = p_interpolation_type; data.finish = false; data.elapsed = 0; + // Validate and apply interpolation data + + // Give it the object + ERR_EXPLAIN("Invalid object provided to Tween!"); + ERR_FAIL_COND_V(p_object == NULL, false); // Is the object real + ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); // Is the object a valid instance? data.id = p_object->get_instance_id(); - data.key = p_property.get_subnames(); - data.concatenated_key = p_property.get_concatenated_subnames(); + + // Validate the initial and final values + ERR_EXPLAIN("Initial value type does not match final value type!"); // TODO: Print both types to make debugging easier + ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false); // Do the initial and final value types match? data.initial_val = p_initial_val; data.final_val = p_final_val; + + // Check the Duration + ERR_EXPLAIN("Only non-negative duration values allowed in Tweens!"); + ERR_FAIL_COND_V(p_duration < 0, false); // Is the tween duration non-negative data.duration = p_duration; + + // Tween Delay + ERR_EXPLAIN("Only non-negative delay values allowed in Tweens!"); + ERR_FAIL_COND_V(p_delay < 0, false); // Is the delay non-negative? + data.delay = p_delay; + + // Transition type + ERR_EXPLAIN("Invalid transition type provided to Tween"); + ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); // Is the transition type valid data.trans_type = p_trans_type; + + // Easing type + ERR_EXPLAIN("Invalid easing type provided to Tween"); + ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); // Is the easing type valid data.ease_type = p_ease_type; - data.delay = p_delay; + // Is the property defined? + if (p_property) { + // Check that the object actually contains the given property + bool prop_valid = false; + p_object->get_indexed(p_property->get_subnames(), &prop_valid); + ERR_EXPLAIN("Tween target object has no property named: " + p_property->get_concatenated_subnames()); + ERR_FAIL_COND_V(!prop_valid, false); + + data.key = p_property->get_subnames(); + data.concatenated_key = p_property->get_concatenated_subnames(); + } + + // Is the method defined? + if (p_method) { + // Does the object even have the requested method? + ERR_EXPLAIN("Tween target object has no method named: " + *p_method); // TODO: Fix this error message + ERR_FAIL_COND_V(!p_object->has_method(*p_method), false); + + data.key.push_back(*p_method); + data.concatenated_key = *p_method; + } + + // Is there not a valid delta? if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) return false; + // Add this interpolation to the total _push_interpolate_data(data); return true; } -bool Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { +bool Tween::interpolate_property(Object *p_object, NodePath p_property, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { + // If we are busy updating, call this function again later if (pending_update != 0) { - _add_pending_command("interpolate_method", p_object, p_method, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); + _add_pending_command("interpolate_property", p_object, p_property, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); return true; } - // convert INT to REAL is better for interpolaters - if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); - if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_object == NULL, false); - ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); - ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false); - ERR_FAIL_COND_V(p_duration <= 0, false); - ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); - ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); - ERR_FAIL_COND_V(p_delay < 0, false); + // Get the property from the node path + p_property = p_property.get_as_property_path(); - ERR_EXPLAIN("Object has no method named: %s" + p_method); - ERR_FAIL_COND_V(!p_object->has_method(p_method), false); + // If no initial value given, grab the initial value from the object + // TODO: Is this documented? This is very useful and removes a lot of clutter from tweens! + if (p_initial_val.get_type() == Variant::NIL) p_initial_val = p_object->get_indexed(p_property.get_subnames()); - InterpolateData data; - data.active = true; - data.type = INTER_METHOD; - data.finish = false; - data.elapsed = 0; + // Convert any integers into REALs as they are better for interpolation + if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); + if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - data.id = p_object->get_instance_id(); - data.key.push_back(p_method); - data.concatenated_key = p_method; - data.initial_val = p_initial_val; - data.final_val = p_final_val; - data.duration = p_duration; - data.trans_type = p_trans_type; - data.ease_type = p_ease_type; - data.delay = p_delay; + // Build the interpolation data + bool result = _build_interpolation(INTER_PROPERTY, p_object, &p_property, NULL, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); + return result; +} - if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) - return false; +bool Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { + // If we are busy updating, call this function again later + if (pending_update != 0) { + _add_pending_command("interpolate_method", p_object, p_method, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); + return true; + } - _push_interpolate_data(data); - return true; + // Convert any integers into REALs as they are better for interpolation + if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); + if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); + + // Build the interpolation data + bool result = _build_interpolation(INTER_METHOD, p_object, NULL, &p_method, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); + return result; } bool Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE) { - + // If we are already updating, call this function again later if (pending_update != 0) { _add_pending_command("interpolate_callback", p_object, p_duration, p_callback, p_arg1, p_arg2, p_arg3, p_arg4, p_arg5); return true; } + // Check that the target object is valid ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); + + // Duration cannot be negative ERR_FAIL_COND_V(p_duration < 0, false); + // Check whether the object even has the callback ERR_EXPLAIN("Object has no callback named: %s" + p_callback); ERR_FAIL_COND_V(!p_object->has_method(p_callback), false); + // Build a new InterpolationData InterpolateData data; data.active = true; data.type = INTER_CALLBACK; @@ -1116,12 +1314,14 @@ bool Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_c data.call_deferred = false; data.elapsed = 0; + // Give the data it's configuration data.id = p_object->get_instance_id(); data.key.push_back(p_callback); data.concatenated_key = p_callback; data.duration = p_duration; data.delay = 0; + // Add arguments to the interpolation int args = 0; if (p_arg5.get_type() != Variant::NIL) args = 5; @@ -1143,23 +1343,30 @@ bool Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_c data.arg[3] = p_arg4; data.arg[4] = p_arg5; + // Add the new interpolation _push_interpolate_data(data); return true; } bool Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE) { - + // If we are already updating, call this function again later if (pending_update != 0) { _add_pending_command("interpolate_deferred_callback", p_object, p_duration, p_callback, p_arg1, p_arg2, p_arg3, p_arg4, p_arg5); return true; } + + // Check that the target object is valid ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); + + // No negative durations allowed ERR_FAIL_COND_V(p_duration < 0, false); + // Confirm the callback exists on the object ERR_EXPLAIN("Object has no callback named: %s" + p_callback); ERR_FAIL_COND_V(!p_object->has_method(p_callback), false); + // Create a new InterpolateData for the callback InterpolateData data; data.active = true; data.type = INTER_CALLBACK; @@ -1167,12 +1374,14 @@ bool Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, S data.call_deferred = true; data.elapsed = 0; + // Give the data it's configuration data.id = p_object->get_instance_id(); data.key.push_back(p_callback); data.concatenated_key = p_callback; data.duration = p_duration; data.delay = 0; + // Collect arguments for the callback int args = 0; if (p_arg5.get_type() != Variant::NIL) args = 5; @@ -1194,32 +1403,46 @@ bool Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, S data.arg[3] = p_arg4; data.arg[4] = p_arg5; + // Add the new interpolation _push_interpolate_data(data); return true; } bool Tween::follow_property(Object *p_object, NodePath p_property, Variant p_initial_val, Object *p_target, NodePath p_target_property, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { + // If we are already updating, call this function again later if (pending_update != 0) { _add_pending_command("follow_property", p_object, p_property, p_initial_val, p_target, p_target_property, p_duration, p_trans_type, p_ease_type, p_delay); return true; } + + // Get the two properties from their paths p_property = p_property.get_as_property_path(); p_target_property = p_target_property.get_as_property_path(); + // If no initial value is given, grab it from the source object + // TODO: Is this documented? It's really helpful for decluttering tweens if (p_initial_val.get_type() == Variant::NIL) p_initial_val = p_object->get_indexed(p_property.get_subnames()); - // convert INT to REAL is better for interpolaters + // Convert initial INT values to REAL as they are better for interpolation if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); + // Confirm the source and target objects are valid ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); ERR_FAIL_COND_V(p_target == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_target), false); - ERR_FAIL_COND_V(p_duration <= 0, false); + + // No negative durations + ERR_FAIL_COND_V(p_duration < 0, false); + + // Ensure transition and easing types are valid ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); + + // No negative delays ERR_FAIL_COND_V(p_delay < 0, false); + // Confirm the source and target objects have the desired properties bool prop_valid = false; p_object->get_indexed(p_property.get_subnames(), &prop_valid); ERR_FAIL_COND_V(!prop_valid, false); @@ -1228,16 +1451,20 @@ bool Tween::follow_property(Object *p_object, NodePath p_property, Variant p_ini Variant target_val = p_target->get_indexed(p_target_property.get_subnames(), &target_prop_valid); ERR_FAIL_COND_V(!target_prop_valid, false); - // convert INT to REAL is better for interpolaters + // Convert target INT to REAL since it is better for interpolation if (target_val.get_type() == Variant::INT) target_val = target_val.operator real_t(); + + // Verify that the target value and initial value are the same type ERR_FAIL_COND_V(target_val.get_type() != p_initial_val.get_type(), false); + // Create a new InterpolateData InterpolateData data; data.active = true; data.type = FOLLOW_PROPERTY; data.finish = false; data.elapsed = 0; + // Give the InterpolateData it's configuration data.id = p_object->get_instance_id(); data.key = p_property.get_subnames(); data.concatenated_key = p_property.get_concatenated_subnames(); @@ -1249,46 +1476,59 @@ bool Tween::follow_property(Object *p_object, NodePath p_property, Variant p_ini data.ease_type = p_ease_type; data.delay = p_delay; + // Add the interpolation _push_interpolate_data(data); return true; } bool Tween::follow_method(Object *p_object, StringName p_method, Variant p_initial_val, Object *p_target, StringName p_target_method, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { + // If we are currently updating, call this function again later if (pending_update != 0) { _add_pending_command("follow_method", p_object, p_method, p_initial_val, p_target, p_target_method, p_duration, p_trans_type, p_ease_type, p_delay); return true; } - // convert INT to REAL is better for interpolaters + // Convert initial INT values to REAL as they are better for interpolation if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); + // Verify the source and target objects are valid ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); ERR_FAIL_COND_V(p_target == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_target), false); - ERR_FAIL_COND_V(p_duration <= 0, false); + + // No negative durations + ERR_FAIL_COND_V(p_duration < 0, false); + + // Ensure that the transition and ease types are valid ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); + + // No negative delays ERR_FAIL_COND_V(p_delay < 0, false); + // Confirm both objects have the target methods ERR_EXPLAIN("Object has no method named: %s" + p_method); ERR_FAIL_COND_V(!p_object->has_method(p_method), false); ERR_EXPLAIN("Target has no method named: %s" + p_target_method); ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false); + // Call the method to get the target value Variant::CallError error; Variant target_val = p_target->call(p_target_method, NULL, 0, error); ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, false); - // convert INT to REAL is better for interpolaters + // Convert target INT values to REAL as they are better for interpolation if (target_val.get_type() == Variant::INT) target_val = target_val.operator real_t(); ERR_FAIL_COND_V(target_val.get_type() != p_initial_val.get_type(), false); + // Make the new InterpolateData for the method follow InterpolateData data; data.active = true; data.type = FOLLOW_METHOD; data.finish = false; data.elapsed = 0; + // Give the data it's configuration data.id = p_object->get_instance_id(); data.key.push_back(p_method); data.concatenated_key = p_method; @@ -1300,31 +1540,41 @@ bool Tween::follow_method(Object *p_object, StringName p_method, Variant p_initi data.ease_type = p_ease_type; data.delay = p_delay; + // Add the new interpolation _push_interpolate_data(data); return true; } bool Tween::targeting_property(Object *p_object, NodePath p_property, Object *p_initial, NodePath p_initial_property, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - + // If we are currently updating, call this function again later if (pending_update != 0) { _add_pending_command("targeting_property", p_object, p_property, p_initial, p_initial_property, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); return true; } + // Grab the target property and the target property p_property = p_property.get_as_property_path(); p_initial_property = p_initial_property.get_as_property_path(); - // convert INT to REAL is better for interpolaters + // Convert the initial INT values to REAL as they are better for Interpolation if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); + // Verify both objects are valid ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); ERR_FAIL_COND_V(p_initial == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_initial), false); - ERR_FAIL_COND_V(p_duration <= 0, false); + + // No negative durations + ERR_FAIL_COND_V(p_duration < 0, false); + + // Ensure transition and easing types are valid ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); + + // No negative delays ERR_FAIL_COND_V(p_delay < 0, false); + // Ensure the initial and target properties exist on their objects bool prop_valid = false; p_object->get_indexed(p_property.get_subnames(), &prop_valid); ERR_FAIL_COND_V(!prop_valid, false); @@ -1333,16 +1583,18 @@ bool Tween::targeting_property(Object *p_object, NodePath p_property, Object *p_ Variant initial_val = p_initial->get_indexed(p_initial_property.get_subnames(), &initial_prop_valid); ERR_FAIL_COND_V(!initial_prop_valid, false); - // convert INT to REAL is better for interpolaters + // Convert the initial INT value to REAL as it is better for interpolation if (initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t(); ERR_FAIL_COND_V(initial_val.get_type() != p_final_val.get_type(), false); + // Build the InterpolateData object InterpolateData data; data.active = true; data.type = TARGETING_PROPERTY; data.finish = false; data.elapsed = 0; + // Give the data it's configuration data.id = p_object->get_instance_id(); data.key = p_property.get_subnames(); data.concatenated_key = p_property.get_concatenated_subnames(); @@ -1355,49 +1607,64 @@ bool Tween::targeting_property(Object *p_object, NodePath p_property, Object *p_ data.ease_type = p_ease_type; data.delay = p_delay; + // Ensure there is a valid delta if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) return false; + // Add the interpolation _push_interpolate_data(data); return true; } bool Tween::targeting_method(Object *p_object, StringName p_method, Object *p_initial, StringName p_initial_method, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { + // If we are currently updating, call this function again later if (pending_update != 0) { _add_pending_command("targeting_method", p_object, p_method, p_initial, p_initial_method, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); return true; } - // convert INT to REAL is better for interpolaters + + // Convert final INT values to REAL as they are better for interpolation if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); + // Make sure the given objects are valid ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_object), false); ERR_FAIL_COND_V(p_initial == NULL, false); ERR_FAIL_COND_V(!ObjectDB::instance_validate(p_initial), false); - ERR_FAIL_COND_V(p_duration <= 0, false); + + // No negative durations + ERR_FAIL_COND_V(p_duration < 0, false); + + // Ensure transition and easing types are valid ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); + + // No negative delays ERR_FAIL_COND_V(p_delay < 0, false); + // Make sure both objects have the given method ERR_EXPLAIN("Object has no method named: %s" + p_method); ERR_FAIL_COND_V(!p_object->has_method(p_method), false); ERR_EXPLAIN("Initial Object has no method named: %s" + p_initial_method); ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false); + // Call the method to get the initial value Variant::CallError error; Variant initial_val = p_initial->call(p_initial_method, NULL, 0, error); ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, false); - // convert INT to REAL is better for interpolaters + // Convert initial INT values to REAL as they aer better for interpolation if (initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t(); ERR_FAIL_COND_V(initial_val.get_type() != p_final_val.get_type(), false); + // Build the new InterpolateData object InterpolateData data; data.active = true; data.type = TARGETING_METHOD; data.finish = false; data.elapsed = 0; + // Configure the data data.id = p_object->get_instance_id(); data.key.push_back(p_method); data.concatenated_key = p_method; @@ -1410,16 +1677,17 @@ bool Tween::targeting_method(Object *p_object, StringName p_method, Object *p_in data.ease_type = p_ease_type; data.delay = p_delay; + // Ensure there is a valid delta if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) return false; + // Add the interpolation _push_interpolate_data(data); return true; } Tween::Tween() { - - //String autoplay; + // Initialize tween attributes tween_process_mode = TWEEN_PROCESS_IDLE; repeat = false; speed_scale = 1; diff --git a/scene/animation/tween.h b/scene/animation/tween.h index aa47c00717..64ce099ecd 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -135,6 +135,7 @@ private: void _tween_process(float p_delta); void _remove_by_uid(int uid); void _push_interpolate_data(InterpolateData &p_data); + bool _build_interpolation(InterpolateType p_interpolation_type, Object *p_object, NodePath *p_property, StringName *p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay); protected: bool _set(const StringName &p_name, const Variant &p_value); diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_stream_player.cpp index 1d9d048fe1..2def9fe8fc 100644 --- a/scene/audio/audio_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* audio_player.cpp */ +/* audio_stream_player.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,38 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "audio_player.h" +#include "audio_stream_player.h" #include "core/engine.h" -void AudioStreamPlayer::_mix_internal(bool p_fadeout) { +void AudioStreamPlayer::_mix_to_bus(const AudioFrame *p_frames, int p_amount) { int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus); - //get data - AudioFrame *buffer = mix_buffer.ptrw(); - int buffer_size = mix_buffer.size(); - - if (p_fadeout) { - // Short fadeout ramp - buffer_size = MIN(buffer_size, 128); - } - - stream_playback->mix(buffer, pitch_scale, buffer_size); - - //multiply volume interpolating to avoid clicks if this changes - float target_volume = p_fadeout ? -80.0 : volume_db; - float vol = Math::db2linear(mix_volume_db); - float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size); - - for (int i = 0; i < buffer_size; i++) { - buffer[i] *= vol; - vol += vol_inc; - } - - //set volume for next mix - mix_volume_db = target_volume; - AudioFrame *targets[4] = { NULL, NULL, NULL, NULL }; if (AudioServer::get_singleton()->get_speaker_mode() == AudioServer::SPEAKER_MODE_STEREO) { @@ -83,16 +59,52 @@ void AudioStreamPlayer::_mix_internal(bool p_fadeout) { for (int c = 0; c < 4; c++) { if (!targets[c]) break; - for (int i = 0; i < buffer_size; i++) { - targets[c][i] += buffer[i]; + for (int i = 0; i < p_amount; i++) { + targets[c][i] += p_frames[i]; } } } +void AudioStreamPlayer::_mix_internal(bool p_fadeout) { + + //get data + AudioFrame *buffer = mix_buffer.ptrw(); + int buffer_size = mix_buffer.size(); + + if (p_fadeout) { + // Short fadeout ramp + buffer_size = MIN(buffer_size, 128); + } + + stream_playback->mix(buffer, pitch_scale, buffer_size); + + //multiply volume interpolating to avoid clicks if this changes + float target_volume = p_fadeout ? -80.0 : volume_db; + float vol = Math::db2linear(mix_volume_db); + float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size); + + for (int i = 0; i < buffer_size; i++) { + buffer[i] *= vol; + vol += vol_inc; + } + + //set volume for next mix + mix_volume_db = target_volume; + + _mix_to_bus(buffer, buffer_size); +} + void AudioStreamPlayer::_mix_audio() { - if (!stream_playback.is_valid() || !active) + if (use_fadeout) { + _mix_to_bus(fadeout_buffer.ptr(), fadeout_buffer.size()); + use_fadeout = false; + } + + if (!stream_playback.is_valid() || !active || + (stream_paused && !stream_paused_fade)) { return; + } if (stream_paused) { if (stream_paused_fade) { @@ -102,17 +114,26 @@ void AudioStreamPlayer::_mix_audio() { return; } - if (setseek >= 0.0) { + if (setstop) { + _mix_internal(true); + stream_playback->stop(); + setstop = false; + } + + if (setseek >= 0.0 && !stop_has_priority) { if (stream_playback->is_playing()) { //fade out to avoid pops _mix_internal(true); } + stream_playback->start(setseek); setseek = -1.0; //reset seek mix_volume_db = volume_db; //reset ramp } + stop_has_priority = false; + _mix_internal(false); } @@ -156,6 +177,28 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) { AudioServer::get_singleton()->lock(); + if (active && stream_playback.is_valid() && !stream_paused) { + //changing streams out of the blue is not a great idea, but at least + //lets try to somehow avoid a click + + AudioFrame *buffer = fadeout_buffer.ptrw(); + int buffer_size = fadeout_buffer.size(); + + stream_playback->mix(buffer, pitch_scale, buffer_size); + + //multiply volume interpolating to avoid clicks if this changes + float target_volume = -80.0; + float vol = Math::db2linear(mix_volume_db); + float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size); + + for (int i = 0; i < buffer_size; i++) { + buffer[i] *= vol; + vol += vol_inc; + } + + use_fadeout = true; + } + mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size()); if (stream_playback.is_valid()) { @@ -163,6 +206,7 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) { stream.unref(); active = false; setseek = -1; + setstop = false; } if (p_stream.is_valid()) { @@ -204,6 +248,7 @@ void AudioStreamPlayer::play(float p_from_pos) { if (stream_playback.is_valid()) { //mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks setseek = p_from_pos; + stop_has_priority = false; active = true; set_process_internal(true); } @@ -218,17 +263,16 @@ void AudioStreamPlayer::seek(float p_seconds) { void AudioStreamPlayer::stop() { - if (stream_playback.is_valid()) { - stream_playback->stop(); - active = false; - set_process_internal(false); + if (stream_playback.is_valid() && active) { + setstop = true; + stop_has_priority = true; } } bool AudioStreamPlayer::is_playing() const { if (stream_playback.is_valid()) { - return active; //&& stream_playback->is_playing(); + return active && !setstop; //&& stream_playback->is_playing(); } return false; @@ -325,6 +369,10 @@ void AudioStreamPlayer::_bus_layout_changed() { _change_notify(); } +Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() { + return stream_playback; +} + void AudioStreamPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer::set_stream); @@ -360,6 +408,8 @@ void AudioStreamPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer::set_stream_paused); ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer::get_stream_paused); + ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer::get_stream_playback); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale"); @@ -387,6 +437,9 @@ AudioStreamPlayer::AudioStreamPlayer() { stream_paused = false; stream_paused_fade = false; mix_target = MIX_TARGET_STEREO; + fadeout_buffer.resize(512); + setstop = false; + use_fadeout = false; AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); } diff --git a/scene/audio/audio_player.h b/scene/audio/audio_stream_player.h index 591c00ed18..ab9161c798 100644 --- a/scene/audio/audio_player.h +++ b/scene/audio/audio_stream_player.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* audio_player.h */ +/* audio_stream_player.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIOPLAYER_H -#define AUDIOPLAYER_H +#ifndef AUDIO_STREAM_PLAYER_H +#define AUDIO_STREAM_PLAYER_H #include "scene/main/node.h" #include "servers/audio/audio_stream.h" class AudioStreamPlayer : public Node { - GDCLASS(AudioStreamPlayer, Node) + GDCLASS(AudioStreamPlayer, Node); public: enum MixTarget { @@ -49,9 +49,13 @@ private: Ref<AudioStreamPlayback> stream_playback; Ref<AudioStream> stream; Vector<AudioFrame> mix_buffer; + Vector<AudioFrame> fadeout_buffer; + bool use_fadeout; volatile float setseek; volatile bool active; + volatile bool setstop; + volatile bool stop_has_priority; float mix_volume_db; float pitch_scale; @@ -71,6 +75,7 @@ private: bool _is_active() const; void _bus_layout_changed(); + void _mix_to_bus(const AudioFrame *p_frames, int p_amount); protected: void _validate_property(PropertyInfo &property) const; @@ -105,9 +110,12 @@ public: void set_stream_paused(bool p_pause); bool get_stream_paused() const; + Ref<AudioStreamPlayback> get_stream_playback(); + AudioStreamPlayer(); ~AudioStreamPlayer(); }; VARIANT_ENUM_CAST(AudioStreamPlayer::MixTarget) -#endif // AUDIOPLAYER_H + +#endif // AUDIO_STREAM_PLAYER_H diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index dc85c8e641..52fcea2a71 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -56,185 +56,23 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) { if (status.disabled) // no interaction with disabled button return; - Ref<InputEventMouseButton> b = p_event; + Ref<InputEventMouseButton> mouse_button = p_event; + bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo(); - if (b.is_valid()) { - if (status.disabled || ((1 << (b->get_button_index() - 1)) & button_mask) == 0) - return; - - if (status.pressing_button) - return; - - if (action_mode == ACTION_MODE_BUTTON_PRESS) { - - if (b->is_pressed()) { - - emit_signal("button_down"); - - if (!toggle_mode) { //mouse press attempt - - status.press_attempt = true; - status.pressing_inside = true; - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - emit_signal("pressed"); - _unpress_group(); - - } else { - - status.pressed = !status.pressed; - pressed(); - - emit_signal("pressed"); - _unpress_group(); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } - - } else { - - emit_signal("button_up"); - - /* this is pointless if (status.press_attempt && status.pressing_inside) { - //released(); - emit_signal("released"); - } -*/ - status.press_attempt = false; - } - update(); - return; - } - - if (b->is_pressed()) { - - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - - } else { - - emit_signal("button_up"); - - if (status.press_attempt && status.pressing_inside) { - - if (!toggle_mode) { //mouse press attempt - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - emit_signal("pressed"); - - } else { - - status.pressed = !status.pressed; - - pressed(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } - - _unpress_group(); - } - - status.press_attempt = false; - } - - update(); + bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) > 0; + if (button_masked || ui_accept) { + on_action_event(p_event); + return; } - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - if (status.press_attempt && status.pressing_button == 0) { + Ref<InputEventMouseMotion> mouse_motion = p_event; + if (mouse_motion.is_valid()) { + if (status.press_attempt) { bool last_press_inside = status.pressing_inside; - status.pressing_inside = has_point(mm->get_position()); - if (last_press_inside != status.pressing_inside) + status.pressing_inside = has_point(mouse_motion->get_position()); + if (last_press_inside != status.pressing_inside) { update(); - } - } - - if (!mm.is_valid() && !b.is_valid()) { - - if (p_event->is_echo()) { - return; - } - - if (status.disabled) { - return; - } - - if (status.press_attempt && status.pressing_button == 0) { - return; - } - - if (p_event->is_action("ui_accept")) { - - if (p_event->is_pressed()) { - - status.pressing_button++; - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - - } else if (status.press_attempt) { - - if (status.pressing_button) - status.pressing_button--; - - if (status.pressing_button) - return; - - status.press_attempt = false; - status.pressing_inside = false; - - emit_signal("button_up"); - - if (!toggle_mode) { //mouse press attempt - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - emit_signal("pressed"); - } else { - - status.pressed = !status.pressed; - - pressed(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } - - _unpress_group(); } - - accept_event(); - update(); } } } @@ -255,7 +93,6 @@ void BaseButton::_notification(int p_what) { if (status.press_attempt) { status.press_attempt = false; - status.pressing_button = 0; update(); } } @@ -268,9 +105,8 @@ void BaseButton::_notification(int p_what) { if (p_what == NOTIFICATION_FOCUS_EXIT) { - if (status.pressing_button && status.press_attempt) { + if (status.press_attempt) { status.press_attempt = false; - status.pressing_button = 0; status.hovering = false; update(); } else if (status.hovering) { @@ -282,10 +118,7 @@ void BaseButton::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { } - if (p_what == NOTIFICATION_EXIT_TREE) { - } - - if (p_what == NOTIFICATION_VISIBILITY_CHANGED && !is_visible_in_tree()) { + if (p_what == NOTIFICATION_EXIT_TREE || (p_what == NOTIFICATION_VISIBILITY_CHANGED && !is_visible_in_tree())) { if (!toggle_mode) { status.pressed = false; @@ -293,21 +126,66 @@ void BaseButton::_notification(int p_what) { status.hovering = false; status.press_attempt = false; status.pressing_inside = false; - status.pressing_button = 0; } } -void BaseButton::pressed() { +void BaseButton::_pressed() { - if (get_script_instance()) - get_script_instance()->call("pressed"); + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_pressed); + } + pressed(); + emit_signal("pressed"); } -void BaseButton::toggled(bool p_pressed) { +void BaseButton::_toggled(bool p_pressed) { if (get_script_instance()) { - get_script_instance()->call("toggled", p_pressed); + get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, p_pressed); } + toggled(p_pressed); + emit_signal("toggled", p_pressed); +} + +void BaseButton::on_action_event(Ref<InputEvent> p_event) { + + if (p_event->is_pressed()) { + status.press_attempt = true; + status.pressing_inside = true; + emit_signal("button_down"); + } + + if (status.press_attempt && status.pressing_inside) { + if (toggle_mode) { + if ((p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_PRESS) || (!p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_RELEASE)) { + if (action_mode == ACTION_MODE_BUTTON_PRESS) { + status.press_attempt = false; + status.pressing_inside = false; + } + status.pressed = !status.pressed; + _unpress_group(); + _toggled(status.pressed); + _pressed(); + } + } else { + if (!p_event->is_pressed()) { + _pressed(); + } + } + } + + if (!p_event->is_pressed()) { // pressed state should be correct with button_up signal + emit_signal("button_up"); + status.press_attempt = false; + } + + update(); +} + +void BaseButton::pressed() { +} + +void BaseButton::toggled(bool p_pressed) { } void BaseButton::set_disabled(bool p_disabled) { @@ -321,7 +199,6 @@ void BaseButton::set_disabled(bool p_disabled) { } status.press_attempt = false; status.pressing_inside = false; - status.pressing_button = 0; } update(); _change_notify("disabled"); @@ -344,6 +221,8 @@ void BaseButton::set_pressed(bool p_pressed) { if (p_pressed) { _unpress_group(); } + _toggled(status.pressed); + update(); } @@ -379,7 +258,7 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const { bool pressing; if (status.press_attempt) { - pressing = status.pressing_inside; + pressing = (status.pressing_inside || keep_pressed_outside); if (status.pressed) pressing = !pressing; } else { @@ -449,10 +328,17 @@ Control::FocusMode BaseButton::get_enabled_focus_mode() const { return enabled_focus_mode; } -void BaseButton::set_shortcut(const Ref<ShortCut> &p_shortcut) { +void BaseButton::set_keep_pressed_outside(bool p_on) { - if (shortcut.is_null() == p_shortcut.is_null()) - return; + keep_pressed_outside = p_on; +} + +bool BaseButton::is_keep_pressed_outside() const { + + return keep_pressed_outside; +} + +void BaseButton::set_shortcut(const Ref<ShortCut> &p_shortcut) { shortcut = p_shortcut; set_process_unhandled_input(shortcut.is_valid()); @@ -464,17 +350,12 @@ Ref<ShortCut> BaseButton::get_shortcut() const { void BaseButton::_unhandled_input(Ref<InputEvent> p_event) { - if (!is_disabled() && is_visible_in_tree() && p_event->is_pressed() && !p_event->is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) { + if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) { if (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)) return; //ignore because of modal window - if (is_toggle_mode()) { - set_pressed(!is_pressed()); - emit_signal("toggled", is_pressed()); - } - - emit_signal("pressed"); + on_action_event(p_event); } } @@ -531,6 +412,8 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_draw_mode"), &BaseButton::get_draw_mode); ClassDB::bind_method(D_METHOD("set_enabled_focus_mode", "mode"), &BaseButton::set_enabled_focus_mode); ClassDB::bind_method(D_METHOD("get_enabled_focus_mode"), &BaseButton::get_enabled_focus_mode); + ClassDB::bind_method(D_METHOD("set_keep_pressed_outside", "enabled"), &BaseButton::set_keep_pressed_outside); + ClassDB::bind_method(D_METHOD("is_keep_pressed_outside"), &BaseButton::is_keep_pressed_outside); ClassDB::bind_method(D_METHOD("set_shortcut", "shortcut"), &BaseButton::set_shortcut); ClassDB::bind_method(D_METHOD("get_shortcut"), &BaseButton::get_shortcut); @@ -552,6 +435,7 @@ void BaseButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "action_mode", PROPERTY_HINT_ENUM, "Button Press,Button Release"), "set_action_mode", "get_action_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask"); ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_enabled_focus_mode", "get_enabled_focus_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "ShortCut"), "set_shortcut", "get_shortcut"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group"); @@ -569,12 +453,12 @@ BaseButton::BaseButton() { toggle_mode = false; shortcut_in_tooltip = true; + keep_pressed_outside = false; status.pressed = false; status.press_attempt = false; status.hovering = false; status.pressing_inside = false; status.disabled = false; - status.pressing_button = 0; set_focus_mode(FOCUS_ALL); enabled_focus_mode = FOCUS_ALL; action_mode = ACTION_MODE_BUTTON_RELEASE; diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 272c07f68a..ffccdd69d6 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -52,6 +52,7 @@ private: int button_mask; bool toggle_mode; bool shortcut_in_tooltip; + bool keep_pressed_outside; FocusMode enabled_focus_mode; Ref<ShortCut> shortcut; @@ -64,13 +65,16 @@ private: bool pressing_inside; bool disabled; - int pressing_button; } status; Ref<ButtonGroup> button_group; void _unpress_group(); + void _pressed(); + void _toggled(bool p_pressed); + + void on_action_event(Ref<InputEvent> p_event); protected: virtual void pressed(); @@ -110,6 +114,9 @@ public: void set_action_mode(ActionMode p_mode); ActionMode get_action_mode() const; + void set_keep_pressed_outside(bool p_on); + bool is_keep_pressed_outside() const; + void set_button_mask(int p_mask); int get_button_mask() const; @@ -133,7 +140,7 @@ VARIANT_ENUM_CAST(BaseButton::ActionMode) class ButtonGroup : public Resource { - GDCLASS(ButtonGroup, Resource) + GDCLASS(ButtonGroup, Resource); friend class BaseButton; Set<BaseButton *> buttons; diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index 12b9fe7c03..cc37d4cf7d 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -255,6 +255,10 @@ void BoxContainer::_notification(int p_what) { _resort(); } break; + case NOTIFICATION_THEME_CHANGED: { + + minimum_size_changed(); + } break; } } diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h index abc228f804..89924f7fcb 100644 --- a/scene/gui/box_container.h +++ b/scene/gui/box_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 621153b6de..65e9cccd05 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "button.h" + #include "core/translation.h" #include "servers/visual_server.h" @@ -102,6 +103,7 @@ void Button::_notification(int p_what) { break; } + FALLTHROUGH; } case DRAW_PRESSED: { @@ -140,8 +142,8 @@ void Button::_notification(int p_what) { if (has_focus()) { - Ref<StyleBox> style = get_stylebox("focus"); - style->draw(ci, Rect2(Point2(), size)); + Ref<StyleBox> style2 = get_stylebox("focus"); + style2->draw(ci, Rect2(Point2(), size)); } Ref<Font> font = get_font("font"); diff --git a/scene/gui/button.h b/scene/gui/button.h index 0b41b14f02..6ba3475e5a 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp index cf71f89830..7c842999d1 100644 --- a/scene/gui/center_container.cpp +++ b/scene/gui/center_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/center_container.h b/scene/gui/center_container.h index 519e1493ec..9c9f61388c 100644 --- a/scene/gui/center_container.h +++ b/scene/gui/center_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index 0790f87ea7..1d8b74d9db 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h index 8375b46ca0..adfb12e7a1 100644 --- a/scene/gui/check_box.h +++ b/scene/gui/check_box.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index fa9538da28..a2d0f388c4 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,13 +34,15 @@ #include "servers/visual_server.h" Size2 CheckButton::get_icon_size() const { - Ref<Texture> on = Control::get_icon("on"); - Ref<Texture> off = Control::get_icon("off"); + + Ref<Texture> on = Control::get_icon(is_disabled() ? "on_disabled" : "on"); + Ref<Texture> off = Control::get_icon(is_disabled() ? "off_disabled" : "off"); Size2 tex_size = Size2(0, 0); if (!on.is_null()) tex_size = Size2(on->get_width(), on->get_height()); if (!off.is_null()) tex_size = Size2(MAX(tex_size.width, off->get_width()), MAX(tex_size.height, off->get_height())); + return tex_size; } @@ -49,9 +51,8 @@ Size2 CheckButton::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); Size2 tex_size = get_icon_size(); minsize.width += tex_size.width; - if (get_text().length() > 0) { + if (get_text().length() > 0) minsize.width += get_constant("hseparation"); - } Ref<StyleBox> sb = get_stylebox("normal"); minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM)); @@ -67,8 +68,8 @@ void CheckButton::_notification(int p_what) { RID ci = get_canvas_item(); - Ref<Texture> on = Control::get_icon("on"); - Ref<Texture> off = Control::get_icon("off"); + Ref<Texture> on = Control::get_icon(is_disabled() ? "on_disabled" : "on"); + Ref<Texture> off = Control::get_icon(is_disabled() ? "off_disabled" : "off"); Ref<StyleBox> sb = get_stylebox("normal"); Vector2 ofs; diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h index a11749e3f6..13b0dbc194 100644 --- a/scene/gui/check_button.h +++ b/scene/gui/check_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 523e07087b..58a0762469 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -35,10 +35,9 @@ #include "core/os/os.h" #ifdef TOOLS_ENABLED +#include "editor_scale.h" #include "editor_settings.h" #endif - -#include "scene/gui/separator.h" #include "scene/main/viewport.h" void ColorPicker::_notification(int p_what) { @@ -81,11 +80,8 @@ void ColorPicker::_notification(int p_what) { } break; case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { - if (screen != NULL) { - if (screen->is_visible()) { - screen->hide(); - } - } + if (screen != NULL && screen->is_visible()) + screen->hide(); } break; } } @@ -97,6 +93,28 @@ void ColorPicker::set_focus_on_line_edit() { void ColorPicker::_update_controls() { + const char *rgb[3] = { "R", "G", "B" }; + const char *hsv[3] = { "H", "S", "V" }; + + if (hsv_mode_enabled) { + for (int i = 0; i < 3; i++) + labels[i]->set_text(hsv[i]); + } else { + for (int i = 0; i < 3; i++) + labels[i]->set_text(rgb[i]); + } + + if (hsv_mode_enabled) { + set_raw_mode(false); + btn_raw->set_disabled(true); + } else if (raw_mode_enabled) { + set_hsv_mode(false); + btn_hsv->set_disabled(true); + } else { + btn_raw->set_disabled(false); + btn_hsv->set_disabled(false); + } + if (edit_alpha) { values[3]->show(); scroll[3]->show(); @@ -108,7 +126,7 @@ void ColorPicker::_update_controls() { } } -void ColorPicker::set_pick_color(const Color &p_color) { +void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) { color = p_color; if (color != last_hsv) { @@ -121,7 +139,12 @@ void ColorPicker::set_pick_color(const Color &p_color) { if (!is_inside_tree()) return; - _update_color(); + _update_color(p_update_sliders); +} + +void ColorPicker::set_pick_color(const Color &p_color) { + + _set_pick_color(p_color, true); //because setters can't have more arguments } void ColorPicker::set_edit_alpha(bool p_show) { @@ -146,17 +169,24 @@ void ColorPicker::_value_changed(double) { if (updating) return; - for (int i = 0; i < 4; i++) { - color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0); + if (hsv_mode_enabled) { + color.set_hsv(scroll[0]->get_value() / 360.0, + scroll[1]->get_value() / 100.0, + scroll[2]->get_value() / 100.0, + scroll[3]->get_value() / 100.0); + } else { + for (int i = 0; i < 4; i++) { + color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0); + } } - set_pick_color(color); + _set_pick_color(color, false); emit_signal("color_changed", color); } void ColorPicker::_html_entered(const String &p_html) { - if (updating) + if (updating || text_is_constructor || !c_text->is_visible()) return; float last_alpha = color.a; @@ -171,21 +201,40 @@ void ColorPicker::_html_entered(const String &p_html) { emit_signal("color_changed", color); } -void ColorPicker::_update_color() { +void ColorPicker::_update_color(bool p_update_sliders) { updating = true; - for (int i = 0; i < 4; i++) { - scroll[i]->set_step(0.01); - if (raw_mode_enabled) { - scroll[i]->set_max(100); - if (i == 3) - scroll[i]->set_max(1); - scroll[i]->set_value(color.components[i]); + if (p_update_sliders) { + + if (hsv_mode_enabled) { + for (int i = 0; i < 4; i++) { + scroll[i]->set_step(0.1); + } + + scroll[0]->set_max(360); + scroll[0]->set_value(h * 360.0); + scroll[1]->set_max(100); + scroll[1]->set_value(s * 100.0); + scroll[2]->set_max(100); + scroll[2]->set_value(v * 100.0); + scroll[3]->set_max(100); + scroll[3]->set_value(color.components[3] * 100.0); } else { - const int byte_value = color.components[i] * 255; - scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1); - scroll[i]->set_value(byte_value); + for (int i = 0; i < 4; i++) { + if (raw_mode_enabled) { + scroll[i]->set_step(0.01); + scroll[i]->set_max(100); + if (i == 3) + scroll[i]->set_max(1); + scroll[i]->set_value(color.components[i]); + } else { + scroll[i]->set_step(1); + const float byte_value = color.components[i] * 255.0; + scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1); + scroll[i]->set_value(byte_value); + } + } } } @@ -210,15 +259,18 @@ void ColorPicker::_update_presets() { } void ColorPicker::_text_type_toggled() { - if (!Engine::get_singleton()->is_editor_hint()) - return; + text_is_constructor = !text_is_constructor; if (text_is_constructor) { text_type->set_text(""); text_type->set_icon(get_icon("Script", "EditorIcons")); + + c_text->set_editable(false); } else { text_type->set_text("#"); text_type->set_icon(NULL); + + c_text->set_editable(true); } _update_color(); } @@ -272,13 +324,33 @@ PoolColorArray ColorPicker::get_presets() const { return arr; } +void ColorPicker::set_hsv_mode(bool p_enabled) { + + if (hsv_mode_enabled == p_enabled || raw_mode_enabled) + return; + hsv_mode_enabled = p_enabled; + if (btn_hsv->is_pressed() != p_enabled) + btn_hsv->set_pressed(p_enabled); + + if (!is_inside_tree()) + return; + + _update_controls(); + _update_color(); +} + +bool ColorPicker::is_hsv_mode() const { + + return hsv_mode_enabled; +} + void ColorPicker::set_raw_mode(bool p_enabled) { - if (raw_mode_enabled == p_enabled) + if (raw_mode_enabled == p_enabled || hsv_mode_enabled) return; raw_mode_enabled = p_enabled; - if (btn_mode->is_pressed() != p_enabled) - btn_mode->set_pressed(p_enabled); + if (btn_raw->is_pressed() != p_enabled) + btn_raw->set_pressed(p_enabled); if (!is_inside_tree()) return; @@ -303,19 +375,21 @@ bool ColorPicker::is_deferred_mode() const { void ColorPicker::_update_text_value() { bool visible = true; if (text_is_constructor) { - String t = "Color(" + String::num(color.r) + "," + String::num(color.g) + "," + String::num(color.b); + String t = "Color(" + String::num(color.r) + ", " + String::num(color.g) + ", " + String::num(color.b); if (edit_alpha && color.a < 1) - t += ("," + String::num(color.a) + ")"); + t += ", " + String::num(color.a) + ")"; else t += ")"; c_text->set_text(t); - } else { - if (color.r > 1 || color.g > 1 || color.b > 1 || color.r < 0 || color.g < 0 || color.b < 0) { - visible = false; - } else { - c_text->set_text(color.to_html(edit_alpha && color.a < 1)); - } } + + if (color.r > 1 || color.g > 1 || color.b > 1 || color.r < 0 || color.g < 0 || color.b < 0) { + visible = false; + } else if (!text_is_constructor) { + c_text->set_text(color.to_html(edit_alpha && color.a < 1)); + } + + text_type->set_visible(visible); c_text->set_visible(visible); } @@ -465,7 +539,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) { set_pick_color(presets[index]); _update_color(); emit_signal("color_changed", color); - } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT) { + } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) { int index = bev->get_position().x / (preset->get_size().x / presets.size()); Color clicked_preset = presets[index]; erase_preset(clicked_preset); @@ -493,21 +567,17 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) { void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> bev = p_event; - - if (bev.is_valid()) { - - if (bev->get_button_index() == BUTTON_LEFT && !bev->is_pressed()) { - emit_signal("color_changed", color); - screen->hide(); - } + if (bev.is_valid() && bev->get_button_index() == BUTTON_LEFT && !bev->is_pressed()) { + emit_signal("color_changed", color); + screen->hide(); } Ref<InputEventMouseMotion> mev = p_event; - if (mev.is_valid()) { Viewport *r = get_tree()->get_root(); if (!r->get_visible_rect().has_point(Point2(mev->get_global_position().x, mev->get_global_position().y))) return; + Ref<Image> img = r->get_texture()->get_data(); if (img.is_valid() && !img->empty()) { img->lock(); @@ -533,6 +603,8 @@ void ColorPicker::_screen_pick_pressed() { screen->set_anchors_and_margins_preset(Control::PRESET_WIDE); screen->set_default_cursor_shape(CURSOR_POINTING_HAND); screen->connect("gui_input", this, "_screen_input"); + // It immediately toggles off in the first press otherwise. + screen->call_deferred("connect", "hide", btn_pick, "set_pressed", varray(false)); } screen->raise(); screen->show_modal(); @@ -563,16 +635,47 @@ void ColorPicker::_html_focus_exit() { _focus_exit(); } +void ColorPicker::set_presets_enabled(bool p_enabled) { + presets_enabled = p_enabled; + if (!p_enabled) { + bt_add_preset->set_disabled(true); + bt_add_preset->set_focus_mode(FOCUS_NONE); + } else { + bt_add_preset->set_disabled(false); + bt_add_preset->set_focus_mode(FOCUS_ALL); + } +} + +bool ColorPicker::are_presets_enabled() const { + return presets_enabled; +} + +void ColorPicker::set_presets_visible(bool p_visible) { + presets_visible = p_visible; + preset_separator->set_visible(p_visible); + preset_container->set_visible(p_visible); +} + +bool ColorPicker::are_presets_visible() const { + return presets_visible; +} + void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color); ClassDB::bind_method(D_METHOD("get_pick_color"), &ColorPicker::get_pick_color); + ClassDB::bind_method(D_METHOD("set_hsv_mode", "mode"), &ColorPicker::set_hsv_mode); + ClassDB::bind_method(D_METHOD("is_hsv_mode"), &ColorPicker::is_hsv_mode); ClassDB::bind_method(D_METHOD("set_raw_mode", "mode"), &ColorPicker::set_raw_mode); ClassDB::bind_method(D_METHOD("is_raw_mode"), &ColorPicker::is_raw_mode); ClassDB::bind_method(D_METHOD("set_deferred_mode", "mode"), &ColorPicker::set_deferred_mode); ClassDB::bind_method(D_METHOD("is_deferred_mode"), &ColorPicker::is_deferred_mode); ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha); ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha); + ClassDB::bind_method(D_METHOD("set_presets_enabled", "enabled"), &ColorPicker::set_presets_enabled); + ClassDB::bind_method(D_METHOD("are_presets_enabled"), &ColorPicker::are_presets_enabled); + ClassDB::bind_method(D_METHOD("set_presets_visible", "visible"), &ColorPicker::set_presets_visible); + ClassDB::bind_method(D_METHOD("are_presets_visible"), &ColorPicker::are_presets_visible); ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset); ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset); ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets); @@ -594,8 +697,11 @@ void ColorPicker::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hsv_mode"), "set_hsv_mode", "is_hsv_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible"), "set_presets_visible", "are_presets_visible"); ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color"))); ADD_SIGNAL(MethodInfo("preset_added", PropertyInfo(Variant::COLOR, "color"))); @@ -608,28 +714,34 @@ ColorPicker::ColorPicker() : updating = true; edit_alpha = true; text_is_constructor = false; + hsv_mode_enabled = false; raw_mode_enabled = false; deferred_mode_enabled = false; changing_color = false; + presets_enabled = true; + presets_visible = true; screen = NULL; HBoxContainer *hb_smpl = memnew(HBoxContainer); - btn_pick = memnew(ToolButton); - btn_pick->connect("pressed", this, "_screen_pick_pressed"); + add_child(hb_smpl); sample = memnew(TextureRect); + hb_smpl->add_child(sample); sample->set_h_size_flags(SIZE_EXPAND_FILL); sample->connect("draw", this, "_sample_draw"); - hb_smpl->add_child(sample); + btn_pick = memnew(ToolButton); hb_smpl->add_child(btn_pick); - add_child(hb_smpl); + btn_pick->set_toggle_mode(true); + btn_pick->set_tooltip(TTR("Pick a color from the screen.")); + btn_pick->connect("pressed", this, "_screen_pick_pressed"); HBoxContainer *hb_edit = memnew(HBoxContainer); + add_child(hb_edit); hb_edit->set_v_size_flags(SIZE_EXPAND_FILL); uv_edit = memnew(Control); - + hb_edit->add_child(uv_edit); uv_edit->connect("gui_input", this, "_uv_input"); uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); uv_edit->set_h_size_flags(SIZE_EXPAND_FILL); @@ -637,19 +749,14 @@ ColorPicker::ColorPicker() : uv_edit->set_custom_minimum_size(Size2(get_constant("sv_width"), get_constant("sv_height"))); uv_edit->connect("draw", this, "_hsv_draw", make_binds(0, uv_edit)); - add_child(hb_edit); - w_edit = memnew(Control); + hb_edit->add_child(w_edit); w_edit->set_custom_minimum_size(Size2(get_constant("h_width"), 0)); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); w_edit->connect("gui_input", this, "_w_input"); w_edit->connect("draw", this, "_hsv_draw", make_binds(1, w_edit)); - hb_edit->add_child(uv_edit); - hb_edit->add_child(memnew(VSeparator)); - hb_edit->add_child(w_edit); - VBoxContainer *vbl = memnew(VBoxContainer); add_child(vbl); @@ -658,13 +765,12 @@ ColorPicker::ColorPicker() : VBoxContainer *vbr = memnew(VBoxContainer); add_child(vbr); vbr->set_h_size_flags(SIZE_EXPAND_FILL); - const char *lt[4] = { "R", "G", "B", "A" }; for (int i = 0; i < 4; i++) { HBoxContainer *hbc = memnew(HBoxContainer); - labels[i] = memnew(Label(lt[i])); + labels[i] = memnew(Label()); labels[i]->set_custom_minimum_size(Size2(get_constant("label_width"), 0)); labels[i]->set_v_size_flags(SIZE_SHRINK_CENTER); hbc->add_child(labels[i]); @@ -688,45 +794,64 @@ ColorPicker::ColorPicker() : vbr->add_child(hbc); } + labels[3]->set_text("A"); HBoxContainer *hhb = memnew(HBoxContainer); - - btn_mode = memnew(CheckButton); - btn_mode->set_text(TTR("Raw Mode")); - btn_mode->connect("toggled", this, "set_raw_mode"); - hhb->add_child(btn_mode); vbr->add_child(hhb); + + btn_hsv = memnew(CheckButton); + hhb->add_child(btn_hsv); + btn_hsv->set_text(TTR("HSV")); + btn_hsv->connect("toggled", this, "set_hsv_mode"); + + btn_raw = memnew(CheckButton); + hhb->add_child(btn_raw); + btn_raw->set_text(TTR("Raw")); + btn_raw->connect("toggled", this, "set_raw_mode"); + text_type = memnew(Button); - text_type->set_flat(true); - text_type->connect("pressed", this, "_text_type_toggled"); hhb->add_child(text_type); + text_type->set_text("#"); + text_type->set_tooltip(TTR("Switch between hexadecimal and code values.")); + if (Engine::get_singleton()->is_editor_hint()) { + +#ifdef TOOLS_ENABLED + text_type->set_custom_minimum_size(Size2(28 * EDSCALE, 0)); // Adjust for the width of the "Script" icon. +#endif + text_type->connect("pressed", this, "_text_type_toggled"); + } else { + + text_type->set_flat(true); + text_type->set_mouse_filter(MOUSE_FILTER_IGNORE); + } c_text = memnew(LineEdit); hhb->add_child(c_text); + c_text->set_h_size_flags(SIZE_EXPAND_FILL); c_text->connect("text_entered", this, "_html_entered"); c_text->connect("focus_entered", this, "_focus_enter"); c_text->connect("focus_exited", this, "_html_focus_exit"); - text_type->set_text("#"); - c_text->set_h_size_flags(SIZE_EXPAND_FILL); - _update_controls(); updating = false; set_pick_color(Color(1, 1, 1)); - HBoxContainer *bbc = memnew(HBoxContainer); - add_child(bbc); + preset_separator = memnew(HSeparator); + add_child(preset_separator); + + preset_container = memnew(HBoxContainer); + add_child(preset_container); preset = memnew(TextureRect); - bbc->add_child(preset); + preset_container->add_child(preset); preset->connect("gui_input", this, "_preset_input"); preset->connect("draw", this, "_update_presets"); bt_add_preset = memnew(Button); - bt_add_preset->set_tooltip(TTR("Add current color as a preset")); + preset_container->add_child(bt_add_preset); + bt_add_preset->set_tooltip(TTR("Add current color as a preset.")); bt_add_preset->connect("pressed", this, "_add_preset_pressed"); - bbc->add_child(bt_add_preset); } ///////////////// @@ -746,23 +871,33 @@ void ColorPickerButton::_modal_closed() { void ColorPickerButton::pressed() { _update_picker(); - popup->set_position(get_global_position() - picker->get_combined_minimum_size()); + popup->set_position(get_global_position() - picker->get_combined_minimum_size() * get_global_transform().get_scale()); + popup->set_scale(get_global_transform().get_scale()); popup->popup(); picker->set_focus_on_line_edit(); } void ColorPickerButton::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { + switch (p_what) { + case NOTIFICATION_DRAW: { - Ref<StyleBox> normal = get_stylebox("normal"); - 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); + Ref<StyleBox> normal = get_stylebox("normal"); + 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); + } break; + case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { + + if (popup) + popup->hide(); + } break; } - if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST && popup) { - popup->hide(); + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (popup && !is_visible_in_tree()) { + popup->hide(); + } } } @@ -813,6 +948,8 @@ void ColorPickerButton::_update_picker() { add_child(popup); picker->connect("color_changed", this, "_color_changed"); popup->connect("modal_closed", this, "_modal_closed"); + popup->connect("about_to_show", this, "set_pressed", varray(true)); + popup->connect("popup_hide", this, "set_pressed", varray(false)); picker->set_pick_color(color); picker->set_edit_alpha(edit_alpha); } @@ -837,10 +974,12 @@ void ColorPickerButton::_bind_methods() { ColorPickerButton::ColorPickerButton() { - //Initialization is now done deferred - //this improves performance in the inspector as the color picker - //can be expensive to initialize + // Initialization is now done deferred, + // this improves performance in the inspector as the color picker + // can be expensive to initialize. picker = NULL; popup = NULL; edit_alpha = true; + + set_toggle_mode(true); } diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index e32c830434..3af27a9856 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,6 +37,7 @@ #include "scene/gui/label.h" #include "scene/gui/line_edit.h" #include "scene/gui/popup.h" +#include "scene/gui/separator.h" #include "scene/gui/slider.h" #include "scene/gui/spin_box.h" #include "scene/gui/texture_rect.h" @@ -52,10 +53,13 @@ private: Control *w_edit; TextureRect *sample; TextureRect *preset; + HBoxContainer *preset_container; + HSeparator *preset_separator; Button *bt_add_preset; List<Color> presets; ToolButton *btn_pick; - CheckButton *btn_mode; + CheckButton *btn_hsv; + CheckButton *btn_raw; HSlider *scroll[4]; SpinBox *values[4]; Label *labels[4]; @@ -67,16 +71,19 @@ private: Color color; bool raw_mode_enabled; + bool hsv_mode_enabled; bool deferred_mode_enabled; bool updating; bool changing_color; + bool presets_enabled; + bool presets_visible; float h, s, v; Color last_hsv; void _html_entered(const String &p_html); void _value_changed(double); void _update_controls(); - void _update_color(); + void _update_color(bool p_update_sliders = true); void _update_presets(); void _update_text_value(); void _text_type_toggled(); @@ -101,6 +108,7 @@ public: void set_edit_alpha(bool p_show); bool is_editing_alpha() const; + void _set_pick_color(const Color &p_color, bool p_update_sliders); void set_pick_color(const Color &p_color); Color get_pick_color() const; @@ -108,12 +116,21 @@ public: void erase_preset(const Color &p_color); PoolColorArray get_presets() const; + void set_hsv_mode(bool p_enabled); + bool is_hsv_mode() const; + void set_raw_mode(bool p_enabled); bool is_raw_mode() const; void set_deferred_mode(bool p_enabled); bool is_deferred_mode() const; + void set_presets_enabled(bool p_enabled); + bool are_presets_enabled() const; + + void set_presets_visible(bool p_visible); + bool are_presets_visible() const; + void set_focus_on_line_edit(); ColorPicker(); diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp index 463f3911dc..df9b4e8498 100644 --- a/scene/gui/color_rect.cpp +++ b/scene/gui/color_rect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/color_rect.h b/scene/gui/color_rect.h index a841008f76..7a7bbe1029 100644 --- a/scene/gui/color_rect.h +++ b/scene/gui/color_rect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,7 @@ #include "scene/gui/control.h" class ColorRect : public Control { - GDCLASS(ColorRect, Control) + GDCLASS(ColorRect, Control); Color color; diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index d606629041..c9cf5f8308 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -95,6 +95,7 @@ void Container::_sort_children() { void Container::fit_child_in_rect(Control *p_child, const Rect2 &p_rect) { + ERR_FAIL_COND(!p_child); ERR_FAIL_COND(p_child->get_parent() != this); Size2 minsize = p_child->get_combined_minimum_size(); @@ -168,6 +169,19 @@ void Container::_notification(int p_what) { } } +String Container::get_configuration_warning() const { + + String warning = Control::get_configuration_warning(); + + if (get_class() == "Container" && get_script().is_null()) { + if (warning != String()) { + warning += "\n"; + } + warning += TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, then please use a plain 'Control' node instead."); + } + return warning; +} + void Container::_bind_methods() { ClassDB::bind_method(D_METHOD("_sort_children"), &Container::_sort_children); diff --git a/scene/gui/container.h b/scene/gui/container.h index c472162f58..80d3f6ee5d 100644 --- a/scene/gui/container.h +++ b/scene/gui/container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -57,6 +57,8 @@ public: void fit_child_in_rect(Control *p_child, const Rect2 &p_rect); + virtual String get_configuration_warning() const; + Container(); }; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index a580d89439..0845b56828 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,22 +29,23 @@ /*************************************************************************/ #include "control.h" -#include "core/project_settings.h" -#include "scene/main/canvas_layer.h" -#include "scene/main/viewport.h" -#include "servers/visual_server.h" #include "core/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/print_string.h" +#include "core/project_settings.h" #include "scene/gui/label.h" #include "scene/gui/panel.h" +#include "scene/main/canvas_layer.h" +#include "scene/main/viewport.h" #include "scene/scene_string_names.h" +#include "servers/visual_server.h" + #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" +#include "editor/plugins/canvas_item_editor_plugin.h" #endif -#include <stdio.h> Dictionary Control::_edit_get_state() const { @@ -66,6 +67,7 @@ Dictionary Control::_edit_get_state() const { s["margins"] = margins; return s; } + void Control::_edit_set_state(const Dictionary &p_state) { Dictionary state = p_state; @@ -87,7 +89,12 @@ void Control::_edit_set_state(const Dictionary &p_state) { } void Control::_edit_set_position(const Point2 &p_position) { +#ifdef TOOLS_ENABLED + set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled()); +#else + // Unlikely to happen. TODO: enclose all _edit_ functions into TOOLS_ENABLED set_position(p_position); +#endif }; Point2 Control::_edit_get_position() const { @@ -103,8 +110,14 @@ Size2 Control::_edit_get_scale() const { } void Control::_edit_set_rect(const Rect2 &p_edit_rect) { +#ifdef TOOLS_ENABLED + set_position((get_position() + get_transform().basis_xform(p_edit_rect.position)).snapped(Vector2(1, 1)), CanvasItemEditor::get_singleton()->is_anchors_mode_enabled()); + set_size(p_edit_rect.size.snapped(Vector2(1, 1)), CanvasItemEditor::get_singleton()->is_anchors_mode_enabled()); +#else + // Unlikely to happen. TODO: enclose all _edit_ functions into TOOLS_ENABLED set_position((get_position() + get_transform().basis_xform(p_edit_rect.position)).snapped(Vector2(1, 1))); set_size(p_edit_rect.size.snapped(Vector2(1, 1))); +#endif } Rect2 Control::_edit_get_rect() const { @@ -206,65 +219,62 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { if (name.begins_with("custom_icons/")) { String dname = name.get_slicec('/', 1); + if (data.icon_override.has(dname)) { + data.icon_override[dname]->disconnect("changed", this, "_override_changed"); + } data.icon_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_shaders/")) { String dname = name.get_slicec('/', 1); + if (data.shader_override.has(dname)) { + data.shader_override[dname]->disconnect("changed", this, "_override_changed"); + } data.shader_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_styles/")) { String dname = name.get_slicec('/', 1); + if (data.style_override.has(dname)) { + data.style_override[dname]->disconnect("changed", this, "_override_changed"); + } data.style_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_fonts/")) { String dname = name.get_slicec('/', 1); if (data.font_override.has(dname)) { - _unref_font(data.font_override[dname]); + data.font_override[dname]->disconnect("changed", this, "_override_changed"); } data.font_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_colors/")) { String dname = name.get_slicec('/', 1); data.color_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else if (name.begins_with("custom_constants/")) { String dname = name.get_slicec('/', 1); data.constant_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - update(); } else return false; } else { if (name.begins_with("custom_icons/")) { String dname = name.get_slicec('/', 1); - notification(NOTIFICATION_THEME_CHANGED); add_icon_override(dname, p_value); } else if (name.begins_with("custom_shaders/")) { String dname = name.get_slicec('/', 1); add_shader_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_styles/")) { String dname = name.get_slicec('/', 1); add_style_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_fonts/")) { String dname = name.get_slicec('/', 1); add_font_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_colors/")) { String dname = name.get_slicec('/', 1); add_color_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_constants/")) { String dname = name.get_slicec('/', 1); add_constant_override(dname, p_value); - notification(NOTIFICATION_THEME_CHANGED); } else return false; } @@ -279,7 +289,7 @@ void Control::_update_minimum_size() { Size2 minsize = get_combined_minimum_size(); if (minsize.x > data.size_cache.x || minsize.y > data.size_cache.y) { - _size_changed(); + set_size(data.size_cache); } data.updating_last_minimum_size = false; @@ -1369,7 +1379,7 @@ void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bo float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range; float previous_opposite_margin_pos = data.margin[(p_margin + 2) % 4] + data.anchor[(p_margin + 2) % 4] * parent_range; - data.anchor[p_margin] = CLAMP(p_anchor, 0.0, 1.0); + data.anchor[p_margin] = p_anchor; if (((p_margin == MARGIN_LEFT || p_margin == MARGIN_TOP) && data.anchor[p_margin] > data.anchor[(p_margin + 2) % 4]) || ((p_margin == MARGIN_RIGHT || p_margin == MARGIN_BOTTOM) && data.anchor[p_margin] < data.anchor[(p_margin + 2) % 4])) { @@ -1391,19 +1401,14 @@ void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bo } update(); - _change_notify("anchor"); + _change_notify("anchor_left"); + _change_notify("anchor_right"); + _change_notify("anchor_top"); + _change_notify("anchor_bottom"); } void Control::_set_anchor(Margin p_margin, float p_anchor) { -#ifdef TOOLS_ENABLED - if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) { - set_anchor(p_margin, p_anchor, EDITOR_DEF("editors/2d/keep_margins_when_changing_anchors", false)); - } else { - set_anchor(p_margin, p_anchor, false); - } -#else - set_anchor(p_margin, p_anchor, false); -#endif + set_anchor(p_margin, p_anchor); } void Control::set_anchor_and_margin(Margin p_margin, float p_anchor, float p_pos, bool p_push_opposite_anchor) { @@ -1412,7 +1417,7 @@ void Control::set_anchor_and_margin(Margin p_margin, float p_anchor, float p_pos set_margin(p_margin, p_pos); } -void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin) { +void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { //Left switch (p_preset) { case PRESET_TOP_LEFT: @@ -1423,21 +1428,21 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin) { case PRESET_LEFT_WIDE: case PRESET_HCENTER_WIDE: case PRESET_WIDE: - set_anchor(MARGIN_LEFT, ANCHOR_BEGIN, p_keep_margin); + set_anchor(MARGIN_LEFT, ANCHOR_BEGIN, p_keep_margins); break; case PRESET_CENTER_TOP: case PRESET_CENTER_BOTTOM: case PRESET_CENTER: case PRESET_VCENTER_WIDE: - set_anchor(MARGIN_LEFT, 0.5, p_keep_margin); + set_anchor(MARGIN_LEFT, 0.5, p_keep_margins); break; case PRESET_TOP_RIGHT: case PRESET_BOTTOM_RIGHT: case PRESET_CENTER_RIGHT: case PRESET_RIGHT_WIDE: - set_anchor(MARGIN_LEFT, ANCHOR_END, p_keep_margin); + set_anchor(MARGIN_LEFT, ANCHOR_END, p_keep_margins); break; } @@ -1451,21 +1456,21 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin) { case PRESET_TOP_WIDE: case PRESET_VCENTER_WIDE: case PRESET_WIDE: - set_anchor(MARGIN_TOP, ANCHOR_BEGIN, p_keep_margin); + set_anchor(MARGIN_TOP, ANCHOR_BEGIN, p_keep_margins); break; case PRESET_CENTER_LEFT: case PRESET_CENTER_RIGHT: case PRESET_CENTER: case PRESET_HCENTER_WIDE: - set_anchor(MARGIN_TOP, 0.5, p_keep_margin); + set_anchor(MARGIN_TOP, 0.5, p_keep_margins); break; case PRESET_BOTTOM_LEFT: case PRESET_BOTTOM_RIGHT: case PRESET_CENTER_BOTTOM: case PRESET_BOTTOM_WIDE: - set_anchor(MARGIN_TOP, ANCHOR_END, p_keep_margin); + set_anchor(MARGIN_TOP, ANCHOR_END, p_keep_margins); break; } @@ -1475,14 +1480,14 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin) { case PRESET_BOTTOM_LEFT: case PRESET_CENTER_LEFT: case PRESET_LEFT_WIDE: - set_anchor(MARGIN_RIGHT, ANCHOR_BEGIN, p_keep_margin); + set_anchor(MARGIN_RIGHT, ANCHOR_BEGIN, p_keep_margins); break; case PRESET_CENTER_TOP: case PRESET_CENTER_BOTTOM: case PRESET_CENTER: case PRESET_VCENTER_WIDE: - set_anchor(MARGIN_RIGHT, 0.5, p_keep_margin); + set_anchor(MARGIN_RIGHT, 0.5, p_keep_margins); break; case PRESET_TOP_RIGHT: @@ -1493,7 +1498,7 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin) { case PRESET_BOTTOM_WIDE: case PRESET_HCENTER_WIDE: case PRESET_WIDE: - set_anchor(MARGIN_RIGHT, ANCHOR_END, p_keep_margin); + set_anchor(MARGIN_RIGHT, ANCHOR_END, p_keep_margins); break; } @@ -1503,14 +1508,14 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin) { case PRESET_TOP_RIGHT: case PRESET_CENTER_TOP: case PRESET_TOP_WIDE: - set_anchor(MARGIN_BOTTOM, ANCHOR_BEGIN, p_keep_margin); + set_anchor(MARGIN_BOTTOM, ANCHOR_BEGIN, p_keep_margins); break; case PRESET_CENTER_LEFT: case PRESET_CENTER_RIGHT: case PRESET_CENTER: case PRESET_HCENTER_WIDE: - set_anchor(MARGIN_BOTTOM, 0.5, p_keep_margin); + set_anchor(MARGIN_BOTTOM, 0.5, p_keep_margins); break; case PRESET_BOTTOM_LEFT: @@ -1521,7 +1526,7 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin) { case PRESET_BOTTOM_WIDE: case PRESET_VCENTER_WIDE: case PRESET_WIDE: - set_anchor(MARGIN_BOTTOM, ANCHOR_END, p_keep_margin); + set_anchor(MARGIN_BOTTOM, ANCHOR_END, p_keep_margins); break; } } @@ -1714,7 +1719,11 @@ Point2 Control::get_global_position() const { return get_global_transform().get_origin(); } -void Control::set_global_position(const Point2 &p_point) { +void Control::_set_global_position(const Point2 &p_point) { + set_global_position(p_point); +} + +void Control::set_global_position(const Point2 &p_point, bool p_keep_margins) { Transform2D inv; @@ -1723,7 +1732,7 @@ void Control::set_global_position(const Point2 &p_point) { inv = data.parent_canvas_item->get_global_transform().affine_inverse(); } - set_position(inv.xform(p_point)); + set_position(inv.xform(p_point), p_keep_margins); } Rect2 Control::_compute_child_rect(const float p_anchors[4], const float p_margins[4]) const { @@ -1737,6 +1746,18 @@ Rect2 Control::_compute_child_rect(const float p_anchors[4], const float p_margi return result; } +void Control::_compute_anchors(Rect2 p_rect, const float p_margins[4], float (&r_anchors)[4]) { + + Size2 parent_rect_size = get_parent_anchorable_rect().size; + ERR_FAIL_COND(parent_rect_size.x == 0.0); + ERR_FAIL_COND(parent_rect_size.y == 0.0); + + r_anchors[0] = (p_rect.position.x - p_margins[0]) / parent_rect_size.x; + r_anchors[1] = (p_rect.position.y - p_margins[1]) / parent_rect_size.y; + r_anchors[2] = (p_rect.position.x + p_rect.size.x - p_margins[2]) / parent_rect_size.x; + r_anchors[3] = (p_rect.position.y + p_rect.size.y - p_margins[3]) / parent_rect_size.y; +} + void Control::_compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]) { Size2 parent_rect_size = get_parent_anchorable_rect().size; @@ -1746,13 +1767,28 @@ void Control::_compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r r_margins[3] = p_rect.position.y + p_rect.size.y - (p_anchors[3] * parent_rect_size.y); } -void Control::set_position(const Size2 &p_point) { +void Control::_set_position(const Size2 &p_point) { + set_position(p_point); +} - _compute_margins(Rect2(p_point, data.size_cache), data.anchor, data.margin); +void Control::set_position(const Size2 &p_point, bool p_keep_margins) { + if (p_keep_margins) { + _compute_anchors(Rect2(p_point, data.size_cache), data.margin, data.anchor); + _change_notify("anchor_left"); + _change_notify("anchor_right"); + _change_notify("anchor_top"); + _change_notify("anchor_bottom"); + } else { + _compute_margins(Rect2(p_point, data.size_cache), data.anchor, data.margin); + } _size_changed(); } -void Control::set_size(const Size2 &p_size) { +void Control::_set_size(const Size2 &p_size) { + set_size(p_size); +} + +void Control::set_size(const Size2 &p_size, bool p_keep_margins) { Size2 new_size = p_size; Size2 min = get_combined_minimum_size(); @@ -1761,7 +1797,15 @@ void Control::set_size(const Size2 &p_size) { if (new_size.y < min.y) new_size.y = min.y; - _compute_margins(Rect2(data.pos_cache, new_size), data.anchor, data.margin); + if (p_keep_margins) { + _compute_anchors(Rect2(data.pos_cache, new_size), data.margin, data.anchor); + _change_notify("anchor_left"); + _change_notify("anchor_right"); + _change_notify("anchor_top"); + _change_notify("anchor_bottom"); + } else { + _compute_margins(Rect2(data.pos_cache, new_size), data.anchor, data.margin); + } _size_changed(); } @@ -1799,52 +1843,83 @@ Rect2 Control::get_anchorable_rect() const { void Control::add_icon_override(const StringName &p_name, const Ref<Texture> &p_icon) { - ERR_FAIL_COND(p_icon.is_null()); - data.icon_override[p_name] = p_icon; + if (data.icon_override.has(p_name)) { + data.icon_override[p_name]->disconnect("changed", this, "_override_changed"); + } + + // clear if "null" is passed instead of a icon + if (p_icon.is_null()) { + data.icon_override.erase(p_name); + } else { + data.icon_override[p_name] = p_icon; + if (data.icon_override[p_name].is_valid()) { + data.icon_override[p_name]->connect("changed", this, "_override_changed", Vector<Variant>(), CONNECT_REFERENCE_COUNTED); + } + } notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) { - ERR_FAIL_COND(p_shader.is_null()); - data.shader_override[p_name] = p_shader; + + if (data.shader_override.has(p_name)) { + data.shader_override[p_name]->disconnect("changed", this, "_override_changed"); + } + + // clear if "null" is passed instead of a shader + if (p_shader.is_null()) { + data.shader_override.erase(p_name); + } else { + data.shader_override[p_name] = p_shader; + if (data.shader_override[p_name].is_valid()) { + data.shader_override[p_name]->connect("changed", this, "_override_changed", Vector<Variant>(), CONNECT_REFERENCE_COUNTED); + } + } notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { - ERR_FAIL_COND(p_style.is_null()); - data.style_override[p_name] = p_style; + if (data.style_override.has(p_name)) { + data.style_override[p_name]->disconnect("changed", this, "_override_changed"); + } + + // clear if "null" is passed instead of a style + if (p_style.is_null()) { + data.style_override.erase(p_name); + } else { + data.style_override[p_name] = p_style; + if (data.style_override[p_name].is_valid()) { + data.style_override[p_name]->connect("changed", this, "_override_changed", Vector<Variant>(), CONNECT_REFERENCE_COUNTED); + } + } notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_font_override(const StringName &p_name, const Ref<Font> &p_font) { - ERR_FAIL_COND(p_font.is_null()); if (data.font_override.has(p_name)) { - _unref_font(data.font_override[p_name]); + data.font_override[p_name]->disconnect("changed", this, "_override_changed"); } - data.font_override[p_name] = p_font; - if (p_font.is_valid()) { - _ref_font(p_font); + // clear if "null" is passed instead of a font + if (p_font.is_null()) { + data.font_override.erase(p_name); + } else { + data.font_override[p_name] = p_font; + if (data.font_override[p_name].is_valid()) { + data.font_override[p_name]->connect("changed", this, "_override_changed", Vector<Variant>(), CONNECT_REFERENCE_COUNTED); + } } - notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_color_override(const StringName &p_name, const Color &p_color) { data.color_override[p_name] = p_color; notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::add_constant_override(const StringName &p_name, int p_constant) { data.constant_override[p_name] = p_constant; notification(NOTIFICATION_THEME_CHANGED); - update(); } void Control::set_focus_mode(FocusMode p_focus_mode) { @@ -2143,7 +2218,6 @@ void Control::_propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool c->data.theme_owner = p_owner; } c->notification(NOTIFICATION_THEME_CHANGED); - c->update(); } } @@ -2550,32 +2624,10 @@ float Control::get_rotation_degrees() const { return Math::rad2deg(get_rotation()); } -//needed to update the control if the font changes.. -void Control::_ref_font(Ref<Font> p_sc) { - - if (!data.font_refcount.has(p_sc)) { - data.font_refcount[p_sc] = 1; - p_sc->connect("changed", this, "_font_changed"); - } else { - data.font_refcount[p_sc] += 1; - } -} - -void Control::_unref_font(Ref<Font> p_sc) { +void Control::_override_changed() { - ERR_FAIL_COND(!data.font_refcount.has(p_sc)); - data.font_refcount[p_sc]--; - if (data.font_refcount[p_sc] == 0) { - p_sc->disconnect("changed", this, "_font_changed"); - data.font_refcount.erase(p_sc); - } -} - -void Control::_font_changed() { - - update(); notification(NOTIFICATION_THEME_CHANGED); - minimum_size_changed(); //fonts affect minimum size pretty much almost always + minimum_size_changed(); // overrides are likely to affect minimum size } void Control::set_pivot_offset(const Vector2 &p_pivot) { @@ -2645,6 +2697,12 @@ bool Control::is_visibility_clip_disabled() const { void Control::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { +#ifdef TOOLS_ENABLED + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\""; +#else + const String quote_style = "\""; +#endif + Node::get_argument_options(p_function, p_idx, r_options); if (p_idx == 0) { @@ -2662,7 +2720,7 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List sn.sort_custom<StringName::AlphCompare>(); for (List<StringName>::Element *E = sn.front(); E; E = E->next()) { - r_options->push_back("\"" + E->get() + "\""); + r_options->push_back(quote_style + E->get() + quote_style); } } } @@ -2707,20 +2765,23 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("accept_event"), &Control::accept_event); ClassDB::bind_method(D_METHOD("get_minimum_size"), &Control::get_minimum_size); ClassDB::bind_method(D_METHOD("get_combined_minimum_size"), &Control::get_combined_minimum_size); - ClassDB::bind_method(D_METHOD("set_anchors_preset", "preset", "keep_margin"), &Control::set_anchors_preset, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_anchors_preset", "preset", "keep_margins"), &Control::set_anchors_preset, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_margins_preset", "preset", "resize_mode", "margin"), &Control::set_margins_preset, DEFVAL(PRESET_MODE_MINSIZE), DEFVAL(0)); ClassDB::bind_method(D_METHOD("set_anchors_and_margins_preset", "preset", "resize_mode", "margin"), &Control::set_anchors_and_margins_preset, DEFVAL(PRESET_MODE_MINSIZE), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("set_anchor", "margin", "anchor", "keep_margin", "push_opposite_anchor"), &Control::set_anchor, DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("_set_anchor", "margin", "anchor"), &Control::_set_anchor); + ClassDB::bind_method(D_METHOD("set_anchor", "margin", "anchor", "keep_margin", "push_opposite_anchor"), &Control::set_anchor, DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_anchor", "margin"), &Control::get_anchor); ClassDB::bind_method(D_METHOD("set_margin", "margin", "offset"), &Control::set_margin); ClassDB::bind_method(D_METHOD("set_anchor_and_margin", "margin", "anchor", "offset", "push_opposite_anchor"), &Control::set_anchor_and_margin, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_begin", "position"), &Control::set_begin); ClassDB::bind_method(D_METHOD("set_end", "position"), &Control::set_end); - ClassDB::bind_method(D_METHOD("set_position", "position"), &Control::set_position); - ClassDB::bind_method(D_METHOD("set_size", "size"), &Control::set_size); + ClassDB::bind_method(D_METHOD("set_position", "position", "keep_margins"), &Control::set_position, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("_set_position", "margin"), &Control::_set_position); + ClassDB::bind_method(D_METHOD("set_size", "size", "keep_margins"), &Control::set_size, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("_set_size", "size"), &Control::_set_size); ClassDB::bind_method(D_METHOD("set_custom_minimum_size", "size"), &Control::set_custom_minimum_size); - ClassDB::bind_method(D_METHOD("set_global_position", "position"), &Control::set_global_position); + ClassDB::bind_method(D_METHOD("set_global_position", "position", "keep_margins"), &Control::set_global_position, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("_set_global_position", "position"), &Control::_set_global_position); ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Control::set_rotation); ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Control::set_rotation_degrees); ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Control::set_scale); @@ -2735,7 +2796,7 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_scale"), &Control::get_scale); ClassDB::bind_method(D_METHOD("get_pivot_offset"), &Control::get_pivot_offset); ClassDB::bind_method(D_METHOD("get_custom_minimum_size"), &Control::get_custom_minimum_size); - ClassDB::bind_method(D_METHOD("get_parent_area_size"), &Control::get_size); + ClassDB::bind_method(D_METHOD("get_parent_area_size"), &Control::get_parent_area_size); ClassDB::bind_method(D_METHOD("get_global_position"), &Control::get_global_position); ClassDB::bind_method(D_METHOD("get_rect"), &Control::get_rect); ClassDB::bind_method(D_METHOD("get_global_rect"), &Control::get_global_rect); @@ -2829,7 +2890,7 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("_theme_changed"), &Control::_theme_changed); - ClassDB::bind_method(D_METHOD("_font_changed"), &Control::_font_changed); + ClassDB::bind_method(D_METHOD("_override_changed"), &Control::_override_changed); BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size")); @@ -2840,10 +2901,10 @@ void Control::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::BOOL, "_clips_input")); ADD_GROUP("Anchor", "anchor_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.01"), "_set_anchor", "get_anchor", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.01"), "_set_anchor", "get_anchor", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.01"), "_set_anchor", "get_anchor", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.01"), "_set_anchor", "get_anchor", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_BOTTOM); ADD_GROUP("Margin", "margin_"); ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_left", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_LEFT); @@ -2856,9 +2917,9 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_v_grow_direction", "get_v_grow_direction"); ADD_GROUP("Rect", "rect_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); - 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_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_position", "get_position"); + 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::VECTOR2, "rect_scale"), "set_scale", "get_scale"); diff --git a/scene/gui/control.h b/scene/gui/control.h index eb39d9ca0f..a6f9a442ae 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -207,7 +207,6 @@ private: HashMap<StringName, Ref<Font> > font_override; HashMap<StringName, Color> color_override; HashMap<StringName, int> constant_override; - Map<Ref<Font>, int> font_refcount; } data; @@ -218,6 +217,9 @@ private: Control *_get_focus_neighbour(Margin p_margin, int p_count = 0); void _set_anchor(Margin p_margin, float p_anchor); + void _set_position(const Point2 &p_point); + void _set_global_position(const Point2 &p_point); + void _set_size(const Size2 &p_size); void _propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign = true); void _theme_changed(); @@ -230,13 +232,12 @@ private: Rect2 _compute_child_rect(const float p_anchors[4], const float p_margins[4]) const; void _compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]); + void _compute_anchors(Rect2 p_rect, const float p_margins[4], float (&r_anchors)[4]); void _size_changed(); String _get_tooltip() const; - void _ref_font(Ref<Font> p_sc); - void _unref_font(Ref<Font> p_sc); - void _font_changed(); + void _override_changed(); void _update_canvas_item_transform(); @@ -328,7 +329,7 @@ public: /* POSITIONING */ - void set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin = true); + void set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins = true); void set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0); void set_anchors_and_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0); @@ -346,12 +347,12 @@ public: Point2 get_begin() const; Point2 get_end() const; - void set_position(const Point2 &p_point); - void set_global_position(const Point2 &p_point); + void set_position(const Point2 &p_point, bool p_keep_margins = false); + void set_global_position(const Point2 &p_point, bool p_keep_margins = false); Point2 get_position() const; Point2 get_global_position() const; - void set_size(const Size2 &p_size); + void set_size(const Size2 &p_size, bool p_keep_margins = false); Size2 get_size() const; Rect2 get_rect() const; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 50511f6bbd..4da11b671e 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -406,12 +406,20 @@ void AcceptDialog::set_hide_on_ok(bool p_hide) { hide_on_ok = p_hide; } - bool AcceptDialog::get_hide_on_ok() const { return hide_on_ok; } +void AcceptDialog::set_autowrap(bool p_autowrap) { + + label->set_autowrap(p_autowrap); +} +bool AcceptDialog::has_autowrap() { + + return label->has_autowrap(); +} + void AcceptDialog::register_text_enter(Node *p_line_edit) { ERR_FAIL_NULL(p_line_edit); @@ -530,6 +538,8 @@ void AcceptDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_custom_action"), &AcceptDialog::_custom_action); ClassDB::bind_method(D_METHOD("set_text", "text"), &AcceptDialog::set_text); ClassDB::bind_method(D_METHOD("get_text"), &AcceptDialog::get_text); + ClassDB::bind_method(D_METHOD("set_autowrap", "autowrap"), &AcceptDialog::set_autowrap); + ClassDB::bind_method(D_METHOD("has_autowrap"), &AcceptDialog::has_autowrap); ADD_SIGNAL(MethodInfo("confirmed")); ADD_SIGNAL(MethodInfo("custom_action", PropertyInfo(Variant::STRING, "action"))); @@ -537,6 +547,7 @@ void AcceptDialog::_bind_methods() { ADD_GROUP("Dialog", "dialog"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "dialog_text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_hide_on_ok"), "set_hide_on_ok", "get_hide_on_ok"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_autowrap"), "set_autowrap", "has_autowrap"); } bool AcceptDialog::swap_ok_cancel = false; @@ -555,7 +566,6 @@ AcceptDialog::AcceptDialog() { label->set_anchor(MARGIN_BOTTOM, ANCHOR_END); label->set_begin(Point2(margin, margin)); label->set_end(Point2(-margin, -button_margin - 10)); - //label->set_autowrap(true); add_child(label); hbc = memnew(HBoxContainer); diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index feb080dd06..c1a7f26a85 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -145,6 +145,9 @@ public: void set_text(String p_text); String get_text() const; + void set_autowrap(bool p_autowrap); + bool has_autowrap(); + AcceptDialog(); ~AcceptDialog(); }; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index a869f7cfcd..bc8dcf0e82 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -48,8 +48,9 @@ void FileDialog::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - refresh->set_icon(get_icon("reload")); dir_up->set_icon(get_icon("parent_folder")); + refresh->set_icon(get_icon("reload")); + show_hidden->set_icon(get_icon("toggle_hidden")); } if (p_what == NOTIFICATION_POPUP_HIDE) { @@ -86,7 +87,9 @@ void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) { _dir_entered(".."); } break; - default: { handled = false; } + default: { + handled = false; + } } if (handled) @@ -391,20 +394,19 @@ void FileDialog::update_file_list() { List<String> files; List<String> dirs; - bool isdir; - bool ishidden; - bool show_hidden = show_hidden_files; + bool is_dir; + bool is_hidden; String item; - while ((item = dir_access->get_next(&isdir)) != "") { + while ((item = dir_access->get_next(&is_dir)) != "") { if (item == "." || item == "..") continue; - ishidden = dir_access->current_is_hidden(); + is_hidden = dir_access->current_is_hidden(); - if (show_hidden || !ishidden) { - if (!isdir) + if (show_hidden_files || !is_hidden) { + if (!is_dir) files.push_back(item); else dirs.push_back(item); @@ -429,8 +431,6 @@ void FileDialog::update_file_list() { dirs.pop_front(); } - dirs.clear(); - List<String> patterns; // build filter if (filter->get_selected() == filter->get_item_count() - 1) { @@ -505,8 +505,6 @@ void FileDialog::update_file_list() { if (tree->get_root() && tree->get_root()->get_children() && tree->get_selected() == NULL) tree->get_root()->get_children()->select(0); - - files.clear(); } void FileDialog::_filter_selected(int) { @@ -861,7 +859,7 @@ FileDialog::FileDialog() { HBoxContainer *hbc = memnew(HBoxContainer); dir_up = memnew(ToolButton); - dir_up->set_tooltip(RTR("Go to parent folder")); + dir_up->set_tooltip(RTR("Go to parent folder.")); hbc->add_child(dir_up); dir_up->connect("pressed", this, "_go_up"); @@ -871,9 +869,17 @@ FileDialog::FileDialog() { dir->set_h_size_flags(SIZE_EXPAND_FILL); refresh = memnew(ToolButton); + refresh->set_tooltip(RTR("Refresh")); refresh->connect("pressed", this, "_update_file_list"); hbc->add_child(refresh); + show_hidden = memnew(ToolButton); + show_hidden->set_toggle_mode(true); + show_hidden->set_pressed(is_showing_hidden_files()); + show_hidden->set_tooltip(RTR("Toggle Hidden Files")); + show_hidden->connect("toggled", this, "set_show_hidden_files"); + hbc->add_child(show_hidden); + drives = memnew(OptionButton); hbc->add_child(drives); drives->connect("item_selected", this, "_select_drive"); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 8bd15080d3..9f7ea1a2f2 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -90,6 +90,7 @@ private: ToolButton *dir_up; ToolButton *refresh; + ToolButton *show_hidden; Vector<String> filters; diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index c13964d196..75f5f79873 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,10 +29,17 @@ /*************************************************************************/ #include "gradient_edit.h" + #include "core/os/keyboard.h" -#include "editor/editor_scale.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_scale.h" #define SPACING (3 * EDSCALE) +#define POINT_WIDTH (8 * EDSCALE) +#else +#define SPACING 3 +#define POINT_WIDTH 8 +#endif GradientEdit::GradientEdit() { grabbed = -1; diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index f6927ad0b7..6f31107729 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -33,10 +33,8 @@ #include "scene/gui/color_picker.h" #include "scene/gui/popup.h" -#include "scene/resources/color_ramp.h" #include "scene/resources/default_theme/theme_data.h" - -#define POINT_WIDTH (8 * EDSCALE) +#include "scene/resources/gradient.h" class GradientEdit : public Control { diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index eee3213fe7..dabff08fea 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,6 +34,10 @@ #include "core/os/keyboard.h" #include "scene/gui/box_container.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_scale.h" +#endif + #define ZOOM_SCALE 1.2 #define MIN_ZOOM (((1 / ZOOM_SCALE) / ZOOM_SCALE) / ZOOM_SCALE) @@ -217,8 +221,8 @@ void GraphEdit::_graph_node_raised(Node *p_gn) { } int first_not_comment = 0; for (int i = 0; i < get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); - if (gn && !gn->is_comment()) { + GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); + if (gn2 && !gn2->is_comment()) { first_not_comment = i; break; } @@ -257,8 +261,9 @@ void GraphEdit::add_child_notify(Node *p_child) { void GraphEdit::remove_child_notify(Node *p_child) { Control::remove_child_notify(p_child); - - top_layer->call_deferred("raise"); //top layer always on top! + if (is_inside_tree()) { + top_layer->call_deferred("raise"); //top layer always on top! + } GraphNode *gn = Object::cast_to<GraphNode>(p_child); if (gn) { gn->disconnect("offset_changed", this, "_graph_node_moved"); @@ -665,11 +670,15 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector<Color> colors; points.push_back(p_from); colors.push_back(p_color); - _bake_segment2d(points, colors, 0, 1, p_from, c1, p_to, c2, 0, 3, 9, 8, p_color, p_to_color, lines); + _bake_segment2d(points, colors, 0, 1, p_from, c1, p_to, c2, 0, 3, 9, 3, p_color, p_to_color, lines); points.push_back(p_to); colors.push_back(p_to_color); +#ifdef TOOLS_ENABLED + p_where->draw_polyline_colors(points, colors, Math::floor(2 * EDSCALE), true); +#else p_where->draw_polyline_colors(points, colors, 2, true); +#endif } void GraphEdit::_connections_layer_draw() { @@ -761,7 +770,9 @@ void GraphEdit::_top_layer_draw() { } if (box_selecting) - top_layer->draw_rect(box_selecting_rect, Color(0.7, 0.7, 1.0, 0.3)); + top_layer->draw_rect( + box_selecting_rect, + get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); } void GraphEdit::set_selected(Node *p_child) { @@ -950,33 +961,33 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { previus_selected.clear(); for (int i = get_child_count() - 1; i >= 0; i--) { - GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); - if (!gn || !gn->is_selected()) + GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); + if (!gn2 || !gn2->is_selected()) continue; - previus_selected.push_back(gn); + previus_selected.push_back(gn2); } } else if (b->get_shift()) { box_selection_mode_aditive = false; previus_selected.clear(); for (int i = get_child_count() - 1; i >= 0; i--) { - GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); - if (!gn || !gn->is_selected()) + GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); + if (!gn2 || !gn2->is_selected()) continue; - previus_selected.push_back(gn); + previus_selected.push_back(gn2); } } else { box_selection_mode_aditive = true; previus_selected.clear(); for (int i = get_child_count() - 1; i >= 0; i--) { - GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); - if (!gn) + GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); + if (!gn2) continue; - gn->set_selected(false); + gn2->set_selected(false); } } } @@ -1042,7 +1053,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) { - if (ABS(E->get().activity - p_activity) < CMP_EPSILON) { + if (Math::is_equal_approx(E->get().activity, p_activity)) { //update only if changed top_layer->update(); connections_layer->update(); @@ -1277,7 +1288,7 @@ void GraphEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING, "to"), PropertyInfo(Variant::INT, "to_slot"))); ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING, "to"), PropertyInfo(Variant::INT, "to_slot"))); - ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2, "p_position"))); + ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2, "position"))); ADD_SIGNAL(MethodInfo("duplicate_nodes_request")); ADD_SIGNAL(MethodInfo("node_selected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::VECTOR2, "release_position"))); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 71165e3dc9..de826bf505 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index b189afd30b..6463ee5ad5 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -159,12 +159,9 @@ void GraphNode::_resort() { fit_child_in_rect(c, r); cache_y.push_back(vofs + size.y * 0.5); - if (vofs > 0) - vofs += sep; - vofs += size.y; + vofs += size.y + sep; } - _change_notify(); update(); connpos_dirty = true; } @@ -192,97 +189,104 @@ bool GraphNode::has_point(const Point2 &p_point) const { void GraphNode::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { + switch (p_what) { + case NOTIFICATION_DRAW: { - Ref<StyleBox> sb; + Ref<StyleBox> sb; - if (comment) { - sb = get_stylebox(selected ? "commentfocus" : "comment"); + if (comment) { + sb = get_stylebox(selected ? "commentfocus" : "comment"); - } else { + } else { - sb = get_stylebox(selected ? "selectedframe" : "frame"); - } + sb = get_stylebox(selected ? "selectedframe" : "frame"); + } - //sb=sb->duplicate(); - //sb->call("set_modulate",modulate); - Ref<Texture> port = get_icon("port"); - Ref<Texture> close = get_icon("close"); - Ref<Texture> resizer = get_icon("resizer"); - int close_offset = get_constant("close_offset"); - int close_h_offset = get_constant("close_h_offset"); - Color close_color = get_color("close_color"); - Ref<Font> title_font = get_font("title_font"); - int title_offset = get_constant("title_offset"); - int title_h_offset = get_constant("title_h_offset"); - Color title_color = get_color("title_color"); - Point2i icofs = -port->get_size() * 0.5; - int edgeofs = get_constant("port_offset"); - icofs.y += sb->get_margin(MARGIN_TOP); - - draw_style_box(sb, Rect2(Point2(), get_size())); - - switch (overlay) { - case OVERLAY_DISABLED: { - - } break; - case OVERLAY_BREAKPOINT: { - - draw_style_box(get_stylebox("breakpoint"), Rect2(Point2(), get_size())); - } break; - case OVERLAY_POSITION: { - draw_style_box(get_stylebox("position"), Rect2(Point2(), get_size())); - - } break; - } + //sb=sb->duplicate(); + //sb->call("set_modulate",modulate); + Ref<Texture> port = get_icon("port"); + Ref<Texture> close = get_icon("close"); + Ref<Texture> resizer = get_icon("resizer"); + int close_offset = get_constant("close_offset"); + int close_h_offset = get_constant("close_h_offset"); + Color close_color = get_color("close_color"); + Ref<Font> title_font = get_font("title_font"); + int title_offset = get_constant("title_offset"); + int title_h_offset = get_constant("title_h_offset"); + Color title_color = get_color("title_color"); + Point2i icofs = -port->get_size() * 0.5; + int edgeofs = get_constant("port_offset"); + icofs.y += sb->get_margin(MARGIN_TOP); + + draw_style_box(sb, Rect2(Point2(), get_size())); + + switch (overlay) { + case OVERLAY_DISABLED: { + + } break; + case OVERLAY_BREAKPOINT: { + + draw_style_box(get_stylebox("breakpoint"), Rect2(Point2(), get_size())); + } break; + case OVERLAY_POSITION: { + draw_style_box(get_stylebox("position"), Rect2(Point2(), get_size())); + + } break; + } - int w = get_size().width - sb->get_minimum_size().x; + int w = get_size().width - sb->get_minimum_size().x; - if (show_close) - w -= close->get_width(); + if (show_close) + w -= close->get_width(); - draw_string(title_font, Point2(sb->get_margin(MARGIN_LEFT) + title_h_offset, -title_font->get_height() + title_font->get_ascent() + title_offset), title, title_color, w); - if (show_close) { - Vector2 cpos = Point2(w + sb->get_margin(MARGIN_LEFT) + close_h_offset, -close->get_height() + close_offset); - draw_texture(close, cpos, close_color); - close_rect.position = cpos; - close_rect.size = close->get_size(); - } else { - close_rect = Rect2(); - } + draw_string(title_font, Point2(sb->get_margin(MARGIN_LEFT) + title_h_offset, -title_font->get_height() + title_font->get_ascent() + title_offset), title, title_color, w); + if (show_close) { + Vector2 cpos = Point2(w + sb->get_margin(MARGIN_LEFT) + close_h_offset, -close->get_height() + close_offset); + draw_texture(close, cpos, close_color); + close_rect.position = cpos; + close_rect.size = close->get_size(); + } else { + close_rect = Rect2(); + } - for (Map<int, Slot>::Element *E = slot_info.front(); E; E = E->next()) { - - if (E->key() < 0 || E->key() >= cache_y.size()) - continue; - if (!slot_info.has(E->key())) - continue; - const Slot &s = slot_info[E->key()]; - //left - if (s.enable_left) { - Ref<Texture> p = port; - if (s.custom_slot_left.is_valid()) { - p = s.custom_slot_left; + for (Map<int, Slot>::Element *E = slot_info.front(); E; E = E->next()) { + + if (E->key() < 0 || E->key() >= cache_y.size()) + continue; + if (!slot_info.has(E->key())) + continue; + const Slot &s = slot_info[E->key()]; + //left + if (s.enable_left) { + Ref<Texture> p = port; + if (s.custom_slot_left.is_valid()) { + p = s.custom_slot_left; + } + p->draw(get_canvas_item(), icofs + Point2(edgeofs, cache_y[E->key()]), s.color_left); } - p->draw(get_canvas_item(), icofs + Point2(edgeofs, cache_y[E->key()]), s.color_left); - } - if (s.enable_right) { - Ref<Texture> p = port; - if (s.custom_slot_right.is_valid()) { - p = s.custom_slot_right; + if (s.enable_right) { + Ref<Texture> p = port; + if (s.custom_slot_right.is_valid()) { + p = s.custom_slot_right; + } + p->draw(get_canvas_item(), icofs + Point2(get_size().x - edgeofs, cache_y[E->key()]), s.color_right); } - p->draw(get_canvas_item(), icofs + Point2(get_size().x - edgeofs, cache_y[E->key()]), s.color_right); } - } - if (resizable) { - draw_texture(resizer, get_size() - resizer->get_size()); - } - } + if (resizable) { + draw_texture(resizer, get_size() - resizer->get_size()); + } + } break; - if (p_what == NOTIFICATION_SORT_CHILDREN) { + case NOTIFICATION_SORT_CHILDREN: { - _resort(); + _resort(); + } break; + + case NOTIFICATION_THEME_CHANGED: { + + minimum_size_changed(); + } break; } } @@ -402,9 +406,12 @@ Size2 GraphNode::get_minimum_size() const { void GraphNode::set_title(const String &p_title) { + if (title == p_title) + return; title = p_title; - minimum_size_changed(); update(); + _change_notify("title"); + minimum_size_changed(); } String GraphNode::get_title() const { diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 20d25a69b0..2179904cc4 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index bb1d1d7695..d0e2edc7b5 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -164,6 +164,10 @@ void GridContainer::_notification(int p_what) { } } break; + case NOTIFICATION_THEME_CHANGED: { + + minimum_size_changed(); + } break; } } diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h index 243d06f034..3196046378 100644 --- a/scene/gui/grid_container.h +++ b/scene/gui/grid_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 1669d62082..91b76839d7 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -470,6 +470,8 @@ Size2 ItemList::Item::get_icon_size() const { void ItemList::_gui_input(const Ref<InputEvent> &p_event) { + double prev_scroll = scroll_bar->get_value(); + Ref<InputEventMouseMotion> mm = p_event; if (defer_select_single >= 0 && mm.is_valid()) { defer_select_single = -1; @@ -715,9 +717,9 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { } } else if (p_event->is_action("ui_cancel")) { search_string = ""; - } else if (p_event->is_action("ui_select")) { + } else if (p_event->is_action("ui_select") && select_mode == SELECT_MULTI) { - if (select_mode == SELECT_MULTI && current >= 0 && current < items.size()) { + if (current >= 0 && current < items.size()) { if (items[current].selectable && !items[current].disabled && !items[current].selected) { select(current, false); emit_signal("multi_selected", current, true); @@ -747,9 +749,21 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { search_string = ""; } - search_string += String::chr(k->get_unicode()); - for (int i = 0; i < items.size(); i++) { - if (items[i].text.begins_with(search_string)) { + if (String::chr(k->get_unicode()) != search_string) + search_string += String::chr(k->get_unicode()); + + for (int i = current + 1; i <= items.size(); i++) { + if (i == items.size()) { + if (current == 0) + break; + else + i = 0; + } + + if (i == current) + break; + + if (items[i].text.findn(search_string) == 0) { set_current(i); ensure_current_is_visible(); if (select_mode == SELECT_SINGLE) { @@ -767,6 +781,9 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * pan_gesture->get_delta().y / 8); } + + if (scroll_bar->get_value() != prev_scroll) + accept_event(); //accept event if scroll changed } void ItemList::ensure_current_is_visible() { @@ -1094,7 +1111,7 @@ void ItemList::_notification(int p_what) { if (items[i].disabled) modulate.a *= 0.5; - // If the icon is transposed, we have to swith the size so that it is drawn correctly + // If the icon is transposed, we have to switch the size so that it is drawn correctly if (items[i].icon_transposed) { Size2 size_tmp = draw_rect.size; draw_rect.size.x = size_tmp.y; @@ -1114,13 +1131,13 @@ void ItemList::_notification(int p_what) { int max_len = -1; - Vector2 size = font->get_string_size(items[i].text); + Vector2 size2 = font->get_string_size(items[i].text); if (fixed_column_width) max_len = fixed_column_width; else if (same_column_width) max_len = items[i].rect_cache.size.x; else - max_len = size.x; + max_len = size2.x; Color modulate = items[i].selected ? font_color_selected : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color); if (items[i].disabled) @@ -1170,12 +1187,12 @@ void ItemList::_notification(int p_what) { } else { if (fixed_column_width > 0) - size.x = MIN(size.x, fixed_column_width); + size2.x = MIN(size2.x, fixed_column_width); if (icon_mode == ICON_MODE_TOP) { - text_ofs.x += (items[i].rect_cache.size.width - size.x) / 2; + text_ofs.x += (items[i].rect_cache.size.width - size2.x) / 2; } else { - text_ofs.y += (items[i].rect_cache.size.height - size.y) / 2; + text_ofs.y += (items[i].rect_cache.size.height - size2.y) / 2; } text_ofs.y += font->get_ascent(); @@ -1243,7 +1260,7 @@ int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const { Rect2 rc = items[i].rect_cache; if (i % current_columns == current_columns - 1) { - rc.size.width = get_size().width; //not right but works + rc.size.width = get_size().width - rc.position.x; //make sure you can still select the last item when clicking past the column } if (rc.has_point(pos)) { diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index acd17986eb..3a7cc65ab4 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 14e8c34d5f..e3e9368a12 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/label.h b/scene/gui/label.h index d5e0b60773..561c42ef9e 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 42d7f1b080..da6bff8ab8 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "line_edit.h" + #include "core/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" @@ -43,7 +44,7 @@ static bool _is_text_char(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; + return !is_symbol(c); } void LineEdit::_gui_input(Ref<InputEvent> p_event) { @@ -55,6 +56,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { menu->set_position(get_global_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); + menu->set_scale(get_global_transform().get_scale()); menu->popup(); grab_focus(); return; @@ -66,6 +68,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { _reset_caret_blink_timer(); if (b->is_pressed()) { + accept_event(); //don't pass event further when clicked on text field if (!text.empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; clear_button_status.pressing_inside = true; @@ -157,6 +160,38 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (!k->is_pressed()) return; + +#ifdef APPLE_STYLE_KEYS + if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) { + uint32_t remap_key = KEY_UNKNOWN; + switch (k->get_scancode()) { + case KEY_F: { + remap_key = KEY_RIGHT; + } break; + case KEY_B: { + remap_key = KEY_LEFT; + } break; + case KEY_P: { + remap_key = KEY_UP; + } break; + case KEY_N: { + remap_key = KEY_DOWN; + } break; + case KEY_D: { + remap_key = KEY_DELETE; + } break; + case KEY_H: { + remap_key = KEY_BACKSPACE; + } break; + } + + if (remap_key != KEY_UNKNOWN) { + k->set_scancode(remap_key); + k->set_control(false); + } + } +#endif + unsigned int code = k->get_scancode(); if (k->get_command()) { @@ -248,7 +283,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { set_cursor_position(text.length()); } break; #endif - default: { handled = false; } + default: { + handled = false; + } } if (handled) { @@ -318,7 +355,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { handled = false; break; } - // numlock disabled. fallthrough to key_left + FALLTHROUGH; } case KEY_LEFT: { @@ -365,7 +402,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { handled = false; break; } - // numlock disabled. fallthrough to key_right + FALLTHROUGH; } case KEY_RIGHT: { @@ -472,7 +509,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { handled = false; break; } - // numlock disabled. fallthrough to key_home + FALLTHROUGH; } case KEY_HOME: { @@ -485,7 +522,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { handled = false; break; } - // numlock disabled. fallthrough to key_end + FALLTHROUGH; } case KEY_END: { @@ -502,7 +539,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (handled) { accept_event(); - } else if (!k->get_alt() && !k->get_command()) { + } else if (!k->get_command()) { if (k->get_unicode() >= 32 && k->get_scancode() != KEY_DELETE) { if (editable) { @@ -609,9 +646,7 @@ void LineEdit::_notification(int p_what) { #endif case NOTIFICATION_RESIZED: { - if (expand_to_text_length) { - window_pos = 0; //force scroll back since it's expanding to text length - } + window_pos = 0; set_cursor_position(get_cursor_position()); } break; @@ -719,6 +754,8 @@ void LineEdit::_notification(int p_what) { } else { x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT)); } + + ofs_max -= r_icon->get_width(); } int caret_height = font->get_height() > y_area ? y_area : font->get_height(); @@ -860,9 +897,11 @@ void LineEdit::_notification(int p_what) { } break; case MainLoop::NOTIFICATION_OS_IME_UPDATE: { - ime_text = OS::get_singleton()->get_ime_text(); - ime_selection = OS::get_singleton()->get_ime_selection(); - update(); + if (has_focus()) { + ime_text = OS::get_singleton()->get_ime_text(); + ime_selection = OS::get_singleton()->get_ime_selection(); + update(); + } } break; } } @@ -884,7 +923,8 @@ void LineEdit::cut_text() { void LineEdit::paste_text() { - String paste_buffer = OS::get_singleton()->get_clipboard(); + // Strip escape characters like \n and \t as they can't be displayed on LineEdit. + String paste_buffer = OS::get_singleton()->get_clipboard().strip_escapes(); if (paste_buffer != "") { @@ -913,6 +953,10 @@ void LineEdit::undo() { TextOperation op = undo_stack_pos->get(); text = op.text; set_cursor_position(op.cursor_pos); + + if (expand_to_text_length) + minimum_size_changed(); + _emit_text_change(); } @@ -927,6 +971,10 @@ void LineEdit::redo() { TextOperation op = undo_stack_pos->get(); text = op.text; set_cursor_position(op.cursor_pos); + + if (expand_to_text_length) + minimum_size_changed(); + _emit_text_change(); } @@ -1150,14 +1198,14 @@ void LineEdit::set_cursor_position(int p_pos) { if (cursor_pos <= window_pos) { /* Adjust window if cursor goes too much to the left */ - if (window_pos > 0) - set_window_pos(window_pos - 1); - + set_window_pos(MAX(0, cursor_pos - 1)); } else if (cursor_pos > window_pos) { /* Adjust window if cursor goes too much to the right */ int window_width = get_size().width - style->get_minimum_size().width; - if (right_icon.is_valid()) { - window_width -= right_icon->get_width(); + 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; + window_width -= r_icon->get_width(); } if (window_width < 0) @@ -1221,6 +1269,7 @@ void LineEdit::append_at_cursor(String p_text) { void LineEdit::clear_internal() { + deselect(); _clear_undo_stack(); cached_width = 0; cursor_pos = 0; @@ -1286,13 +1335,11 @@ int LineEdit::get_max_length() const { void LineEdit::selection_fill_at_cursor() { - int aux; - selection.begin = cursor_pos; selection.end = selection.cursor_start; if (selection.end < selection.begin) { - aux = selection.end; + int aux = selection.end; selection.end = selection.begin; selection.begin = aux; } @@ -1313,7 +1360,27 @@ void LineEdit::select_all() { void LineEdit::set_editable(bool p_editable) { + if (editable == p_editable) + return; + editable = p_editable; + + // Reorganize context menu. + menu->clear(); + if (editable) + menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X); + menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C); + if (editable) + menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V); + menu->add_separator(); + menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A); + if (editable) { + menu->add_item(RTR("Clear"), MENU_CLEAR); + menu->add_separator(); + menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z); + menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z); + } + update(); } @@ -1609,7 +1676,6 @@ LineEdit::LineEdit() { deselect(); set_focus_mode(FOCUS_ALL); - editable = true; set_default_cursor_shape(CURSOR_IBEAM); set_mouse_filter(MOUSE_FILTER_STOP); @@ -1624,15 +1690,8 @@ LineEdit::LineEdit() { context_menu_enabled = true; menu = memnew(PopupMenu); add_child(menu); - menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X); - menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C); - menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V); - menu->add_separator(); - menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A); - menu->add_item(RTR("Clear"), MENU_CLEAR); - menu->add_separator(); - menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z); - menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z); + editable = false; // initialise to opposite first, so we get past the early-out in set_editable + set_editable(true); menu->connect("id_pressed", this, "menu_option"); expand_to_text_length = false; } diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index ddcdeda8c0..3b29780dc0 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index a603487cf1..21527e9bfc 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h index 0821ad9c0d..17c4bca67b 100644 --- a/scene/gui/link_button.h +++ b/scene/gui/link_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,7 +32,7 @@ #define LINKBUTTON_H #include "scene/gui/base_button.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" class LinkButton : public BaseButton { diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index 5e1d53fe1d..62ba45c484 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -64,27 +64,33 @@ Size2 MarginContainer::get_minimum_size() const { void MarginContainer::_notification(int p_what) { - if (p_what == NOTIFICATION_SORT_CHILDREN) { + switch (p_what) { + case NOTIFICATION_SORT_CHILDREN: { - int margin_left = get_constant("margin_left"); - int margin_top = get_constant("margin_top"); - int margin_right = get_constant("margin_right"); - int margin_bottom = get_constant("margin_bottom"); + int margin_left = get_constant("margin_left"); + int margin_top = get_constant("margin_top"); + int margin_right = get_constant("margin_right"); + int margin_bottom = get_constant("margin_bottom"); - Size2 s = get_size(); + Size2 s = get_size(); - for (int i = 0; i < get_child_count(); i++) { + for (int i = 0; i < get_child_count(); i++) { - Control *c = Object::cast_to<Control>(get_child(i)); - if (!c) - continue; - if (c->is_set_as_toplevel()) - continue; + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; - int w = s.width - margin_left - margin_right; - int h = s.height - margin_top - margin_bottom; - fit_child_in_rect(c, Rect2(margin_left, margin_top, w, h)); - } + int w = s.width - margin_left - margin_right; + int h = s.height - margin_top - margin_bottom; + fit_child_in_rect(c, Rect2(margin_left, margin_top, w, h)); + } + } break; + case NOTIFICATION_THEME_CHANGED: { + + minimum_size_changed(); + } break; } } diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h index ea75109248..336b68665f 100644 --- a/scene/gui/margin_container.h +++ b/scene/gui/margin_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index b4cb297900..e12cd55e6f 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -55,8 +55,9 @@ void MenuButton::pressed() { Size2 size = get_size(); Point2 gp = get_global_position(); - popup->set_global_position(gp + Size2(0, size.height)); + popup->set_global_position(gp + Size2(0, size.height * get_global_transform().get_scale().y)); popup->set_size(Size2(size.width, 0)); + popup->set_scale(get_global_transform().get_scale()); popup->set_parent_rect(Rect2(Point2(gp - popup->get_global_position()), get_size())); popup->popup(); } @@ -91,6 +92,16 @@ bool MenuButton::is_switch_on_hover() { return switch_on_hover; } +void MenuButton::_notification(int p_what) { + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + + if (!is_visible_in_tree()) { + popup->hide(); + } + } +} + void MenuButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_popup"), &MenuButton::get_popup); @@ -116,15 +127,18 @@ MenuButton::MenuButton() { switch_on_hover = false; set_flat(true); + set_toggle_mode(true); set_disable_shortcuts(false); set_enabled_focus_mode(FOCUS_NONE); + set_process_unhandled_key_input(true); + set_action_mode(ACTION_MODE_BUTTON_PRESS); + popup = memnew(PopupMenu); popup->hide(); add_child(popup); - popup->set_as_toplevel(true); popup->set_pass_on_modal_close_click(false); - set_process_unhandled_key_input(true); - set_action_mode(ACTION_MODE_BUTTON_PRESS); + popup->connect("about_to_show", this, "set_pressed", varray(true)); // For when switching from another MenuButton. + popup->connect("popup_hide", this, "set_pressed", varray(false)); } MenuButton::~MenuButton() { diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index abc49f4988..42e909d991 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -52,6 +52,7 @@ class MenuButton : public Button { void _gui_input(Ref<InputEvent> p_event); protected: + void _notification(int p_what); static void _bind_methods(); public: diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp index 802dc0db4f..23e0ea876d 100644 --- a/scene/gui/nine_patch_rect.cpp +++ b/scene/gui/nine_patch_rect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/nine_patch_rect.h b/scene/gui/nine_patch_rect.h index b4b4602a7d..ac17e52fc1 100644 --- a/scene/gui/nine_patch_rect.h +++ b/scene/gui/nine_patch_rect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 6b847c6483..872402e9e1 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -72,6 +72,11 @@ void OptionButton::_notification(int p_what) { Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); arrow->draw(ci, ofs, clr); + } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + + if (!is_visible_in_tree()) { + popup->hide(); + } } } @@ -81,44 +86,27 @@ void OptionButton::_focused(int p_which) { void OptionButton::_selected(int p_which) { - int selid = -1; - for (int i = 0; i < popup->get_item_count(); i++) { - - bool is_clicked = popup->get_item_id(i) == p_which; - if (is_clicked) { - selid = i; - break; - } - } - - if (selid == -1 && p_which >= 0 && p_which < popup->get_item_count()) { - _select(p_which, true); - } else { - - ERR_FAIL_COND(selid == -1); - - _select(selid, true); - } + _select(p_which, true); } void OptionButton::pressed() { Size2 size = get_size(); - popup->set_global_position(get_global_position() + Size2(0, size.height)); + popup->set_global_position(get_global_position() + Size2(0, size.height * get_global_transform().get_scale().y)); popup->set_size(Size2(size.width, 0)); - + popup->set_scale(get_global_transform().get_scale()); popup->popup(); } -void OptionButton::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID) { +void OptionButton::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id) { - popup->add_icon_radio_check_item(p_icon, p_label, p_ID); + popup->add_icon_radio_check_item(p_icon, p_label, p_id); if (popup->get_item_count() == 1) select(0); } -void OptionButton::add_item(const String &p_label, int p_ID) { +void OptionButton::add_item(const String &p_label, int p_id) { - popup->add_radio_check_item(p_label, p_ID); + popup->add_radio_check_item(p_label, p_id); if (popup->get_item_count() == 1) select(0); } @@ -131,9 +119,9 @@ void OptionButton::set_item_icon(int p_idx, const Ref<Texture> &p_icon) { popup->set_item_icon(p_idx, p_icon); } -void OptionButton::set_item_id(int p_idx, int p_ID) { +void OptionButton::set_item_id(int p_idx, int p_id) { - popup->set_item_id(p_idx, p_ID); + popup->set_item_id(p_idx, p_id); } void OptionButton::set_item_metadata(int p_idx, const Variant &p_metadata) { @@ -160,6 +148,12 @@ int OptionButton::get_item_id(int p_idx) const { return popup->get_item_id(p_idx); } + +int OptionButton::get_item_index(int p_id) const { + + return popup->get_item_index(p_id); +} + Variant OptionButton::get_item_metadata(int p_idx) const { return popup->get_item_metadata(p_idx); @@ -306,6 +300,7 @@ void OptionButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_text", "idx"), &OptionButton::get_item_text); ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &OptionButton::get_item_icon); ClassDB::bind_method(D_METHOD("get_item_id", "idx"), &OptionButton::get_item_id); + ClassDB::bind_method(D_METHOD("get_item_index", "id"), &OptionButton::get_item_index); ClassDB::bind_method(D_METHOD("get_item_metadata", "idx"), &OptionButton::get_item_metadata); ClassDB::bind_method(D_METHOD("is_item_disabled", "idx"), &OptionButton::is_item_disabled); ClassDB::bind_method(D_METHOD("get_item_count"), &OptionButton::get_item_count); @@ -326,23 +321,26 @@ void OptionButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); // "selected" property must come after "items", otherwise GH-10213 occurs ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected"); - ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "ID"))); - ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "ID"))); + ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "id"))); } OptionButton::OptionButton() { current = -1; + set_toggle_mode(true); set_text_align(ALIGN_LEFT); set_action_mode(ACTION_MODE_BUTTON_PRESS); popup = memnew(PopupMenu); popup->hide(); add_child(popup); - popup->set_as_toplevel(true); popup->set_pass_on_modal_close_click(false); - popup->connect("id_pressed", this, "_selected"); + popup->set_notify_transform(true); + popup->set_allow_search(true); + popup->connect("index_pressed", this, "_selected"); popup->connect("id_focused", this, "_focused"); + popup->connect("popup_hide", this, "set_pressed", varray(false)); } OptionButton::~OptionButton() { diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index d5f866d806..51d5fd6947 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -59,18 +59,19 @@ protected: static void _bind_methods(); public: - void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID = -1); - void add_item(const String &p_label, int p_ID = -1); + void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1); + void add_item(const String &p_label, int p_id = -1); void set_item_text(int p_idx, const String &p_text); void set_item_icon(int p_idx, const Ref<Texture> &p_icon); - void set_item_id(int p_idx, int p_ID); + void set_item_id(int p_idx, int p_id); void set_item_metadata(int p_idx, const Variant &p_metadata); void set_item_disabled(int p_idx, bool p_disabled); String get_item_text(int p_idx) const; Ref<Texture> get_item_icon(int p_idx) const; int get_item_id(int p_idx) const; + int get_item_index(int p_id) const; Variant get_item_metadata(int p_idx) const; bool is_item_disabled(int p_idx) const; diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp index d3b7b72ee1..c26bd09f50 100644 --- a/scene/gui/panel.cpp +++ b/scene/gui/panel.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/panel.h b/scene/gui/panel.h index db8b35372e..f8d15e4261 100644 --- a/scene/gui/panel.h +++ b/scene/gui/panel.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp index a778d62659..b1fced87fc 100644 --- a/scene/gui/panel_container.cpp +++ b/scene/gui/panel_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h index 267e2b921f..15661d3e35 100644 --- a/scene/gui/panel_container.h +++ b/scene/gui/panel_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index bfbe62e1c7..fdb1b65f77 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -52,16 +52,20 @@ void Popup::_notification(int p_what) { //small helper to make editing of these easier in editor #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { + //edited on editor set_as_toplevel(false); - } + } else #endif + if (is_visible()) { + hide(); + } } } void Popup::_fix_size() { Point2 pos = get_global_position(); - Size2 size = get_size(); + Size2 size = get_size() * get_scale(); Point2 window_size = get_viewport_rect().size; if (pos.x + size.width > window_size.width) @@ -111,6 +115,18 @@ void Popup::set_as_minsize() { set_size(total_minsize); } +void Popup::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) { + + Size2 popup_size = p_size; + Size2 window_size = get_viewport_rect().size; + + // clamp popup size in each dimension if window size is too small (using fallback ratio) + popup_size.x = MIN(window_size.x * p_fallback_ratio, popup_size.x); + popup_size.y = MIN(window_size.y * p_fallback_ratio, popup_size.y); + + popup_centered(popup_size); +} + void Popup::popup_centered_minsize(const Size2 &p_minsize) { set_custom_minimum_size(p_minsize); @@ -120,49 +136,22 @@ void Popup::popup_centered_minsize(const Size2 &p_minsize) { void Popup::popup_centered(const Size2 &p_size) { - Point2 window_size = get_viewport_rect().size; - - emit_signal("about_to_show"); Rect2 rect; + Size2 window_size = get_viewport_rect().size; rect.size = p_size == Size2() ? get_size() : p_size; - rect.position = ((window_size - rect.size) / 2.0).floor(); - set_position(rect.position); - set_size(rect.size); - - show_modal(exclusive); - _fix_size(); - - Control *focusable = find_next_valid_focus(); - if (focusable) - focusable->grab_focus(); - _post_popup(); - notification(NOTIFICATION_POST_POPUP); - popped_up = true; + popup(rect); } void Popup::popup_centered_ratio(float p_screen_ratio) { - emit_signal("about_to_show"); - Rect2 rect; - Point2 window_size = get_viewport_rect().size; + Size2 window_size = get_viewport_rect().size; rect.size = (window_size * p_screen_ratio).floor(); rect.position = ((window_size - rect.size) / 2.0).floor(); - set_position(rect.position); - set_size(rect.size); - show_modal(exclusive); - _fix_size(); - - Control *focusable = find_next_valid_focus(); - if (focusable) - focusable->grab_focus(); - - _post_popup(); - notification(NOTIFICATION_POST_POPUP); - popped_up = true; + popup(rect); } void Popup::popup(const Rect2 &p_bounds) { @@ -202,6 +191,7 @@ void Popup::_bind_methods() { ClassDB::bind_method(D_METHOD("popup_centered", "size"), &Popup::popup_centered, DEFVAL(Size2())); ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Popup::popup_centered_ratio, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("popup_centered_minsize", "minsize"), &Popup::popup_centered_minsize, DEFVAL(Size2())); + ClassDB::bind_method(D_METHOD("popup_centered_clamped", "size", "fallback_ratio"), &Popup::popup_centered_clamped, DEFVAL(Size2()), DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("popup", "bounds"), &Popup::popup, DEFVAL(Rect2())); ClassDB::bind_method(D_METHOD("set_exclusive", "enable"), &Popup::set_exclusive); ClassDB::bind_method(D_METHOD("is_exclusive"), &Popup::is_exclusive); diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 5b1ef7d6ca..6615c51ec5 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -64,6 +64,7 @@ public: void popup_centered(const Size2 &p_size = Size2()); void popup_centered_minsize(const Size2 &p_minsize = Size2()); void set_as_minsize(); + void popup_centered_clamped(const Size2 &p_size = Size2(), float p_fallback_ratio = 0.75); virtual void popup(const Rect2 &p_bounds = Rect2()); virtual String get_configuration_warning() const; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 82d6e6480e..2cac345dae 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -31,6 +31,7 @@ #include "popup_menu.h" #include "core/os/input.h" #include "core/os/keyboard.h" +#include "core/os/os.h" #include "core/print_string.h" #include "core/translation.h" @@ -54,9 +55,11 @@ Size2 PopupMenu::get_minimum_size() const { Ref<Font> font = get_font("font"); float max_w = 0; + float icon_w = 0; int font_h = font->get_height(); - int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()); + int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation; int accel_max_w = 0; + bool has_check = false; for (int i = 0; i < items.size(); i++) { @@ -65,8 +68,7 @@ Size2 PopupMenu::get_minimum_size() const { Size2 icon_size = items[i].icon->get_size(); size.height = MAX(icon_size.height, font_h); - size.width += icon_size.width; - size.width += hseparation; + icon_w = MAX(icon_size.width + hseparation, icon_w); } else { size.height = font_h; @@ -74,10 +76,8 @@ Size2 PopupMenu::get_minimum_size() const { size.width += items[i].h_ofs; - if (items[i].checkable_type) { - - size.width += check_w + hseparation; - } + if (items[i].checkable_type) + has_check = true; String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text; size.width += font->get_string_size(text).width; @@ -91,16 +91,17 @@ Size2 PopupMenu::get_minimum_size() const { accel_max_w = MAX(accel_w, accel_max_w); } - if (items[i].submenu != "") { - + if (items[i].submenu != "") size.width += get_icon("submenu")->get_width(); - } - minsize.height += size.height; max_w = MAX(max_w, size.width); + + minsize.height += size.height; } - minsize.width += max_w + accel_max_w; + minsize.width += max_w + icon_w + accel_max_w; + if (has_check) + minsize.width += check_w; return minsize; } @@ -147,10 +148,10 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const { void PopupMenu::_activate_submenu(int over) { Node *n = get_node(items[over].submenu); - ERR_EXPLAIN("item subnode does not exist: " + items[over].submenu); + ERR_EXPLAIN("Item subnode does not exist: " + items[over].submenu); ERR_FAIL_COND(!n); Popup *pm = Object::cast_to<Popup>(n); - ERR_EXPLAIN("item subnode is not a Popup: " + items[over].submenu); + ERR_EXPLAIN("Item subnode is not a Popup: " + items[over].submenu); ERR_FAIL_COND(!pm); if (pm->is_visible_in_tree()) return; //already visible! @@ -159,13 +160,14 @@ void PopupMenu::_activate_submenu(int over) { Rect2 pr(p, get_size()); Ref<StyleBox> style = get_stylebox("panel"); - Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y); + Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y) * get_global_transform().get_scale(); Size2 size = pm->get_size(); // fix pos if (pos.x + size.width > get_viewport_rect().size.width) pos.x = p.x - size.width; pm->set_position(pos); + pm->set_scale(get_global_transform().get_scale()); pm->popup(); PopupMenu *pum = Object::cast_to<PopupMenu>(pm); @@ -196,11 +198,11 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) { int vseparation = get_constant("vseparation"); Ref<Font> font = get_font("font"); - float dy = (vseparation + font->get_height()) * 3 * p_factor; + float dy = (vseparation + font->get_height()) * 3 * p_factor * get_global_transform().get_scale().y; if (dy > 0 && global_y < 0) dy = MIN(dy, -global_y - 1); - else if (dy < 0 && global_y + get_size().y > get_viewport_rect().size.y) - dy = -MIN(-dy, global_y + get_size().y - get_viewport_rect().size.y - 1); + else if (dy < 0 && global_y + get_size().y * get_global_transform().get_scale().y > get_viewport_rect().size.y) + dy = -MIN(-dy, global_y + get_size().y * get_global_transform().get_scale().y - get_viewport_rect().size.y - 1); set_position(get_position() + Vector2(0, dy)); Ref<InputEventMouseMotion> ie; @@ -239,7 +241,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { for (int i = search_from; i >= 0; i--) { - if (i < 0 || i >= items.size()) + if (i >= items.size()) continue; if (!items[i].separator && !items[i].disabled) { @@ -289,7 +291,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { case BUTTON_WHEEL_DOWN: { - if (get_global_position().y + get_size().y > get_viewport_rect().size.y) { + if (get_global_position().y + get_size().y * get_global_transform().get_scale().y > get_viewport_rect().size.y) { _scroll(-b->get_factor(), b->get_position()); } } break; @@ -354,7 +356,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { } int over = _get_mouse_over(m->get_position()); - int id = (over < 0 || items[over].separator || items[over].disabled) ? -1 : (items[over].ID >= 0 ? items[over].ID : over); + int id = (over < 0 || items[over].separator || items[over].disabled) ? -1 : (items[over].id >= 0 ? items[over].id : over); if (id < 0) { mouse_over = -1; @@ -379,6 +381,43 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position()); } } + + Ref<InputEventKey> k = p_event; + + if (allow_search && k.is_valid() && k->get_unicode()) { + + uint64_t now = OS::get_singleton()->get_ticks_msec(); + uint64_t diff = now - search_time_msec; + uint64_t max_interval = uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000)); + search_time_msec = now; + + if (diff > max_interval) { + search_string = ""; + } + + if (String::chr(k->get_unicode()) != search_string) + search_string += String::chr(k->get_unicode()); + + for (int i = mouse_over + 1; i <= items.size(); i++) { + if (i == items.size()) { + if (mouse_over <= 0) + break; + else + i = 0; + } + + if (i == mouse_over) + break; + + if (items[i].text.findn(search_string) == 0) { + mouse_over = i; + emit_signal("id_focused", i); + update(); + accept_event(); + break; + } + } + } } bool PopupMenu::has_point(const Point2 &p_point) const { @@ -415,7 +454,6 @@ void PopupMenu::_notification(int p_what) { minimum_size_changed(); update(); - } break; case NOTIFICATION_DRAW: { @@ -443,15 +481,31 @@ void PopupMenu::_notification(int p_what) { Color font_color_hover = get_color("font_color_hover"); float font_h = font->get_height(); + // Add the check and the wider icon to the offset of all items. + float icon_ofs = 0.0; + bool has_check = false; + for (int i = 0; i < items.size(); i++) { + + if (!items[i].icon.is_null()) + icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs); + + if (items[i].checkable_type) + has_check = true; + } + if (icon_ofs > 0.0) + icon_ofs += hseparation; + + float check_ofs = 0.0; + if (has_check) + check_ofs = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation; + for (int i = 0; i < items.size(); i++) { if (i > 0) ofs.y += vseparation; Point2 item_ofs = ofs; - float h; Size2 icon_size; - - Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1); + float h; if (!items[i].icon.is_null()) { @@ -489,16 +543,15 @@ void PopupMenu::_notification(int p_what) { } } + Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1); + if (items[i].checkable_type) { Texture *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr(); icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color); - item_ofs.x += icon->get_width() + hseparation; } if (!items[i].icon.is_null()) { - items[i].icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); - item_ofs.x += items[i].icon->get_width(); - item_ofs.x += hseparation; + items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); } if (items[i].submenu != "") { @@ -514,21 +567,21 @@ void PopupMenu::_notification(int p_what) { } } else { + item_ofs.x += icon_ofs + check_ofs; font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color)); } if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { //accelerator - String text = _get_accel_text(i); - item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text).width; - font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, i == mouse_over ? font_color_hover : font_color_accel); + String text2 = _get_accel_text(i); + item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width; + font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel); } items.write[i]._ofs_cache = ofs.y; ofs.y += h; } - } break; case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { @@ -576,93 +629,93 @@ void PopupMenu::_notification(int p_what) { } } -void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) { +void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { Item item; item.icon = p_icon; item.text = p_label; item.xl_text = tr(p_label); item.accel = p_accel; - item.ID = p_ID; + item.id = p_id; items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_item(const String &p_label, int p_ID, uint32_t p_accel) { +void PopupMenu::add_item(const String &p_label, int p_id, uint32_t p_accel) { Item item; item.text = p_label; item.xl_text = tr(p_label); item.accel = p_accel; - item.ID = p_ID; + item.id = p_id == -1 ? items.size() : p_id; items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_ID) { +void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) { Item item; item.text = p_label; item.xl_text = tr(p_label); - item.ID = p_ID; + item.id = p_id; item.submenu = p_submenu; items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) { +void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { Item item; item.icon = p_icon; item.text = p_label; item.xl_text = tr(p_label); item.accel = p_accel; - item.ID = p_ID; + item.id = p_id; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel) { +void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) { Item item; item.text = p_label; item.xl_text = tr(p_label); item.accel = p_accel; - item.ID = p_ID; + item.id = p_id == -1 ? items.size() : p_id; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p_accel) { +void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p_accel) { - add_check_item(p_label, p_ID, p_accel); + add_check_item(p_label, p_id, p_accel); items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } -void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) { +void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { - add_icon_check_item(p_icon, p_label, p_ID, p_accel); + add_icon_check_item(p_icon, p_label, p_id, p_accel); items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } -void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { +void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { ERR_FAIL_COND(p_shortcut.is_null()); _ref_shortcut(p_shortcut); Item item; - item.ID = p_ID; + item.id = p_id; item.icon = p_icon; item.shortcut = p_shortcut; item.shortcut_is_global = p_global; @@ -671,14 +724,14 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut minimum_size_changed(); } -void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { +void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { ERR_FAIL_COND(p_shortcut.is_null()); _ref_shortcut(p_shortcut); Item item; - item.ID = p_ID; + item.id = p_id; item.shortcut = p_shortcut; item.shortcut_is_global = p_global; items.push_back(item); @@ -686,14 +739,14 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_g minimum_size_changed(); } -void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { +void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { ERR_FAIL_COND(p_shortcut.is_null()); _ref_shortcut(p_shortcut); Item item; - item.ID = p_ID; + item.id = p_id; item.shortcut = p_shortcut; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; item.icon = p_icon; @@ -703,14 +756,14 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<Sh minimum_size_changed(); } -void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { +void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { ERR_FAIL_COND(p_shortcut.is_null()); _ref_shortcut(p_shortcut); Item item; - item.ID = p_ID; + item.id = p_id; item.shortcut = p_shortcut; item.shortcut_is_global = p_global; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; @@ -719,21 +772,21 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo minimum_size_changed(); } -void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { +void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { - add_check_shortcut(p_shortcut, p_ID, p_global); + add_check_shortcut(p_shortcut, p_id, p_global); items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } -void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_ID, uint32_t p_accel) { +void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, uint32_t p_accel) { Item item; item.text = p_label; item.xl_text = tr(p_label); item.accel = p_accel; - item.ID = p_ID; + item.id = p_id; item.max_states = p_max_states; item.state = p_default_state; items.push_back(item); @@ -767,10 +820,10 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { update(); minimum_size_changed(); } -void PopupMenu::set_item_id(int p_idx, int p_ID) { +void PopupMenu::set_item_id(int p_idx, int p_id) { ERR_FAIL_INDEX(p_idx, items.size()); - items.write[p_idx].ID = p_ID; + items.write[p_idx].id = p_id; update(); minimum_size_changed(); @@ -866,14 +919,14 @@ bool PopupMenu::is_item_checked(int p_idx) const { int PopupMenu::get_item_id(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, items.size(), 0); - return items[p_idx].ID; + return items[p_idx].id; } -int PopupMenu::get_item_index(int p_ID) const { +int PopupMenu::get_item_index(int p_id) const { for (int i = 0; i < items.size(); i++) { - if (items[i].ID == p_ID) + if (items[i].id == p_id) return i; } @@ -1062,7 +1115,7 @@ void PopupMenu::activate_item(int p_item) { ERR_FAIL_INDEX(p_item, items.size()); ERR_FAIL_COND(items[p_item].separator); - int id = items[p_item].ID >= 0 ? items[p_item].ID : p_item; + int id = items[p_item].id >= 0 ? items[p_item].id : p_item; //hide all parent PopupMenus Node *next = get_parent(); @@ -1124,7 +1177,7 @@ void PopupMenu::add_separator(const String &p_text) { Item sep; sep.separator = true; - sep.ID = -1; + sep.id = -1; if (p_text != String()) { sep.text = p_text; sep.xl_text = tr(p_text); @@ -1274,6 +1327,16 @@ float PopupMenu::get_submenu_popup_delay() const { return submenu_timer->get_wait_time(); } +void PopupMenu::set_allow_search(bool p_allow) { + + allow_search = p_allow; +} + +bool PopupMenu::get_allow_search() const { + + return allow_search; +} + void PopupMenu::set_hide_on_window_lose_focus(bool p_enabled) { hide_on_window_lose_focus = p_enabled; @@ -1392,6 +1455,9 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hide_on_window_lose_focus", "enable"), &PopupMenu::set_hide_on_window_lose_focus); ClassDB::bind_method(D_METHOD("is_hide_on_window_lose_focus"), &PopupMenu::is_hide_on_window_lose_focus); + ClassDB::bind_method(D_METHOD("set_allow_search", "allow"), &PopupMenu::set_allow_search); + ClassDB::bind_method(D_METHOD("get_allow_search"), &PopupMenu::get_allow_search); + ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); @@ -1399,9 +1465,10 @@ void PopupMenu::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "submenu_popup_delay"), "set_submenu_popup_delay", "get_submenu_popup_delay"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_search"), "set_allow_search", "get_allow_search"); - ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID"))); - ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "ID"))); + ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index"))); } @@ -1420,6 +1487,10 @@ PopupMenu::PopupMenu() { initial_button_mask = 0; during_grabbed_click = false; + allow_search = false; + search_time_msec = 0; + search_string = ""; + set_focus_mode(FOCUS_ALL); set_as_toplevel(true); set_hide_on_item_selection(true); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index a06a17c9fe..babdd21281 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -55,7 +55,7 @@ class PopupMenu : public Popup { int state; bool separator; bool disabled; - int ID; + int id; Variant metadata; String submenu; String tooltip; @@ -112,6 +112,10 @@ class PopupMenu : public Popup { void _ref_shortcut(Ref<ShortCut> p_sc); void _unref_shortcut(Ref<ShortCut> p_sc); + bool allow_search; + uint64_t search_time_msec; + String search_string; + protected: virtual bool has_point(const Point2 &p_point) const; @@ -120,26 +124,26 @@ protected: static void _bind_methods(); public: - void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID = -1, uint32_t p_accel = 0); - void add_item(const String &p_label, int p_ID = -1, uint32_t p_accel = 0); - void add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID = -1, uint32_t p_accel = 0); - void add_check_item(const String &p_label, int p_ID = -1, uint32_t p_accel = 0); - void add_radio_check_item(const String &p_label, int p_ID = -1, uint32_t p_accel = 0); - void add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID = -1, uint32_t p_accel = 0); - void add_submenu_item(const String &p_label, const String &p_submenu, int p_ID = -1); - - void add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); - void add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); - void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); - void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); - void add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); - - void add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_ID = -1, uint32_t p_accel = 0); + void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0); + void add_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0); + void add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0); + void add_check_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0); + void add_radio_check_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0); + void add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0); + void add_submenu_item(const String &p_label, const String &p_submenu, int p_id = -1); + + void add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + + void add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id = -1, uint32_t p_accel = 0); void set_item_text(int p_idx, const String &p_text); void set_item_icon(int p_idx, const Ref<Texture> &p_icon); void set_item_checked(int p_idx, bool p_checked); - void set_item_id(int p_idx, int p_ID); + void set_item_id(int p_idx, int p_id); void set_item_accelerator(int p_idx, uint32_t p_accel); void set_item_metadata(int p_idx, const Variant &p_meta); void set_item_disabled(int p_idx, bool p_disabled); @@ -161,7 +165,7 @@ public: Ref<Texture> get_item_icon(int p_idx) const; bool is_item_checked(int p_idx) const; int get_item_id(int p_idx) const; - int get_item_index(int p_ID) const; + int get_item_index(int p_id) const; uint32_t get_item_accelerator(int p_idx) const; Variant get_item_metadata(int p_idx) const; bool is_item_disabled(int p_idx) const; @@ -206,6 +210,9 @@ public: void set_submenu_popup_delay(float p_time); float get_submenu_popup_delay() const; + void set_allow_search(bool p_allow); + bool get_allow_search() const; + virtual void popup(const Rect2 &p_bounds = Rect2()); void set_hide_on_window_lose_focus(bool p_enabled); diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index fc5d56237a..264eda4035 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -39,9 +39,12 @@ Size2 ProgressBar::get_minimum_size() const { Size2 minimum_size = bg->get_minimum_size(); minimum_size.height = MAX(minimum_size.height, fg->get_minimum_size().height); minimum_size.width = MAX(minimum_size.width, fg->get_minimum_size().width); - //if (percent_visible) { this is needed, else the progressbar will collapse - minimum_size.height = MAX(minimum_size.height, bg->get_minimum_size().height + font->get_height()); - //} + if (percent_visible) { + minimum_size.height = MAX(minimum_size.height, bg->get_minimum_size().height + font->get_height()); + } else { // this is needed, else the progressbar will collapse + minimum_size.width = MAX(minimum_size.width, 1); + minimum_size.height = MAX(minimum_size.height, 1); + } return minimum_size; } @@ -92,5 +95,6 @@ void ProgressBar::_bind_methods() { ProgressBar::ProgressBar() { set_v_size_flags(0); + set_step(0.01); percent_visible = true; } diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h index d091c983b1..6157183e0f 100644 --- a/scene/gui/progress_bar.h +++ b/scene/gui/progress_bar.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index e862743934..d00acaf08a 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -63,7 +63,7 @@ void Range::Shared::emit_value_changed() { void Range::_changed_notify(const char *p_what) { - emit_signal("changed", shared->val); + emit_signal("changed"); update(); _change_notify(p_what); } @@ -79,6 +79,7 @@ void Range::Shared::emit_changed(const char *p_what) { } void Range::set_value(double p_val) { + if (shared->step > 0) p_val = Math::round(p_val / shared->step) * shared->step; @@ -303,22 +304,27 @@ bool Range::is_ratio_exp() const { } void Range::set_allow_greater(bool p_allow) { + shared->allow_greater = p_allow; } bool Range::is_greater_allowed() const { + return shared->allow_greater; } void Range::set_allow_lesser(bool p_allow) { + shared->allow_lesser = p_allow; } bool Range::is_lesser_allowed() const { + return shared->allow_lesser; } Range::Range() { + shared = memnew(Shared); shared->min = 0; shared->max = 100; diff --git a/scene/gui/range.h b/scene/gui/range.h index 58f15c8aa8..cf0add8c89 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp index e96e5afb2a..553e133946 100644 --- a/scene/gui/reference_rect.cpp +++ b/scene/gui/reference_rect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/reference_rect.h b/scene/gui/reference_rect.h index 9fad1a06b0..de3ccaeeca 100644 --- a/scene/gui/reference_rect.h +++ b/scene/gui/reference_rect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index db890bf1c8..8891f679ee 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -307,6 +307,13 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & switch (it->type) { + case ITEM_ALIGN: { + + ItemAlign *align_it = static_cast<ItemAlign *>(it); + + align = align_it->align; + + } break; case ITEM_TEXT: { ItemText *text = static_cast<ItemText *>(it); @@ -544,7 +551,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & Vector2 draw_ofs = Point2(wofs, y); Color font_color_shadow = get_color("font_color_shadow"); bool use_outline = get_constant("shadow_as_outline"); - Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); + Point2 shadow_ofs2(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); if (p_mode == PROCESS_CACHE) { @@ -568,7 +575,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < frame->lines.size(); i++) { - _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs); + _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs2); table->columns.write[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width); table->columns.write[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width); } @@ -592,7 +599,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & //assign actual widths for (int i = 0; i < table->columns.size(); i++) { table->columns.write[i].width = table->columns[i].min_width; - if (table->columns[i].expand) + if (table->columns[i].expand && total_ratio > 0) table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; table->total_width += table->columns[i].width + hseparation; } @@ -641,7 +648,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < frame->lines.size(); i++) { int ly = 0; - _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs); + _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs2); frame->lines.write[i].height_cache = ly; //actual height frame->lines.write[i].height_accum_cache = ly; //actual height } @@ -674,9 +681,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & if (visible) { if (p_mode == PROCESS_DRAW) { - nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs); + nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs2); } else if (p_mode == PROCESS_POINTER) { - _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs, p_click_pos, r_click_item, r_click_char, r_outside); + _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs2, p_click_pos, r_click_item, r_click_char, r_outside); if (r_click_item && *r_click_item) { RETURN; // exit early } @@ -711,7 +718,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & } break; - default: {} + default: { + } } Item *itp = it; @@ -752,6 +760,8 @@ void RichTextLabel::_scroll_changed(double) { else scroll_following = false; + scroll_updated = true; + update(); } @@ -777,7 +787,6 @@ void RichTextLabel::_update_scroll() { main->first_invalid_line = 0; //invalidate ALL _validate_line_caches(main); } - scroll_updated = true; } void RichTextLabel::_notification(int p_what) { @@ -1133,18 +1142,19 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { } Variant meta; - if (item && !outside && _find_meta(item, &meta)) { - if (meta_hovering != item) { + ItemMeta *item_meta; + if (item && !outside && _find_meta(item, &meta, &item_meta)) { + if (meta_hovering != item_meta) { if (meta_hovering) { emit_signal("meta_hover_ended", current_meta); } - meta_hovering = static_cast<ItemMeta *>(item); + meta_hovering = item_meta; current_meta = meta; emit_signal("meta_hover_started", meta); } } else if (meta_hovering) { - emit_signal("meta_hover_ended", current_meta); meta_hovering = NULL; + emit_signal("meta_hover_ended", current_meta); current_meta = false; } } @@ -1269,7 +1279,7 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) { return false; } -bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta) { +bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item) { Item *item = p_item; @@ -1280,6 +1290,8 @@ bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta) { ItemMeta *meta = static_cast<ItemMeta *>(item); if (r_meta) *r_meta = meta->meta; + if (r_item) + *r_item = meta; return true; } @@ -1406,9 +1418,13 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) if (p_enter) current = p_item; - if (p_ensure_newline && current_frame->lines[current_frame->lines.size() - 1].from) { - _invalidate_current_line(current_frame); - current_frame->lines.resize(current_frame->lines.size() + 1); + if (p_ensure_newline) { + Item *from = current_frame->lines[current_frame->lines.size() - 1].from; + // only create a new line for Item types that generate content/layout, ignore those that represent formatting/styling + if (from && from->type != ITEM_FONT && from->type != ITEM_COLOR && from->type != ITEM_UNDERLINE && from->type != ITEM_STRIKETHROUGH) { + _invalidate_current_line(current_frame); + current_frame->lines.resize(current_frame->lines.size() + 1); + } } if (current_frame->lines[current_frame->lines.size() - 1].from == NULL) { @@ -2001,7 +2017,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p Item *it = main; int charidx = 0; - if (p_from_selection && selection.active && selection.enabled) { + if (p_from_selection && selection.active) { it = selection.to; charidx = selection.to_char + 1; } @@ -2331,6 +2347,7 @@ RichTextLabel::RichTextLabel() { tab_size = 4; default_align = ALIGN_LEFT; underline_meta = true; + meta_hovering = NULL; override_selected_font_color = false; scroll_visible = false; diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 7c30738e2d..114c6103e2 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -285,7 +285,7 @@ private: Color _find_color(Item *p_item, const Color &p_default_color); bool _find_underline(Item *p_item); bool _find_strikethrough(Item *p_item); - bool _find_meta(Item *p_item, Variant *r_meta); + bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = NULL); void _update_scroll(); void _scroll_changed(double); diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 0e68476439..686d1c96cc 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -53,29 +53,19 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) { if (b.is_valid()) { accept_event(); - if (b->get_button_index() == 5 && b->is_pressed()) { + if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) { - /* - if (orientation==VERTICAL) - set_val( get_val() + get_page() / 4.0 ); - else - */ set_value(get_value() + get_page() / 4.0); accept_event(); } - if (b->get_button_index() == 4 && b->is_pressed()) { + if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) { - /* - if (orientation==HORIZONTAL) - set_val( get_val() - get_page() / 4.0 ); - else - */ set_value(get_value() - get_page() / 4.0); accept_event(); } - if (b->get_button_index() != 1) + if (b->get_button_index() != BUTTON_LEFT) return; if (b->is_pressed()) { diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h index cde4120cdb..5ceabfc06b 100644 --- a/scene/gui/scroll_bar.h +++ b/scene/gui/scroll_bar.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 9c22a049b8..a1034937b5 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -88,13 +88,16 @@ void ScrollContainer::_cancel_drag() { void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { + double prev_v_scroll = v_scroll->get_value(); + double prev_h_scroll = h_scroll->get_value(); + Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { // only horizontal is enabled, scroll horizontally - if (h_scroll->is_visible() && !v_scroll->is_visible()) { + if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) { h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor()); } else if (v_scroll->is_visible_in_tree()) { v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() / 8 * mb->get_factor()); @@ -103,7 +106,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) { // only horizontal is enabled, scroll horizontally - if (h_scroll->is_visible() && !v_scroll->is_visible()) { + if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) { h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor()); } else if (v_scroll->is_visible()) { v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() / 8 * mb->get_factor()); @@ -122,6 +125,9 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + if (!OS::get_singleton()->has_touchscreen_ui_hint()) return; @@ -204,6 +210,9 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8); } } + + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed } void ScrollContainer::_update_scrollbar_position() { @@ -271,7 +280,6 @@ void ScrollContainer::_notification(int p_what) { } if (!scroll_v || (!v_scroll->is_visible_in_tree() && c->get_v_size_flags() & SIZE_EXPAND)) { r.position.y = 0; - r.size.height = size.height; if (c->get_v_size_flags() & SIZE_EXPAND) r.size.height = MAX(size.height, minsize.height); else @@ -369,8 +377,10 @@ void ScrollContainer::update_scrollbars() { Ref<StyleBox> sb = get_stylebox("bg"); size -= sb->get_minimum_size(); - Size2 hmin = h_scroll->get_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); + Size2 hmin; + Size2 vmin; + if (scroll_h) hmin = h_scroll->get_combined_minimum_size(); + if (scroll_v) vmin = v_scroll->get_combined_minimum_size(); Size2 min = child_max_size; diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index abef80294a..2ab169f4d0 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp index cd0b06da81..a717420b9b 100644 --- a/scene/gui/separator.cpp +++ b/scene/gui/separator.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/separator.h b/scene/gui/separator.h index 7949c7ca9b..54ad9b5bb5 100644 --- a/scene/gui/separator.h +++ b/scene/gui/separator.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp index 6fcf96f611..400fdca082 100644 --- a/scene/gui/shortcut.cpp +++ b/scene/gui/shortcut.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h index 7613a24e43..df0623ed50 100644 --- a/scene/gui/shortcut.h +++ b/scene/gui/shortcut.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 147c0518ec..b777e77bc3 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,8 +34,15 @@ Size2 Slider::get_minimum_size() const { Ref<StyleBox> style = get_stylebox("slider"); - Size2i ms = style->get_minimum_size() + style->get_center_size(); - return ms; + Size2i ss = style->get_minimum_size() + style->get_center_size(); + + Ref<Texture> grabber = get_icon("grabber"); + Size2i rs = grabber->get_size(); + + if (orientation == HORIZONTAL) + return Size2i(ss.width, MAX(ss.height, rs.height)); + else + return Size2i(MAX(ss.width, rs.width), ss.height); } void Slider::_gui_input(Ref<InputEvent> p_event) { @@ -134,7 +141,11 @@ void Slider::_gui_input(Ref<InputEvent> p_event) { void Slider::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_THEME_CHANGED: { + minimum_size_changed(); + update(); + } break; case NOTIFICATION_MOUSE_ENTER: { mouse_inside = true; @@ -284,6 +295,7 @@ Slider::Slider(Orientation p_orientation) { mouse_inside = false; grab.active = false; ticks = 0; + ticks_on_borders = false; custom_step = -1; editable = true; scrollable = true; diff --git a/scene/gui/slider.h b/scene/gui/slider.h index 4d02348159..d0ab7baecf 100644 --- a/scene/gui/slider.h +++ b/scene/gui/slider.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 4f43bb0581..e778af3ceb 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -277,6 +277,7 @@ SpinBox::SpinBox() { add_child(line_edit); line_edit->set_anchors_and_margins_preset(Control::PRESET_WIDE); + line_edit->set_mouse_filter(MOUSE_FILTER_PASS); //connect("value_changed",this,"_value_changed"); line_edit->connect("text_entered", this, "_text_entered", Vector<Variant>(), CONNECT_DEFERRED); line_edit->connect("focus_exited", this, "_line_edit_focus_exit", Vector<Variant>(), CONNECT_DEFERRED); diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 6425af7158..49dc6d950c 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index c3265d3ed5..e5d1844d39 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -164,34 +164,35 @@ void SplitContainer::_notification(int p_what) { _resort(); } break; - case NOTIFICATION_MOUSE_ENTER: { - - mouse_inside = true; - update(); - } break; case NOTIFICATION_MOUSE_EXIT: { mouse_inside = false; - update(); + if (get_constant("autohide")) + update(); } break; case NOTIFICATION_DRAW: { if (!_getch(0) || !_getch(1)) return; - if (collapsed || (!mouse_inside && get_constant("autohide"))) + if (collapsed || (!dragging && !mouse_inside && get_constant("autohide"))) + return; + + if (dragger_visibility != DRAGGER_VISIBLE) return; int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_constant("separation") : 0; Ref<Texture> tex = get_icon("grabber"); Size2 size = get_size(); - if (dragger_visibility == DRAGGER_VISIBLE) { - if (vertical) - draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2)); - else - draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2)); - } + if (vertical) + draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2)); + else + draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2)); + } break; + case NOTIFICATION_THEME_CHANGED: { + + minimum_size_changed(); } break; } } @@ -237,7 +238,23 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm = p_event; - if (mm.is_valid() && dragging) { + if (mm.is_valid()) { + + bool mouse_inside_state = false; + if (vertical) + mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + get_constant("separation"); + else + mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_constant("separation"); + + if (mouse_inside != mouse_inside_state) { + + mouse_inside = mouse_inside_state; + if (get_constant("autohide")) + update(); + } + + if (!dragging) + return; split_offset = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from); should_clamp_split_offset = true; diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index f8b3343aa8..97838e19a3 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -35,7 +35,7 @@ class SplitContainer : public Container { - GDCLASS(SplitContainer, Container) + GDCLASS(SplitContainer, Container); public: enum DraggerVisibility { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 4c354768fe..39c76e6646 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -86,8 +86,8 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { emit_signal("pre_popup_pressed"); Vector2 popup_pos = get_global_position(); - popup_pos.x += size.width - popup->get_size().width; - popup_pos.y += menu->get_height(); + popup_pos.x += size.width * get_global_transform().get_scale().x - popup->get_size().width * popup->get_global_transform().get_scale().x; + popup_pos.y += menu->get_height() * get_global_transform().get_scale().y; popup->set_global_position(popup_pos); popup->popup(); @@ -127,6 +127,9 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { // Activate the clicked tab. pos.x -= tabs_ofs_cache; for (int i = first_tab_cache; i <= last_tab_cache; i++) { + if (get_tab_hidden(i)) { + continue; + } int tab_width = _get_tab_width(i); if (pos.x < tab_width) { if (!get_tab_disabled(i)) { @@ -143,6 +146,11 @@ void TabContainer::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_TRANSLATION_CHANGED: { + + minimum_size_changed(); + update(); + } break; case NOTIFICATION_RESIZED: { Vector<Control *> tabs = _get_tabs(); @@ -178,7 +186,6 @@ void TabContainer::_notification(int p_what) { first_tab_cache--; } } break; - case NOTIFICATION_DRAW: { RID canvas = get_canvas_item(); @@ -216,6 +223,9 @@ void TabContainer::_notification(int p_what) { // Check if all tabs would fit into the header area. int all_tabs_width = 0; for (int i = 0; i < tabs.size(); i++) { + if (get_tab_hidden(i)) { + continue; + } int tab_width = _get_tab_width(i); all_tabs_width += tab_width; @@ -241,6 +251,9 @@ void TabContainer::_notification(int p_what) { all_tabs_width = 0; Vector<int> tab_widths; for (int i = first_tab_cache; i < tabs.size(); i++) { + if (get_tab_hidden(i)) { + continue; + } int tab_width = _get_tab_width(i); if (all_tabs_width + tab_width > header_width && tab_widths.size() > 0) break; @@ -267,6 +280,9 @@ void TabContainer::_notification(int p_what) { // Draw all visible tabs. int x = 0; for (int i = 0; i < tab_widths.size(); i++) { + if (get_tab_hidden(i)) { + continue; + } Ref<StyleBox> tab_style; Color font_color; if (get_tab_disabled(i + first_tab_cache)) { @@ -338,6 +354,8 @@ void TabContainer::_notification(int p_what) { } } break; case NOTIFICATION_THEME_CHANGED: { + + minimum_size_changed(); call_deferred("_on_theme_changed"); //wait until all changed theme } break; } @@ -353,7 +371,7 @@ int TabContainer::_get_tab_width(int p_index) const { ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0); Control *control = Object::cast_to<Control>(_get_tabs()[p_index]); - if (!control || control->is_set_as_toplevel()) + if (!control || control->is_set_as_toplevel() || get_tab_hidden(p_index)) return 0; // Get the width of the text displayed on the tab. @@ -718,6 +736,7 @@ void TabContainer::set_tab_title(int p_tab, const String &p_title) { Control *child = _get_tab(p_tab); ERR_FAIL_COND(!child); child->set_meta("_tab_name", p_title); + update(); } String TabContainer::get_tab_title(int p_tab) const { @@ -735,6 +754,7 @@ void TabContainer::set_tab_icon(int p_tab, const Ref<Texture> &p_icon) { Control *child = _get_tab(p_tab); ERR_FAIL_COND(!child); child->set_meta("_tab_icon", p_icon); + update(); } Ref<Texture> TabContainer::get_tab_icon(int p_tab) const { @@ -764,6 +784,36 @@ bool TabContainer::get_tab_disabled(int p_tab) const { return false; } +void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) { + + Control *child = _get_tab(p_tab); + ERR_FAIL_COND(!child); + child->set_meta("_tab_hidden", p_hidden); + update(); + for (int i = 0; i < get_tab_count(); i++) { + int try_tab = (p_tab + 1 + i) % get_tab_count(); + if (get_tab_disabled(try_tab) || get_tab_hidden(try_tab)) { + continue; + } + + set_current_tab(try_tab); + return; + } + + //assumed no other tab can be switched to, just hide + child->hide(); +} + +bool TabContainer::get_tab_hidden(int p_tab) const { + + Control *child = _get_tab(p_tab); + ERR_FAIL_COND_V(!child, false); + if (child->has_meta("_tab_hidden")) + return child->get_meta("_tab_hidden"); + else + return false; +} + void TabContainer::get_translatable_strings(List<String> *p_strings) const { Vector<Control *> tabs = _get_tabs(); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 8a3c9d2bb2..f7a9fb64fd 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -96,6 +96,9 @@ public: void set_tab_disabled(int p_tab, bool p_disabled); bool get_tab_disabled(int p_tab) const; + void set_tab_hidden(int p_tab, bool p_hidden); + bool get_tab_hidden(int p_tab) const; + int get_tab_count() const; void set_current_tab(int p_current); int get_current_tab() const; diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 4fe4271368..36571cc878 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -222,6 +222,10 @@ void Tabs::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_TRANSLATION_CHANGED: { + minimum_size_changed(); + update(); + } break; case NOTIFICATION_MOUSE_EXIT: { rb_hover = -1; cb_hover = -1; @@ -232,7 +236,6 @@ void Tabs::_notification(int p_what) { _update_cache(); _ensure_no_over_offset(); ensure_tab_visible(current); - } break; case NOTIFICATION_DRAW: { _update_cache(); @@ -394,7 +397,6 @@ void Tabs::_notification(int p_what) { } else { buttons_visible = false; } - } break; } } diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index a98744b804..7c54f1acf2 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index b1849b7e69..36d7dad1d3 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -50,7 +50,7 @@ inline bool _is_symbol(CharType c) { static bool _is_text_char(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; + return !is_symbol(c); } static bool _is_whitespace(CharType c) { @@ -104,6 +104,13 @@ static CharType _get_right_pair_symbol(CharType c) { return 0; } +static int _find_first_non_whitespace_column_of_line(const String &line) { + int left = 0; + while (left < line.length() && _is_whitespace(line[left])) + left++; + return left; +} + void TextEdit::Text::set_font(const Ref<Font> &p_font) { font = p_font; @@ -292,6 +299,7 @@ void TextEdit::Text::insert(int p_at, const String &p_text) { line.marked = false; line.safe = false; line.breakpoint = false; + line.bookmark = false; line.hidden = false; line.width_cache = -1; line.wrap_amount_cache = -1; @@ -346,10 +354,14 @@ void TextEdit::_update_scrollbars() { if (line_numbers) total_width += cache.line_number_w; - if (draw_breakpoint_gutter) { + if (draw_breakpoint_gutter || draw_bookmark_gutter) { total_width += cache.breakpoint_gutter_width; } + if (draw_info_gutter) { + total_width += cache.info_gutter_width; + } + if (draw_fold_gutter) { total_width += cache.fold_gutter_width; } @@ -394,6 +406,7 @@ void TextEdit::_update_scrollbars() { cursor.line_ofs = 0; cursor.wrap_ofs = 0; v_scroll->set_value(0); + v_scroll->set_max(0); v_scroll->hide(); } @@ -412,6 +425,7 @@ void TextEdit::_update_scrollbars() { cursor.x_ofs = 0; h_scroll->set_value(0); + h_scroll->set_max(0); h_scroll->hide(); } @@ -549,16 +563,17 @@ void TextEdit::_notification(int p_what) { MessageQueue::get_singleton()->push_call(this, "_cursor_changed_emit"); if (text_changed_dirty) MessageQueue::get_singleton()->push_call(this, "_text_changed_emit"); - update_wrap_at(); + _update_wrap_at(); } break; case NOTIFICATION_RESIZED: { _update_scrollbars(); - update_wrap_at(); + call_deferred("_update_wrap_at"); } break; case NOTIFICATION_THEME_CHANGED: { _update_caches(); + _update_wrap_at(); } break; case MainLoop::NOTIFICATION_WM_FOCUS_IN: { window_has_focus = true; @@ -589,18 +604,31 @@ void TextEdit::_notification(int p_what) { } } break; case NOTIFICATION_DRAW: { + + if (first_draw) { + //size may not be the final one, so attempts to ensure cursor was visible may have failed + adjust_viewport_to_cursor(); + first_draw = false; + } Size2 size = get_size(); if ((!has_focus() && !menu->has_focus()) || !window_has_focus) { draw_caret = false; } - if (draw_breakpoint_gutter) { + if (draw_breakpoint_gutter || draw_bookmark_gutter) { breakpoint_gutter_width = (get_row_height() * 55) / 100; cache.breakpoint_gutter_width = breakpoint_gutter_width; } else { cache.breakpoint_gutter_width = 0; } + if (draw_info_gutter) { + info_gutter_width = (get_row_height()); + cache.info_gutter_width = info_gutter_width; + } else { + cache.info_gutter_width = 0; + } + if (draw_fold_gutter) { fold_gutter_width = (get_row_height() * 55) / 100; cache.fold_gutter_width = fold_gutter_width; @@ -630,7 +658,7 @@ void TextEdit::_notification(int p_what) { RID ci = get_canvas_item(); VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true); - int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width; + int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width; int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT); //let's do it easy for now: cache.style_normal->draw(ci, Rect2(Point2(), size)); @@ -665,7 +693,7 @@ void TextEdit::_notification(int p_what) { bool brace_close_matching = false; bool brace_close_mismatch = false; - if (brace_matching_enabled) { + if (brace_matching_enabled && cursor.line >= 0 && cursor.line < text.size() && cursor.column >= 0) { if (cursor.column < text[cursor.line].length()) { //check for open @@ -802,10 +830,14 @@ void TextEdit::_notification(int p_what) { } Point2 cursor_pos; + int cursor_insert_offset_y = 0; // get the highlighted words String highlighted_text = get_selection_text(); + // check if highlighted words contains only whitespaces (tabs or spaces) + bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String(); + String line_num_padding = line_numbers_zero_padded ? "0" : " "; int cursor_wrap_index = get_cursor_wrap_index(); @@ -859,6 +891,9 @@ void TextEdit::_notification(int p_what) { const String &str = wrap_rows[line_wrap_index]; int indent_px = line_wrap_index != 0 ? get_indent_level(line) * cache.font->get_char_size(' ').width : 0; + if (indent_px >= wrap_at) { + indent_px = 0; + } if (line_wrap_index > 0) last_wrap_column += wrap_rows[line_wrap_index - 1].length(); @@ -929,6 +964,16 @@ void TextEdit::_notification(int p_what) { #endif } + // draw bookmark marker + if (text.is_bookmark(line)) { + if (draw_bookmark_gutter) { + int vertical_gap = (get_row_height() * 40) / 100; + int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100; + int marker_radius = get_row_height() - (vertical_gap * 2); + VisualServer::get_singleton()->canvas_item_add_circle(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 + marker_radius / 2, ofs_y + vertical_gap + marker_radius / 2), marker_radius, Color(cache.bookmark_color.r, cache.bookmark_color.g, cache.bookmark_color.b)); + } + } + // draw breakpoint marker if (text.is_breakpoint(line)) { if (draw_breakpoint_gutter) { @@ -941,10 +986,53 @@ void TextEdit::_notification(int p_what) { } } + // draw info icons + if (draw_info_gutter && text.has_info_icon(line)) { + int vertical_gap = (get_row_height() * 40) / 100; + int horizontal_gap = (cache.info_gutter_width * 30) / 100; + int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width; + + Ref<Texture> info_icon = text.get_info_icon(line); + // ensure the icon fits the gutter size + Size2i icon_size = info_icon->get_size(); + if (icon_size.width > cache.info_gutter_width - horizontal_gap) { + icon_size.width = cache.info_gutter_width - horizontal_gap; + } + if (icon_size.height > get_row_height() - horizontal_gap) { + icon_size.height = get_row_height() - horizontal_gap; + } + + Size2i icon_pos; + int xofs = horizontal_gap - (info_icon->get_width() / 4); + int yofs = vertical_gap - (info_icon->get_height() / 4); + icon_pos.x = gutter_left + xofs + ofs_x; + icon_pos.y = ofs_y + yofs; + + draw_texture_rect(info_icon, Rect2(icon_pos, icon_size)); + } + + // draw execution marker + if (executing_line == line) { + if (draw_breakpoint_gutter) { + int icon_extra_size = 4; + int vertical_gap = (get_row_height() * 40) / 100; + int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100; + int marker_height = get_row_height() - (vertical_gap * 2) + icon_extra_size; + int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2) + icon_extra_size; + cache.executing_icon->draw_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 - icon_extra_size / 2, ofs_y + vertical_gap - icon_extra_size / 2, marker_width, marker_height), false, Color(cache.executing_line_color.r, cache.executing_line_color.g, cache.executing_line_color.b)); + } else { +#ifdef TOOLS_ENABLED + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.executing_line_color); +#else + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.executing_line_color); +#endif + } + } + // draw fold markers if (draw_fold_gutter) { int horizontal_gap = (cache.fold_gutter_width * 30) / 100; - int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w; + int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w + cache.info_gutter_width; if (is_folded(line)) { int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2; int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2; @@ -964,7 +1052,7 @@ void TextEdit::_notification(int p_what) { fc = line_num_padding + fc; } - cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, yofs + cache.font->get_ascent()), fc, text.is_safe(line) ? cache.safe_line_number_color : cache.line_number_color); + cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.info_gutter_width + ofs_x, yofs + cache.font->get_ascent()), fc, text.is_safe(line) ? cache.safe_line_number_color : cache.line_number_color); } } @@ -1004,10 +1092,7 @@ void TextEdit::_notification(int p_what) { } if ((char_ofs + char_margin + char_w) >= xmargin_end) { - if (syntax_coloring) - continue; - else - break; + break; } bool in_search_result = false; @@ -1030,7 +1115,7 @@ void TextEdit::_notification(int p_what) { if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) { // draw the wrap indent offset highlight if (line_wrap_index != 0 && j == 0) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, (char_ofs + char_margin), get_row_height()), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, indent_px, get_row_height()), cache.current_line_color); } // if its the last char draw to end of the line if (j == str.length() - 1) { @@ -1058,7 +1143,7 @@ void TextEdit::_notification(int p_what) { VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color); } - if (highlight_all_occurrences) { + if (highlight_all_occurrences && !only_whitespaces_highlighted) { if (highlighted_text_col != -1) { // if we are at the end check for new word on same line @@ -1108,9 +1193,11 @@ void TextEdit::_notification(int p_what) { if (cursor.column == last_wrap_column + j && cursor.line == line && cursor_wrap_index == line_wrap_index) { cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y); + cursor_pos.y += (get_row_height() - cache.font->get_height()) / 2; if (insert_mode) { - cursor_pos.y += (get_row_height() - 3); + cursor_insert_offset_y = (cache.font->get_height() - 3); + cursor_pos.y += cursor_insert_offset_y; } int caret_w = (str[j] == '\t') ? cache.font->get_char_size(' ').width : char_w; @@ -1155,7 +1242,8 @@ void TextEdit::_notification(int p_what) { #else caret_w = (block_caret) ? caret_w : 2; #endif - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color); + + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, cache.font->get_height())), cache.caret_color); } } } @@ -1184,6 +1272,11 @@ void TextEdit::_notification(int p_what) { cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color); } + if (draw_spaces && str[j] == ' ') { + int yofs = (get_row_height() - cache.space_icon->get_height()) / 2; + cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color); + } + char_ofs += char_w; if (line_wrap_index == line_wrap_amount && j == str.length() - 1 && is_folded(line)) { @@ -1198,9 +1291,11 @@ void TextEdit::_notification(int p_what) { if (cursor.column == last_wrap_column + str.length() && cursor.line == line && cursor_wrap_index == line_wrap_index && (char_ofs + char_margin) >= xmargin_beg) { cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y); + cursor_pos.y += (get_row_height() - cache.font->get_height()) / 2; if (insert_mode) { - cursor_pos.y += (get_row_height() - 3); + cursor_insert_offset_y = cache.font->get_height() - 3; + cursor_pos.y += cursor_insert_offset_y; } if (ime_text.length() > 0) { int ofs = 0; @@ -1245,7 +1340,8 @@ void TextEdit::_notification(int p_what) { #else int caret_w = (block_caret) ? char_w : 2; #endif - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color); + + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, cache.font->get_height())), cache.caret_color); } } } @@ -1287,9 +1383,9 @@ void TextEdit::_notification(int p_what) { int th = h + csb->get_minimum_size().y; if (cursor_pos.y + get_row_height() + th > get_size().height) { - completion_rect.position.y = cursor_pos.y - th; + completion_rect.position.y = cursor_pos.y - th - (cache.line_spacing / 2.0f) - cursor_insert_offset_y; } else { - completion_rect.position.y = cursor_pos.y + get_row_height() + csb->get_offset().y; + completion_rect.position.y = cursor_pos.y + cache.font->get_height() + (cache.line_spacing / 2.0f) + csb->get_offset().y - cursor_insert_offset_y; completion_below = true; } @@ -1323,7 +1419,8 @@ void TextEdit::_notification(int p_what) { text_color = color_regions[j].color; } } - draw_string(cache.font, Point2(completion_rect.position.x, completion_rect.position.y + i * get_row_height() + cache.font->get_ascent()), completion_options[l], text_color, completion_rect.size.width); + int yofs = (get_row_height() - cache.font->get_height()) / 2; + draw_string(cache.font, Point2(completion_rect.position.x, completion_rect.position.y + i * get_row_height() + cache.font->get_ascent() + yofs), completion_options[l], text_color, completion_rect.size.width); } if (scrollw) { @@ -1372,8 +1469,8 @@ void TextEdit::_notification(int p_what) { } } - Size2 size = Size2(max_w, sc * font->get_height() + spacing); - Size2 minsize = size + sb->get_minimum_size(); + Size2 size2 = Size2(max_w, sc * font->get_height() + spacing); + Size2 minsize = size2 + sb->get_minimum_size(); if (completion_hint_offset == -0xFFFF) { completion_hint_offset = cursor_pos.x - offset; @@ -1440,9 +1537,11 @@ void TextEdit::_notification(int p_what) { } break; case MainLoop::NOTIFICATION_OS_IME_UPDATE: { - ime_text = OS::get_singleton()->get_ime_text(); - ime_selection = OS::get_singleton()->get_ime_selection(); - update(); + if (has_focus()) { + ime_text = OS::get_singleton()->get_ime_text(); + ime_selection = OS::get_singleton()->get_ime_selection(); + update(); + } } break; } } @@ -1483,8 +1582,7 @@ void TextEdit::_consume_pair_symbol(CharType ch) { } if ((ch == '\'' || ch == '"') && - cursor_get_column() > 0 && - _is_text_char(text[cursor.line][cursor_get_column() - 1])) { + cursor_get_column() > 0 && _is_text_char(text[cursor.line][cursor_get_column() - 1]) && !_is_pair_right_symbol(text[cursor.line][cursor_get_column()])) { insert_text_at_cursor(ch_single); cursor_set_column(cursor_position_to_move); return; @@ -1546,37 +1644,35 @@ void TextEdit::backspace_at_cursor() { set_line_as_breakpoint(prev_line, true); } + if (text.has_info_icon(cursor.line)) { + set_line_info_icon(prev_line, text.get_info_icon(cursor.line), text.get_info(cursor.line)); + } + if (auto_brace_completion_enabled && cursor.column > 0 && _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { _consume_backspace_for_pair_symbol(prev_line, prev_column); } else { // handle space indentation - if (cursor.column - indent_size >= 0 && indent_using_spaces) { - - // if there is enough spaces to count as a tab + if (cursor.column != 0 && indent_using_spaces) { + // check if there are no other chars before cursor, just indentation bool unindent = true; - for (int i = 1; i <= indent_size; i++) { - if (text[cursor.line][cursor.column - i] != ' ') { - unindent = false; - break; - } - } - - // and it is before the first character int i = 0; while (i < cursor.column && i < text[cursor.line].length()) { - if (text[cursor.line][i] != ' ' && text[cursor.line][i] != '\t') { + if (!_is_whitespace(text[cursor.line][i])) { unindent = false; break; } i++; } - // then we can remove it as a single character. + // then we can remove all spaces as a single character. if (unindent) { - _remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column); - prev_column = cursor.column - indent_size; + // we want to remove spaces up to closest indent + // or whole indent if cursor is pointing at it + int spaces_to_delete = _calculate_spaces_till_next_left_indent(cursor.column); + prev_column = cursor.column - spaces_to_delete; + _remove_text(cursor.line, prev_column, cursor.line, cursor.column); } else { _remove_text(prev_line, prev_column, cursor.line, cursor.column); } @@ -1593,6 +1689,10 @@ void TextEdit::indent_right() { int start_line; int end_line; + + // this value informs us by how much we changed selection position by indenting right + // default is 1 for tab indentation + int selection_offset = 1; begin_complex_operation(); if (is_selection_active()) { @@ -1611,18 +1711,24 @@ void TextEdit::indent_right() { for (int i = start_line; i <= end_line; i++) { String line_text = get_line(i); if (indent_using_spaces) { - line_text = space_indent + line_text; + // we don't really care where selection is - we just need to know indentation level at the beginning of the line + int left = _find_first_non_whitespace_column_of_line(line_text); + int spaces_to_add = _calculate_spaces_till_next_right_indent(left); + // since we will add this much spaces we want move whole selection and cursor by this much + selection_offset = spaces_to_add; + for (int j = 0; j < spaces_to_add; j++) + line_text = ' ' + line_text; } else { line_text = '\t' + line_text; } set_line(i, line_text); } - // fix selection and cursor being off by one on the last line + // fix selection and cursor being off after shifting selection right if (is_selection_active()) { - select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1); + select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset); } - cursor_set_column(cursor.column + 1, false); + cursor_set_column(cursor.column + selection_offset, false); end_complex_operation(); update(); } @@ -1631,6 +1737,15 @@ void TextEdit::indent_left() { int start_line; int end_line; + + // moving cursor and selection after unindenting can get tricky + // because changing content of line can move cursor and selection on it's own (if new line ends before previous position of either) + // therefore we just remember initial values + // and at the end of the operation offset them by number of removed characters + int removed_characters = 0; + int initial_selection_end_column = selection.to_column; + int initial_cursor_column = cursor.column; + begin_complex_operation(); if (is_selection_active()) { @@ -1653,21 +1768,43 @@ void TextEdit::indent_left() { if (line_text.begins_with("\t")) { line_text = line_text.substr(1, line_text.length()); set_line(i, line_text); - } else if (line_text.begins_with(space_indent)) { - line_text = line_text.substr(indent_size, line_text.length()); + removed_characters = 1; + } else if (line_text.begins_with(" ")) { + // when unindenting we aim to remove spaces before line that has selection no matter what is selected + // so we start of by finding first non whitespace character of line + int left = _find_first_non_whitespace_column_of_line(line_text); + + // here we remove only enough spaces to align text to nearest full multiple of indentation_size + // in case where selection begins at the start of indentation_size multiple we remove whole indentation level + int spaces_to_remove = _calculate_spaces_till_next_left_indent(left); + + line_text = line_text.substr(spaces_to_remove, line_text.length()); set_line(i, line_text); + removed_characters = spaces_to_remove; } } // fix selection and cursor being off by one on the last line if (is_selection_active() && last_line_text != get_line(end_line)) { - select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1); + select(selection.from_line, selection.from_column - removed_characters, + selection.to_line, initial_selection_end_column - removed_characters); } - cursor_set_column(cursor.column - 1, false); + cursor_set_column(initial_cursor_column - removed_characters, false); end_complex_operation(); update(); } +int TextEdit::_calculate_spaces_till_next_left_indent(int column) { + int spaces_till_indent = column % indent_size; + if (spaces_till_indent == 0) + spaces_till_indent = indent_size; + return spaces_till_indent; +} + +int TextEdit::_calculate_spaces_till_next_right_indent(int column) { + return indent_size - column % indent_size; +} + void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const { float rows = p_mouse.y; @@ -1698,15 +1835,15 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co col = text[row].size(); } else { - int colx = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width); + int colx = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width); colx += cursor.x_ofs; col = get_char_pos_for_line(colx, row, wrap_index); if (is_wrap_enabled() && wrap_index < times_line_wraps(row)) { // move back one if we are at the end of the row - Vector<String> rows = get_wrap_rows_text(row); + Vector<String> rows2 = get_wrap_rows_text(row); int row_end_col = 0; for (int i = 0; i < wrap_index + 1; i++) { - row_end_col += rows[i].length(); + row_end_col += rows2[i].length(); } if (col >= row_end_col) col -= 1; @@ -1719,6 +1856,9 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { + double prev_v_scroll = v_scroll->get_value(); + double prev_h_scroll = h_scroll->get_value(); + Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { @@ -1796,18 +1936,28 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { // toggle breakpoint on gutter click if (draw_breakpoint_gutter) { int gutter = cache.style_normal->get_margin(MARGIN_LEFT); - if (mb->get_position().x > gutter && mb->get_position().x <= gutter + cache.breakpoint_gutter_width + 3) { + if (mb->get_position().x > gutter - 6 && mb->get_position().x <= gutter + cache.breakpoint_gutter_width - 3) { set_line_as_breakpoint(row, !is_line_set_as_breakpoint(row)); emit_signal("breakpoint_toggled", row); return; } } + // emit info clicked + if (draw_info_gutter && text.has_info_icon(row)) { + int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); + int gutter_left = left_margin + cache.breakpoint_gutter_width; + if (mb->get_position().x > gutter_left - 6 && mb->get_position().x <= gutter_left + cache.info_gutter_width - 3) { + emit_signal("info_clicked", row, text.get_info(row)); + return; + } + } + // toggle fold on gutter click if can if (draw_fold_gutter) { int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); - int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w; + int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w + cache.info_gutter_width; if (mb->get_position().x > gutter_left - 6 && mb->get_position().x <= gutter_left + cache.fold_gutter_width - 3) { if (is_folded(row)) { unfold_line(row); @@ -1821,7 +1971,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { // unfold on folded icon click if (is_folded(row)) { int line_width = text.get_line_width(row); - line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width - cursor.x_ofs; + line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.info_gutter_width + cache.fold_gutter_width - cursor.x_ofs; if (mb->get_position().x > line_width - 3 && mb->get_position().x <= line_width + cache.folded_eol_icon->get_width() + 3) { unfold_line(row); return; @@ -1939,6 +2089,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { menu->set_position(get_global_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); + menu->set_scale(get_global_transform().get_scale()); menu->popup(); grab_focus(); } @@ -1962,6 +2113,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _scroll_down(delta); } h_scroll->set_value(h_scroll->get_value() + pan_gesture->get_delta().x * 100); + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + return; } @@ -2005,6 +2159,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + Ref<InputEventKey> k = p_gui_input; if (k.is_valid()) { @@ -2184,6 +2341,36 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { k->set_command(true); k->set_shift(false); } +#ifdef APPLE_STYLE_KEYS + if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) { + uint32_t remap_key = KEY_UNKNOWN; + switch (k->get_scancode()) { + case KEY_F: { + remap_key = KEY_RIGHT; + } break; + case KEY_B: { + remap_key = KEY_LEFT; + } break; + case KEY_P: { + remap_key = KEY_UP; + } break; + case KEY_N: { + remap_key = KEY_DOWN; + } break; + case KEY_D: { + remap_key = KEY_DELETE; + } break; + case KEY_H: { + remap_key = KEY_BACKSPACE; + } break; + } + + if (remap_key != KEY_UNKNOWN) { + k->set_scancode(remap_key); + k->set_control(false); + } + } +#endif _reset_caret_blink_timer(); @@ -2191,10 +2378,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { bool had_selection = selection.active; // stuff to do when selection is active.. - if (selection.active) { - - if (readonly) - return; + if (!readonly && selection.active) { bool clear = false; bool unselect = false; @@ -2386,15 +2570,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (k->get_shift()) { - //simple unindent + // simple unindent int cc = cursor.column; - - const int len = text[cursor.line].length(); const String &line = text[cursor.line]; - int left = 0; // number of whitespace chars at beginning of line - while (left < len && (line[left] == '\t' || line[left] == ' ')) - left++; + int left = _find_first_non_whitespace_column_of_line(line); cc = MIN(cc, left); while (cc < indent_size && cc < left && line[cc] == ' ') @@ -2402,24 +2582,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc > 0 && cc <= text[cursor.line].length()) { if (text[cursor.line][cc - 1] == '\t') { + // tabs unindentation _remove_text(cursor.line, cc - 1, cursor.line, cc); if (cursor.column >= left) cursor_set_column(MAX(0, cursor.column - 1)); update(); } else { - int n = 0; - - for (int i = 1; i <= MIN(cc, indent_size); i++) { - if (line[cc - i] != ' ') { - break; - } - n++; - } - - if (n > 0) { - _remove_text(cursor.line, cc - n, cursor.line, cc); - if (cursor.column > left - n) // inside text? - cursor_set_column(MAX(0, cursor.column - n)); + // spaces unindentation + int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); + if (spaces_to_remove > 0) { + _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc); + if (cursor.column > left - spaces_to_remove) // inside text? + cursor_set_column(MAX(0, cursor.column - spaces_to_remove)); update(); } } @@ -2428,9 +2602,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { update(); } } else { - //simple indent + // simple indent if (indent_using_spaces) { - _insert_text_at_cursor(space_indent); + // insert only as much spaces as needed till next indentation level + int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column); + String indent_to_insert = String(); + for (int i = 0; i < spaces_to_add; i++) + indent_to_insert = ' ' + indent_to_insert; + _insert_text_at_cursor(indent_to_insert); } else { _insert_text_at_cursor("\t"); } @@ -2506,7 +2685,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_left + FALLTHROUGH; } case KEY_LEFT: { @@ -2521,9 +2700,22 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { #ifdef APPLE_STYLE_KEYS if (k->get_command()) { - cursor_set_column(0); + // Start at first column (it's slightly faster that way) and look for the first non-whitespace character. + int new_cursor_pos = 0; + for (int i = 0; i < text[cursor.line].length(); ++i) { + if (!_is_whitespace(text[cursor.line][i])) { + new_cursor_pos = i; + break; + } + } + if (new_cursor_pos == cursor.column) { + // We're already at the first text character, so move to the very beginning of the line. + cursor_set_column(0); + } else { + // We're somewhere to the right of the first text character; move to the first one. + cursor_set_column(new_cursor_pos); + } } else if (k->get_alt()) { - #else if (k->get_alt()) { scancode_handled = false; @@ -2569,7 +2761,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_right + FALLTHROUGH; } case KEY_RIGHT: { @@ -2630,28 +2822,30 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_up + FALLTHROUGH; } case KEY_UP: { - if (k->get_shift()) - _pre_shift_selection(); if (k->get_alt()) { scancode_handled = false; break; } #ifndef APPLE_STYLE_KEYS if (k->get_command()) { - _scroll_lines_up(); - break; - } #else if (k->get_command() && k->get_alt()) { +#endif _scroll_lines_up(); break; } + if (k->get_shift()) { + _pre_shift_selection(); + } + +#ifdef APPLE_STYLE_KEYS if (k->get_command()) { + cursor_set_line(0); } else #endif @@ -2681,28 +2875,28 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_down + FALLTHROUGH; } case KEY_DOWN: { - if (k->get_shift()) - _pre_shift_selection(); if (k->get_alt()) { scancode_handled = false; break; } #ifndef APPLE_STYLE_KEYS if (k->get_command()) { - _scroll_lines_down(); - break; - } - #else if (k->get_command() && k->get_alt()) { +#endif _scroll_lines_down(); break; } + if (k->get_shift()) { + _pre_shift_selection(); + } + +#ifdef APPLE_STYLE_KEYS if (k->get_command()) { cursor_set_line(get_last_unhidden_line(), true, false, 9999); } else @@ -2804,11 +2998,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_home + FALLTHROUGH; } -#ifdef APPLE_STYLE_KEYS case KEY_HOME: { - +#ifdef APPLE_STYLE_KEYS if (k->get_shift()) _pre_shift_selection(); @@ -2818,11 +3011,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _post_shift_selection(); else if (k->get_command() || k->get_control()) deselect(); - - } break; #else - case KEY_HOME: { - if (k->get_shift()) _pre_shift_selection(); @@ -2863,19 +3052,17 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { deselect(); _cancel_completion(); completion_hint = ""; - - } break; #endif + } break; case KEY_KP_1: { if (k->get_unicode() != 0) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_end + FALLTHROUGH; } -#ifdef APPLE_STYLE_KEYS case KEY_END: { - +#ifdef APPLE_STYLE_KEYS if (k->get_shift()) _pre_shift_selection(); @@ -2885,11 +3072,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _post_shift_selection(); else if (k->get_command() || k->get_control()) deselect(); - - } break; #else - case KEY_END: { - if (k->get_shift()) _pre_shift_selection(); @@ -2916,15 +3099,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _cancel_completion(); completion_hint = ""; - - } break; #endif + } break; case KEY_KP_9: { if (k->get_unicode() != 0) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_pageup + FALLTHROUGH; } case KEY_PAGEUP: { @@ -2947,7 +3129,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_pagedown + FALLTHROUGH; } case KEY_PAGEDOWN: { @@ -3126,21 +3308,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (scancode_handled) accept_event(); - /* - if (!scancode_handled && !k->get_command() && !k->get_alt()) { - if (k->get_unicode()>=32) { - - if (readonly) - break; - - accept_event(); - } else { - - break; - } - } -*/ if (k->get_scancode() == KEY_INSERT) { set_insert_mode(!insert_mode); accept_event(); @@ -3183,7 +3351,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { end_complex_operation(); } accept_event(); - } else { } } @@ -3250,7 +3417,6 @@ void TextEdit::_scroll_down(real_t p_delta) { int max_v_scroll = round(v_scroll->get_max() - v_scroll->get_page()); if (target_v_scroll > max_v_scroll) { target_v_scroll = max_v_scroll; - v_scroll->set_value(target_v_scroll); } if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) { v_scroll->set_value(target_v_scroll); @@ -3363,28 +3529,31 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i String preinsert_text = text[p_line].substr(0, p_char); String postinsert_text = text[p_line].substr(p_char, text[p_line].size()); - for (int i = 0; i < substrings.size(); i++) { + for (int j = 0; j < substrings.size(); j++) { //insert the substrings - if (i == 0) { + if (j == 0) { - text.set(p_line, preinsert_text + substrings[i]); + text.set(p_line, preinsert_text + substrings[j]); } else { - text.insert(p_line + i, substrings[i]); + text.insert(p_line + j, substrings[j]); } - if (i == substrings.size() - 1) { + if (j == substrings.size() - 1) { - text.set(p_line + i, text[p_line + i] + postinsert_text); + text.set(p_line + j, text[p_line + j] + postinsert_text); } } if (shift_first_line) { text.set_breakpoint(p_line + 1, text.is_breakpoint(p_line)); text.set_hidden(p_line + 1, text.is_hidden(p_line)); + text.set_info_icon(p_line + 1, text.get_info_icon(p_line), text.get_info(p_line)); + text.set_breakpoint(p_line, false); text.set_hidden(p_line, false); + text.set_info_icon(p_line, NULL, ""); } text.set_line_wrap_amount(p_line, -1); @@ -3493,7 +3662,7 @@ void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r op.chain_forward = false; op.chain_backward = false; - //see if it shold just be set as current op + //see if it should just be set as current op if (current_op.type != op.type) { op.prev_version = get_version(); _push_current_op(); @@ -3544,7 +3713,7 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i op.chain_forward = false; op.chain_backward = false; - //see if it shold just be set as current op + //see if it should just be set as current op if (current_op.type != op.type) { op.prev_version = get_version(); _push_current_op(); @@ -3635,9 +3804,9 @@ int TextEdit::get_total_visible_rows() const { return total_rows; } -void TextEdit::update_wrap_at() { +void TextEdit::_update_wrap_at() { - wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - wrap_right_offset; + wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width - wrap_right_offset; update_cursor_wrap_offset(); text.clear_wrap_cache(); @@ -3671,7 +3840,7 @@ void TextEdit::adjust_viewport_to_cursor() { set_line_as_last_visible(cur_line, cur_wrap); } - int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; + int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width; if (v_scroll->is_visible_in_tree()) visible_width -= v_scroll->get_combined_minimum_size().width; visible_width -= 20; // give it a little more space @@ -3702,7 +3871,7 @@ void TextEdit::center_viewport_to_cursor() { unfold_line(cursor.line); set_line_as_center_visible(cursor.line, get_cursor_wrap_index()); - int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; + int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width; if (v_scroll->is_visible_in_tree()) visible_width -= v_scroll->get_combined_minimum_size().width; visible_width -= 20; // give it a little more space @@ -3779,6 +3948,9 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { int cur_wrap_index = 0; int tab_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width; + if (tab_offset_px >= wrap_at) { + tab_offset_px = 0; + } while (col < line_text.length()) { CharType c = line_text[col]; @@ -3786,30 +3958,36 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { int indent_ofs = (cur_wrap_index != 0 ? tab_offset_px : 0); - word_str += c; - word_px += w; - if (c == ' ') { - // end of a word; add this word to the substring + if (indent_ofs + word_px + w > wrap_at) { + // not enough space to add this char; start next line wrap_substring += word_str; - px += word_px; - word_str = ""; - word_px = 0; - } + lines.push_back(wrap_substring); + cur_wrap_index++; + wrap_substring = ""; + px = 0; - if ((indent_ofs + px + word_px) > wrap_at) { - // do not want to add this word - if (indent_ofs + word_px > wrap_at) { - // not enough space; add it anyway + word_str = ""; + word_str += c; + word_px = w; + } else { + word_str += c; + word_px += w; + if (c == ' ') { + // end of a word; add this word to the substring wrap_substring += word_str; px += word_px; word_str = ""; word_px = 0; } - lines.push_back(wrap_substring); - // reset for next wrap - cur_wrap_index++; - wrap_substring = ""; - px = 0; + + if (indent_ofs + px + word_px > wrap_at) { + // this word will be moved to the next line + lines.push_back(wrap_substring); + // reset for next wrap + cur_wrap_index++; + wrap_substring = ""; + px = 0; + } } col++; } @@ -3900,7 +4078,7 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_ cursor.line = p_row; int n_col = get_char_pos_for_line(cursor.last_fit_x, p_row, p_wrap_index); - if (is_wrap_enabled() && p_wrap_index < times_line_wraps(p_row)) { + if (n_col != 0 && is_wrap_enabled() && p_wrap_index < times_line_wraps(p_row)) { Vector<String> rows = get_wrap_rows_text(p_row); int row_end_col = 0; for (int i = 0; i < p_wrap_index + 1; i++) { @@ -3991,7 +4169,7 @@ void TextEdit::_scroll_moved(double p_to_val) { int v_scroll_i = floor(get_v_scroll()); int sc = 0; int n_line; - for (n_line = 0; n_line < text.size(); n_line++) { + for (n_line = 0; n_line < text.size() - 1; n_line++) { if (!is_line_hidden(n_line)) { sc++; sc += times_line_wraps(n_line); @@ -4022,6 +4200,9 @@ int TextEdit::get_char_pos_for_line(int p_px, int p_line, int p_wrap_index) cons int line_wrap_amount = times_line_wraps(p_line); int wrap_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width; + if (wrap_offset_px >= wrap_at) { + wrap_offset_px = 0; + } if (p_wrap_index > line_wrap_amount) p_wrap_index = line_wrap_amount; if (p_wrap_index > 0) @@ -4063,6 +4244,9 @@ int TextEdit::get_column_x_offset_for_line(int p_char, int p_line) const { int px = get_column_x_offset(n_char, rows[wrap_index]); int wrap_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width; + if (wrap_offset_px >= wrap_at) { + wrap_offset_px = 0; + } if (wrap_index != 0) px += wrap_offset_px; @@ -4126,7 +4310,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { if (highlighted_word != String()) return CURSOR_POINTING_HAND; - int gutter = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width; + int gutter = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width; if ((completion_active && completion_rect.has_point(p_pos))) { return CURSOR_ARROW; } @@ -4137,18 +4321,27 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); // breakpoint icon - if (draw_breakpoint_gutter && p_pos.x > left_margin && p_pos.x <= left_margin + cache.breakpoint_gutter_width + 3) { + if (draw_breakpoint_gutter && p_pos.x > left_margin - 6 && p_pos.x <= left_margin + cache.breakpoint_gutter_width - 3) { return CURSOR_POINTING_HAND; } + // info icons + int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.info_gutter_width; + if (draw_info_gutter && p_pos.x > left_margin + cache.breakpoint_gutter_width - 6 && p_pos.x <= gutter_left - 3) { + if (text.has_info_icon(row)) { + return CURSOR_POINTING_HAND; + } + return CURSOR_ARROW; + } + // fold icon - int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w; - if (draw_fold_gutter && p_pos.x > gutter_left - 6 && p_pos.x <= gutter_left + cache.fold_gutter_width - 3) { + if (draw_fold_gutter && p_pos.x > gutter_left + cache.line_number_w - 6 && p_pos.x <= gutter_left + cache.line_number_w + cache.fold_gutter_width - 3) { if (is_folded(row) || can_fold(row)) return CURSOR_POINTING_HAND; else return CURSOR_ARROW; } + return CURSOR_ARROW; } else { int row, col; @@ -4156,7 +4349,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { // eol fold icon if (is_folded(row)) { int line_width = text.get_line_width(row); - line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width - cursor.x_ofs; + line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs; if (p_pos.x > line_width - 3 && p_pos.x <= line_width + cache.folded_eol_icon->get_width() + 3) { return CURSOR_POINTING_HAND; } @@ -4169,17 +4362,22 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { void TextEdit::set_text(String p_text) { setting_text = true; - _clear(); - _insert_text_at_cursor(p_text); - clear_undo_history(); - cursor.column = 0; - cursor.line = 0; - cursor.x_ofs = 0; - cursor.line_ofs = 0; - cursor.wrap_ofs = 0; - cursor.last_fit_x = 0; - cursor_set_line(0); - cursor_set_column(0); + if (!undo_enabled) { + _clear(); + _insert_text_at_cursor(p_text); + } + + if (undo_enabled) { + cursor_set_line(0); + cursor_set_column(0); + + begin_complex_operation(); + _remove_text(0, 0, MAX(0, get_line_count() - 1), MAX(get_line(MAX(get_line_count() - 1, 0)).size() - 1, 0)); + _insert_text_at_cursor(p_text); + end_complex_operation(); + selection.active = false; + } + update(); setting_text = false; @@ -4276,7 +4474,27 @@ void TextEdit::clear() { void TextEdit::set_readonly(bool p_readonly) { + if (readonly == p_readonly) + return; + readonly = p_readonly; + + // Reorganize context menu. + menu->clear(); + if (!readonly) + menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X); + menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C); + if (!readonly) + menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V); + menu->add_separator(); + menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A); + if (!readonly) { + menu->add_item(RTR("Clear"), MENU_CLEAR); + menu->add_separator(); + menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z); + menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z); + } + update(); } @@ -4345,7 +4563,9 @@ void TextEdit::_update_caches() { cache.mark_color = get_color("mark_color"); cache.current_line_color = get_color("current_line_color"); cache.line_length_guideline_color = get_color("line_length_guideline_color"); + cache.bookmark_color = get_color("bookmark_color"); cache.breakpoint_color = get_color("breakpoint_color"); + cache.executing_line_color = get_color("executing_line_color"); cache.code_folding_color = get_color("code_folding_color"); cache.brace_mismatch_color = get_color("brace_mismatch_color"); cache.word_highlighted_color = get_color("word_highlighted_color"); @@ -4360,9 +4580,11 @@ void TextEdit::_update_caches() { #endif cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon = get_icon("tab"); - cache.folded_icon = get_icon("GuiTreeArrowRight", "EditorIcons"); - cache.can_fold_icon = get_icon("GuiTreeArrowDown", "EditorIcons"); + cache.space_icon = get_icon("space"); + cache.folded_icon = get_icon("folded"); + cache.can_fold_icon = get_icon("fold"); cache.folded_eol_icon = get_icon("GuiEllipsis", "EditorIcons"); + cache.executing_icon = get_icon("MainPlay", "EditorIcons"); text.set_font(cache.font); if (syntax_highlighter) { @@ -4460,6 +4682,8 @@ bool TextEdit::has_keyword_color(String p_keyword) const { } Color TextEdit::get_keyword_color(String p_keyword) const { + + ERR_FAIL_COND_V(!keywords.has(p_keyword), Color()); return keywords[p_keyword]; } @@ -4928,6 +5152,48 @@ bool TextEdit::is_line_set_as_safe(int p_line) const { return text.is_safe(p_line); } +void TextEdit::set_executing_line(int p_line) { + ERR_FAIL_INDEX(p_line, text.size()); + executing_line = p_line; + update(); +} + +void TextEdit::clear_executing_line() { + executing_line = -1; + update(); +} + +bool TextEdit::is_line_set_as_bookmark(int p_line) const { + + ERR_FAIL_INDEX_V(p_line, text.size(), false); + return text.is_bookmark(p_line); +} + +void TextEdit::set_line_as_bookmark(int p_line, bool p_bookmark) { + + ERR_FAIL_INDEX(p_line, text.size()); + text.set_bookmark(p_line, p_bookmark); + update(); +} + +void TextEdit::get_bookmarks(List<int> *p_bookmarks) const { + + for (int i = 0; i < text.size(); i++) { + if (text.is_bookmark(i)) + p_bookmarks->push_back(i); + } +} + +Array TextEdit::get_bookmarks_array() const { + + Array arr; + for (int i = 0; i < text.size(); i++) { + if (text.is_bookmark(i)) + arr.append(i); + } + return arr; +} + bool TextEdit::is_line_set_as_breakpoint(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), false); @@ -4967,6 +5233,19 @@ void TextEdit::remove_breakpoints() { } } +void TextEdit::set_line_info_icon(int p_line, Ref<Texture> p_icon, String p_info) { + ERR_FAIL_INDEX(p_line, text.size()); + text.set_info_icon(p_line, p_icon, p_info); + update(); +} + +void TextEdit::clear_info_icons() { + for (int i = 0; i < text.size(); i++) { + text.set_info_icon(i, NULL, ""); + } + update(); +} + void TextEdit::set_line_as_hidden(int p_line, bool p_hidden) { ERR_FAIL_INDEX(p_line, text.size()); @@ -5183,6 +5462,17 @@ bool TextEdit::is_folded(int p_line) const { return false; } +Vector<int> TextEdit::get_folded_lines() const { + Vector<int> folded_lines; + + for (int i = 0; i < text.size(); i++) { + if (is_folded(i)) { + folded_lines.push_back(i); + } + } + return folded_lines; +} + void TextEdit::fold_line(int p_line) { ERR_FAIL_INDEX(p_line, text.size()); @@ -5323,6 +5613,9 @@ void TextEdit::undo() { TextOperation op = undo_stack_pos->get(); _do_text_op(op, true); + if (op.type != TextOperation::TYPE_INSERT && (op.from_line != op.to_line || op.to_column != op.from_column + 1)) + select(op.from_line, op.from_column, op.to_line, op.to_column); + current_op.version = op.prev_version; if (undo_stack_pos->get().chain_backward) { while (true) { @@ -5449,6 +5742,7 @@ int TextEdit::get_indent_size() { void TextEdit::set_draw_tabs(bool p_draw) { draw_tabs = p_draw; + update(); } bool TextEdit::is_drawing_tabs() const { @@ -5456,6 +5750,16 @@ bool TextEdit::is_drawing_tabs() const { return draw_tabs; } +void TextEdit::set_draw_spaces(bool p_draw) { + + draw_spaces = p_draw; +} + +bool TextEdit::is_drawing_spaces() const { + + return draw_spaces; +} + void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) { override_selected_font_color = p_override_selected_font_color; } @@ -5635,19 +5939,29 @@ void TextEdit::_confirm_completion() { cursor_set_column(cursor.column - completion_base.length(), false); insert_text_at_cursor(completion_current); - // When inserted into the middle of an existing string, don't add an unnecessary quote + // When inserted into the middle of an existing string/method, don't add an unnecessary quote/bracket. String line = text[cursor.line]; CharType next_char = line[cursor.column]; CharType last_completion_char = completion_current[completion_current.length() - 1]; - if ((last_completion_char == '"' || last_completion_char == '\'') && - last_completion_char == next_char) { + if ((last_completion_char == '"' || last_completion_char == '\'') && last_completion_char == next_char) { _base_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); } - if (last_completion_char == '(' && auto_brace_completion_enabled) { - insert_text_at_cursor(")"); - cursor.column--; + if (last_completion_char == '(') { + + if (next_char == last_completion_char) { + _base_remove_text(cursor.line, cursor.column - 1, cursor.line, cursor.column); + } else if (auto_brace_completion_enabled) { + insert_text_at_cursor(")"); + cursor.column--; + } + } else if (last_completion_char == ')' && next_char == '(') { + + _base_remove_text(cursor.line, cursor.column - 2, cursor.line, cursor.column); + if (line[cursor.column + 1] != ')') { + cursor.column--; + } } end_complex_operation(); @@ -5691,6 +6005,7 @@ void TextEdit::_update_completion_candidates() { bool inquote = false; int first_quote = -1; + int restore_quotes = -1; int c = cofs - 1; while (c >= 0) { @@ -5698,6 +6013,11 @@ void TextEdit::_update_completion_candidates() { inquote = !inquote; if (first_quote == -1) first_quote = c; + restore_quotes = 0; + } else if (restore_quotes == 0 && l[c] == '$') { + restore_quotes = 1; + } else if (restore_quotes == 0 && !_is_whitespace(l[c])) { + restore_quotes = -1; } c--; } @@ -5765,6 +6085,11 @@ void TextEdit::_update_completion_candidates() { completion_strings.write[i] = completion_strings[i].unquote().quote("'"); } + if (inquote && restore_quotes == 1 && !completion_strings[i].is_quoted()) { + String quote = single_quote ? "'" : "\""; + completion_strings.write[i] = completion_strings[i].quote(quote); + } + if (completion_strings[i].begins_with(s)) { completion_options.push_back(completion_strings[i]); } else if (completion_strings[i].to_lower().begins_with(s.to_lower())) { @@ -5842,7 +6167,6 @@ void TextEdit::code_complete(const Vector<String> &p_strings, bool p_forced) { completion_current = ""; completion_index = 0; _update_completion_candidates(); - // } String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { @@ -5957,6 +6281,15 @@ void TextEdit::set_line_length_guideline_column(int p_column) { update(); } +void TextEdit::set_bookmark_gutter_enabled(bool p_draw) { + draw_bookmark_gutter = p_draw; + update(); +} + +bool TextEdit::is_bookmark_gutter_enabled() const { + return draw_bookmark_gutter; +} + void TextEdit::set_breakpoint_gutter_enabled(bool p_draw) { draw_breakpoint_gutter = p_draw; update(); @@ -5993,14 +6326,32 @@ int TextEdit::get_fold_gutter_width() const { return cache.fold_gutter_width; } -void TextEdit::set_hiding_enabled(int p_enabled) { +void TextEdit::set_draw_info_gutter(bool p_draw) { + draw_info_gutter = p_draw; + update(); +} + +bool TextEdit::is_drawing_info_gutter() const { + return draw_info_gutter; +} + +void TextEdit::set_info_gutter_width(int p_gutter_width) { + info_gutter_width = p_gutter_width; + update(); +} + +int TextEdit::get_info_gutter_width() const { + return info_gutter_width; +} + +void TextEdit::set_hiding_enabled(bool p_enabled) { if (!p_enabled) unhide_all_lines(); hiding_enabled = p_enabled; update(); } -int TextEdit::is_hiding_enabled() const { +bool TextEdit::is_hiding_enabled() const { return hiding_enabled; } @@ -6083,6 +6434,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("_click_selection_held"), &TextEdit::_click_selection_held); ClassDB::bind_method(D_METHOD("_toggle_draw_caret"), &TextEdit::_toggle_draw_caret); ClassDB::bind_method(D_METHOD("_v_scroll_input"), &TextEdit::_v_scroll_input); + ClassDB::bind_method(D_METHOD("_update_wrap_at"), &TextEdit::_update_wrap_at); BIND_ENUM_CONSTANT(SEARCH_MATCH_CASE); BIND_ENUM_CONSTANT(SEARCH_WHOLE_WORDS); @@ -6148,8 +6500,14 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_show_line_numbers", "enable"), &TextEdit::set_show_line_numbers); ClassDB::bind_method(D_METHOD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled); + ClassDB::bind_method(D_METHOD("set_draw_tabs"), &TextEdit::set_draw_tabs); + ClassDB::bind_method(D_METHOD("is_drawing_tabs"), &TextEdit::is_drawing_tabs); + ClassDB::bind_method(D_METHOD("set_draw_spaces"), &TextEdit::set_draw_spaces); + ClassDB::bind_method(D_METHOD("is_drawing_spaces"), &TextEdit::is_drawing_spaces); ClassDB::bind_method(D_METHOD("set_breakpoint_gutter_enabled", "enable"), &TextEdit::set_breakpoint_gutter_enabled); ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled); + ClassDB::bind_method(D_METHOD("set_draw_fold_gutter"), &TextEdit::set_draw_fold_gutter); + ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &TextEdit::is_drawing_fold_gutter); ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled); ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); @@ -6196,7 +6554,10 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_tabs"), "set_draw_tabs", "is_drawing_tabs"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_spaces"), "set_draw_spaces", "is_drawing_spaces"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "breakpoint_gutter"), "set_breakpoint_gutter_enabled", "is_breakpoint_gutter_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); @@ -6217,6 +6578,7 @@ void TextEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("request_completion")); ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "row"))); ADD_SIGNAL(MethodInfo("symbol_lookup", PropertyInfo(Variant::STRING, "symbol"), PropertyInfo(Variant::INT, "row"), PropertyInfo(Variant::INT, "column"))); + ADD_SIGNAL(MethodInfo("info_clicked", PropertyInfo(Variant::INT, "row"), PropertyInfo(Variant::STRING, "info"))); BIND_ENUM_CONSTANT(MENU_CUT); BIND_ENUM_CONSTANT(MENU_COPY); @@ -6233,9 +6595,9 @@ void TextEdit::_bind_methods() { TextEdit::TextEdit() { - readonly = false; setting_row = false; draw_tabs = false; + draw_spaces = false; override_selected_font_color = false; draw_caret = true; max_chars = 0; @@ -6252,6 +6614,8 @@ TextEdit::TextEdit() { breakpoint_gutter_width = 0; cache.fold_gutter_width = 0; fold_gutter_width = 0; + info_gutter_width = 0; + cache.info_gutter_width = 0; set_default_cursor_shape(CURSOR_IBEAM); indent_size = 4; @@ -6322,8 +6686,10 @@ TextEdit::TextEdit() { line_numbers_zero_padded = false; line_length_guideline = false; line_length_guideline_col = 80; + draw_bookmark_gutter = false; draw_breakpoint_gutter = false; draw_fold_gutter = false; + draw_info_gutter = false; hiding_enabled = false; next_operation_is_complex = false; scroll_past_end_of_file_enabled = false; @@ -6345,16 +6711,12 @@ TextEdit::TextEdit() { context_menu_enabled = true; menu = memnew(PopupMenu); add_child(menu); - menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X); - menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C); - menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V); - menu->add_separator(); - menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A); - menu->add_item(RTR("Clear"), MENU_CLEAR); - menu->add_separator(); - menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z); - menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z); + readonly = true; // initialise to opposite first, so we get past the early-out in set_readonly + set_readonly(false); menu->connect("id_pressed", this, "menu_option"); + first_draw = true; + + executing_line = -1; } TextEdit::~TextEdit() { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index f069ffc167..3e852deda6 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -40,7 +40,7 @@ class SyntaxHighlighter; class TextEdit : public Control { - GDCLASS(TextEdit, Control) + GDCLASS(TextEdit, Control); public: struct HighlighterInfo { @@ -75,10 +75,13 @@ public: int width_cache : 24; bool marked : 1; bool breakpoint : 1; + bool bookmark : 1; bool hidden : 1; bool safe : 1; int wrap_amount_cache : 24; Map<int, ColorRegionInfo> region_info; + Ref<Texture> info_icon; + String info; String data; }; @@ -103,12 +106,21 @@ public: void set(int p_line, const String &p_text); void set_marked(int p_line, bool p_marked) { text.write[p_line].marked = p_marked; } bool is_marked(int p_line) const { return text[p_line].marked; } + void set_bookmark(int p_line, bool p_bookmark) { text.write[p_line].bookmark = p_bookmark; } + bool is_bookmark(int p_line) const { return text[p_line].bookmark; } void set_breakpoint(int p_line, bool p_breakpoint) { text.write[p_line].breakpoint = p_breakpoint; } bool is_breakpoint(int p_line) const { return text[p_line].breakpoint; } void set_hidden(int p_line, bool p_hidden) { text.write[p_line].hidden = p_hidden; } bool is_hidden(int p_line) const { return text[p_line].hidden; } void set_safe(int p_line, bool p_safe) { text.write[p_line].safe = p_safe; } bool is_safe(int p_line) const { return text[p_line].safe; } + void set_info_icon(int p_line, Ref<Texture> p_icon, String p_info) { + text.write[p_line].info_icon = p_icon; + text.write[p_line].info = p_info; + } + bool has_info_icon(int p_line) const { return text[p_line].info_icon.is_valid(); } + const Ref<Texture> &get_info_icon(int p_line) const { return text[p_line].info_icon; } + const String &get_info(int p_line) const { return text[p_line].info; } void insert(int p_at, const String &p_text); void remove(int p_at); int size() const { return text.size(); } @@ -154,9 +166,11 @@ private: struct Cache { Ref<Texture> tab_icon; + Ref<Texture> space_icon; Ref<Texture> can_fold_icon; Ref<Texture> folded_icon; Ref<Texture> folded_eol_icon; + Ref<Texture> executing_icon; Ref<StyleBox> style_normal; Ref<StyleBox> style_focus; Ref<StyleBox> style_readonly; @@ -177,7 +191,9 @@ private: Color member_variable_color; Color selection_color; Color mark_color; + Color bookmark_color; Color breakpoint_color; + Color executing_line_color; Color code_folding_color; Color current_line_color; Color line_length_guideline_color; @@ -193,6 +209,7 @@ private: int line_number_w; int breakpoint_gutter_width; int fold_gutter_width; + int info_gutter_width; } cache; Map<int, int> color_region_cache; @@ -275,8 +292,10 @@ private: int wrap_at; int wrap_right_offset; + bool first_draw; bool setting_row; bool draw_tabs; + bool draw_spaces; bool override_selected_font_color; bool cursor_changed_dirty; bool text_changed_dirty; @@ -285,11 +304,14 @@ private: bool line_numbers_zero_padded; bool line_length_guideline; int line_length_guideline_col; + bool draw_bookmark_gutter; bool draw_breakpoint_gutter; int breakpoint_gutter_width; bool draw_fold_gutter; int fold_gutter_width; bool hiding_enabled; + bool draw_info_gutter; + int info_gutter_width; bool highlight_all_occurrences; bool scroll_past_end_of_file_enabled; @@ -332,11 +354,13 @@ private: bool context_menu_enabled; + int executing_line; + int get_visible_rows() const; int get_total_visible_rows() const; void update_cursor_wrap_offset(); - void update_wrap_at(); + void _update_wrap_at(); bool line_wraps(int line) const; int times_line_wraps(int line) const; Vector<String> get_wrap_rows_text(int p_line) const; @@ -413,6 +437,9 @@ private: void _confirm_completion(); void _update_completion_candidates(); + int _calculate_spaces_till_next_left_indent(int column); + int _calculate_spaces_till_next_right_indent(int column); + protected: virtual String get_tooltip(const Point2 &p_pos) const; @@ -471,14 +498,23 @@ public: void insert_at(const String &p_text, int at); int get_line_count() const; void set_line_as_marked(int p_line, bool p_marked); + void set_line_as_bookmark(int p_line, bool p_bookmark); + bool is_line_set_as_bookmark(int p_line) const; + void get_bookmarks(List<int> *p_bookmarks) const; + Array get_bookmarks_array() const; void set_line_as_breakpoint(int p_line, bool p_breakpoint); bool is_line_set_as_breakpoint(int p_line) const; + void set_executing_line(int p_line); + void clear_executing_line(); void set_line_as_safe(int p_line, bool p_safe); bool is_line_set_as_safe(int p_line) const; void get_breakpoints(List<int> *p_breakpoints) const; Array get_breakpoints_array() const; void remove_breakpoints(); + void set_line_info_icon(int p_line, Ref<Texture> p_icon, String p_info = ""); + void clear_info_icons(); + void set_line_as_hidden(int p_line, bool p_hidden); bool is_line_hidden(int p_line) const; void fold_all_lines(); @@ -489,6 +525,7 @@ public: bool can_fold(int p_line) const; bool is_folded(int p_line) const; + Vector<int> get_folded_lines() const; void fold_line(int p_line); void unfold_line(int p_line); void toggle_fold_line(int p_line); @@ -590,6 +627,8 @@ public: int get_indent_size(); void set_draw_tabs(bool p_draw); bool is_drawing_tabs() const; + void set_draw_spaces(bool p_draw); + bool is_drawing_spaces() const; void set_override_selected_font_color(bool p_override_selected_font_color); bool is_overriding_selected_font_color() const; @@ -637,6 +676,9 @@ public: void set_show_line_length_guideline(bool p_show); void set_line_length_guideline_column(int p_column); + void set_bookmark_gutter_enabled(bool p_draw); + bool is_bookmark_gutter_enabled() const; + void set_breakpoint_gutter_enabled(bool p_draw); bool is_breakpoint_gutter_enabled() const; @@ -649,8 +691,14 @@ public: void set_fold_gutter_width(int p_gutter_width); int get_fold_gutter_width() const; - void set_hiding_enabled(int p_enabled); - int is_hiding_enabled() const; + void set_draw_info_gutter(bool p_draw); + bool is_drawing_info_gutter() const; + + void set_info_gutter_width(int p_gutter_width); + int get_info_gutter_width() const; + + void set_hiding_enabled(bool p_enabled); + bool is_hiding_enabled() const; void set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata); @@ -683,10 +731,11 @@ protected: TextEdit *text_editor; public: + virtual ~SyntaxHighlighter() {} virtual void _update_cache() = 0; virtual Map<int, TextEdit::HighlighterInfo> _get_line_syntax_highlighting(int p_line) = 0; - virtual String get_name() = 0; + virtual String get_name() const = 0; virtual List<String> get_supported_languages() = 0; void set_text_editor(TextEdit *p_text_editor); diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 4a8d87902b..b5f949aeb7 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -64,7 +64,9 @@ bool TextureButton::has_point(const Point2 &p_point) const { Rect2 rect = Rect2(); Size2 mask_size = click_mask->get_size(); - if (_tile) { + if (_position_rect.has_no_area()) { + rect.size = mask_size; + } else if (_tile) { // if the stretch mode is tile we offset the point to keep it inside the mask size rect.size = mask_size; if (_position_rect.has_point(point)) { @@ -206,8 +208,8 @@ void TextureButton::_notification(int p_what) { Size2 scaleSize(size.width / tex_size.width, size.height / tex_size.height); float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height; Size2 scaledTexSize = tex_size * scale; - Point2 ofs = ((scaledTexSize - size) / scale).abs() / 2.0f; - _texture_region = Rect2(ofs, size / scale); + Point2 ofs2 = ((scaledTexSize - size) / scale).abs() / 2.0f; + _texture_region = Rect2(ofs2, size / scale); } break; } } @@ -216,11 +218,12 @@ void TextureButton::_notification(int p_what) { draw_texture_rect(texdraw, _position_rect, _tile); else draw_texture_rect_region(texdraw, _position_rect, _texture_region); + } else { + _position_rect = Rect2(); } if (has_focus() && focused.is_valid()) { - Rect2 drect(Point2(), get_size()); - draw_texture_rect(focused, drect, false); + draw_texture_rect(focused, _position_rect, false); }; } break; } diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h index d42df390e8..d9224de686 100644 --- a/scene/gui/texture_button.h +++ b/scene/gui/texture_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,7 +32,7 @@ #define TEXTURE_BUTTON_H #include "scene/gui/base_button.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" class TextureButton : public BaseButton { GDCLASS(TextureButton, BaseButton); diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index a37659e521..c534df5cbe 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -160,23 +160,27 @@ Point2 TextureProgress::unit_val_to_uv(float val) { if (edge == 0) { if (dir.x > 0) continue; - cp = -dir.x; cq = -(edgeLeft - p.x); + dir.x *= 2.0 * cq; + cp = -dir.x; } else if (edge == 1) { if (dir.x < 0) continue; - cp = dir.x; cq = (edgeRight - p.x); + dir.x *= 2.0 * cq; + cp = dir.x; } else if (edge == 2) { if (dir.y > 0) continue; - cp = -dir.y; cq = -(edgeBottom - p.y); + dir.y *= 2.0 * cq; + cp = -dir.y; } else if (edge == 3) { if (dir.y < 0) continue; - cp = dir.y; cq = (edgeTop - p.y); + dir.y *= 2.0 * cq; + cp = dir.y; } cr = cq / cp; if (cr >= 0 && cr < t1) @@ -247,12 +251,14 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F middle_section_size *= MIN(1.0, (MAX(0.0, width_filled - first_section_size) / MAX(1.0, width_total - first_section_size - last_section_size))); last_section_size = MAX(0.0, last_section_size - (width_total - width_filled)); + first_section_size = MIN(first_section_size, width_filled); width_texture = MIN(width_texture, first_section_size + middle_section_size + last_section_size); switch (mode) { case FILL_LEFT_TO_RIGHT: { src_rect.size.x = width_texture; dst_rect.size.x = width_filled; + topleft.x = first_section_size; bottomright.x = last_section_size; } break; case FILL_RIGHT_TO_LEFT: { @@ -261,11 +267,13 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F dst_rect.position.x += width_total - width_filled; dst_rect.size.x = width_filled; topleft.x = last_section_size; + bottomright.x = first_section_size; } break; case FILL_TOP_TO_BOTTOM: { src_rect.size.y = width_texture; dst_rect.size.y = width_filled; bottomright.y = last_section_size; + topleft.y = first_section_size; } break; case FILL_BOTTOM_TO_TOP: { src_rect.position.y += src_rect.size.y - width_texture; @@ -273,6 +281,7 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F dst_rect.position.y += width_total - width_filled; dst_rect.size.y = width_filled; topleft.y = last_section_size; + bottomright.y = first_section_size; } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { // TODO: Implement diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress.h index a11e55234a..008bf5b038 100644 --- a/scene/gui/texture_progress.h +++ b/scene/gui/texture_progress.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index 4371baf08c..423794d8ba 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -38,30 +38,32 @@ void TextureRect::_notification(int p_what) { if (texture.is_null()) return; + Size2 size; + Point2 offset; + Rect2 region; + bool tile = false; + switch (stretch_mode) { case STRETCH_SCALE_ON_EXPAND: { - Size2 s = expand ? get_size() : texture->get_size(); - draw_texture_rect(texture, Rect2(Point2(), s), false); + size = expand ? get_size() : texture->get_size(); } break; case STRETCH_SCALE: { - draw_texture_rect(texture, Rect2(Point2(), get_size()), false); + size = get_size(); } break; case STRETCH_TILE: { - draw_texture_rect(texture, Rect2(Point2(), get_size()), true); + size = get_size(); + tile = true; } break; case STRETCH_KEEP: { - draw_texture_rect(texture, Rect2(Point2(), texture->get_size()), false); - + size = texture->get_size(); } break; case STRETCH_KEEP_CENTERED: { - - Vector2 ofs = (get_size() - texture->get_size()) / 2; - draw_texture_rect(texture, Rect2(ofs, texture->get_size()), false); + offset = (get_size() - texture->get_size()) / 2; + size = texture->get_size(); } break; case STRETCH_KEEP_ASPECT_CENTERED: case STRETCH_KEEP_ASPECT: { - - Size2 size = get_size(); + size = get_size(); int tex_width = texture->get_width() * size.height / texture->get_height(); int tex_height = size.height; @@ -70,26 +72,35 @@ void TextureRect::_notification(int p_what) { tex_height = texture->get_height() * tex_width / texture->get_width(); } - int ofs_x = 0; - int ofs_y = 0; - if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) { - ofs_x += (size.width - tex_width) / 2; - ofs_y += (size.height - tex_height) / 2; + offset.x += (size.width - tex_width) / 2; + offset.y += (size.height - tex_height) / 2; } - draw_texture_rect(texture, Rect2(ofs_x, ofs_y, tex_width, tex_height)); + size.width = tex_width; + size.height = tex_height; } break; case STRETCH_KEEP_ASPECT_COVERED: { - Size2 size = get_size(); + size = get_size(); + Size2 tex_size = texture->get_size(); Size2 scaleSize(size.width / tex_size.width, size.height / tex_size.height); float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height; Size2 scaledTexSize = tex_size * scale; - Point2 ofs = ((scaledTexSize - size) / scale).abs() / 2.0f; - draw_texture_rect_region(texture, Rect2(Point2(), size), Rect2(ofs, size / scale)); + + region.position = ((scaledTexSize - size) / scale).abs() / 2.0f; + region.size = size / scale; } break; } + + size.width *= hflip ? -1.0f : 1.0f; + size.height *= vflip ? -1.0f : 1.0f; + + if (region.has_no_area()) { + draw_texture_rect(texture, Rect2(offset, size), tile); + } else { + draw_texture_rect_region(texture, Rect2(offset, size), region); + } } } @@ -106,12 +117,18 @@ void TextureRect::_bind_methods() { ClassDB::bind_method(D_METHOD("get_texture"), &TextureRect::get_texture); ClassDB::bind_method(D_METHOD("set_expand", "enable"), &TextureRect::set_expand); ClassDB::bind_method(D_METHOD("has_expand"), &TextureRect::has_expand); + ClassDB::bind_method(D_METHOD("set_flip_h", "enable"), &TextureRect::set_flip_h); + ClassDB::bind_method(D_METHOD("is_flipped_h"), &TextureRect::is_flipped_h); + ClassDB::bind_method(D_METHOD("set_flip_v", "enable"), &TextureRect::set_flip_v); + ClassDB::bind_method(D_METHOD("is_flipped_v"), &TextureRect::is_flipped_v); ClassDB::bind_method(D_METHOD("set_stretch_mode", "stretch_mode"), &TextureRect::set_stretch_mode); ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureRect::get_stretch_mode); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand"); ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale On Expand (Compat),Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v"); BIND_ENUM_CONSTANT(STRETCH_SCALE_ON_EXPAND); BIND_ENUM_CONSTANT(STRETCH_SCALE); @@ -161,9 +178,31 @@ TextureRect::StretchMode TextureRect::get_stretch_mode() const { return stretch_mode; } +void TextureRect::set_flip_h(bool p_flip) { + + hflip = p_flip; + update(); +} +bool TextureRect::is_flipped_h() const { + + return hflip; +} + +void TextureRect::set_flip_v(bool p_flip) { + + vflip = p_flip; + update(); +} +bool TextureRect::is_flipped_v() const { + + return vflip; +} + TextureRect::TextureRect() { expand = false; + hflip = false; + vflip = false; set_mouse_filter(MOUSE_FILTER_PASS); stretch_mode = STRETCH_SCALE_ON_EXPAND; } diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h index b684ac816c..3ab35324e5 100644 --- a/scene/gui/texture_rect.h +++ b/scene/gui/texture_rect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -53,6 +53,8 @@ public: private: bool expand; + bool hflip; + bool vflip; Ref<Texture> texture; StretchMode stretch_mode; @@ -71,6 +73,12 @@ public: void set_stretch_mode(StretchMode p_mode); StretchMode get_stretch_mode() const; + void set_flip_h(bool p_flip); + bool is_flipped_h() const; + + void set_flip_v(bool p_flip); + bool is_flipped_v() const; + TextureRect(); ~TextureRect(); }; diff --git a/scene/gui/tool_button.cpp b/scene/gui/tool_button.cpp index 4220a6b5ce..a81cc34efa 100644 --- a/scene/gui/tool_button.cpp +++ b/scene/gui/tool_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/tool_button.h b/scene/gui/tool_button.h index b8be18e560..8f729cd4df 100644 --- a/scene/gui/tool_button.h +++ b/scene/gui/tool_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 479b035f86..522c1ecb6a 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,7 +29,6 @@ /*************************************************************************/ #include "tree.h" -#include <limits.h> #include "core/math/math_funcs.h" #include "core/os/input.h" @@ -40,9 +39,11 @@ #include "scene/main/viewport.h" #ifdef TOOLS_ENABLED -#include "editor/editor_node.h" +#include "editor/editor_scale.h" #endif +#include <limits.h> + void TreeItem::move_to_top() { if (!parent || parent->children == this) @@ -317,7 +318,7 @@ void TreeItem::set_custom_draw(int p_column, Object *p_object, const StringName void TreeItem::set_collapsed(bool p_collapsed) { - if (collapsed == p_collapsed) + if (collapsed == p_collapsed || !tree) return; collapsed = p_collapsed; TreeItem *ci = tree->selected_item; @@ -343,8 +344,7 @@ void TreeItem::set_collapsed(bool p_collapsed) { } _changed_notify(); - if (tree) - tree->emit_signal("item_collapsed", this); + tree->emit_signal("item_collapsed", this); } bool TreeItem::is_collapsed() { @@ -388,7 +388,7 @@ TreeItem *TreeItem::get_children() { return children; } -TreeItem *TreeItem::get_prev_visible() { +TreeItem *TreeItem::get_prev_visible(bool p_wrap) { TreeItem *current = this; @@ -397,8 +397,20 @@ TreeItem *TreeItem::get_prev_visible() { if (!prev) { current = current->parent; - if (!current || (current == tree->root && tree->hide_root)) + if (current == tree->root && tree->hide_root) { return NULL; + } else if (!current) { + if (p_wrap) { + current = this; + TreeItem *temp = this->get_next_visible(); + while (temp) { + current = temp; + temp = temp->get_next_visible(); + } + } else { + return NULL; + } + } } else { current = prev; @@ -414,7 +426,7 @@ TreeItem *TreeItem::get_prev_visible() { return current; } -TreeItem *TreeItem::get_next_visible() { +TreeItem *TreeItem::get_next_visible(bool p_wrap) { TreeItem *current = this; @@ -432,10 +444,14 @@ TreeItem *TreeItem::get_next_visible() { current = current->parent; } - if (current == NULL) - return NULL; - else + if (!current) { + if (p_wrap) + return tree->root; + else + return NULL; + } else { current = current->next; + } } return current; @@ -739,8 +755,8 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_parent"), &TreeItem::get_parent); ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children); - ClassDB::bind_method(D_METHOD("get_next_visible"), &TreeItem::get_next_visible); - ClassDB::bind_method(D_METHOD("get_prev_visible"), &TreeItem::get_prev_visible); + ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::_remove_child); @@ -940,6 +956,7 @@ int Tree::compute_item_height(TreeItem *p_item) const { int check_icon_h = cache.checked->get_height(); if (height < check_icon_h) height = check_icon_h; + FALLTHROUGH; } case TreeItem::CELL_MODE_STRING: case TreeItem::CELL_MODE_CUSTOM: @@ -960,7 +977,8 @@ int Tree::compute_item_height(TreeItem *p_item) const { } } break; - default: {} + default: { + } } } int item_min_height = p_item->get_custom_minimum_height(); @@ -1071,11 +1089,11 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int font_ascent = font->get_ascent(); int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); - int skip = 0; + int skip2 = 0; for (int i = 0; i < columns.size(); i++) { - if (skip) { - skip--; + if (skip2) { + skip2--; continue; } @@ -1102,7 +1120,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text == "" && p_item->cells[i + plus].icon.is_null()) { w += get_column_width(i + plus); plus++; - skip++; + skip2++; } } @@ -1158,16 +1176,15 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 r.position.x += icon_width; r.size.x -= icon_width; } - //r.grow(cache.selected->get_margin(MARGIN_LEFT)); + p_item->set_meta("__focus_rect", Rect2(r.position, r.size)); if (has_focus()) { cache.selected_focus->draw(ci, r); - p_item->set_meta("__focus_rect", Rect2(r.position, r.size)); } else { cache.selected->draw(ci, r); } if (text_editor->is_visible_in_tree()) { - Vector2 ofs(0, (text_editor->get_size().height - r.size.height) / 2); - text_editor->set_position(get_global_position() + r.position - ofs); + Vector2 ofs2(0, (text_editor->get_size().height - r.size.height) / 2); + text_editor->set_position(get_global_position() + r.position - ofs2); } } @@ -1417,12 +1434,15 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 TreeItem *c = p_item->children; + int prev_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y; + while (c) { - if (cache.draw_relationship_lines == 1 && (!hide_root || c->parent != root)) { + if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) { int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; + if (c->get_children() != NULL) root_pos -= Point2i(cache.arrow->get_width(), 0); @@ -1435,12 +1455,13 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (root_pos.y + line_width >= 0) { VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color, line_width); + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), Point2i(parent_pos.x, prev_ofs), cache.relationship_line_color, line_width); } if (htotal < 0) { return -1; } + prev_ofs = root_pos.y; } if (htotal >= 0) { @@ -1602,6 +1623,7 @@ void Tree::_range_click_timeout() { mb.instance(); ; + propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case) blocked++; propagate_mouse_event(pos + cache.offset, 0, 0, false, root, BUTTON_LEFT, mb); blocked--; @@ -1615,6 +1637,11 @@ void Tree::_range_click_timeout() { if (!click_handled) range_click_timer->stop(); + if (propagate_mouse_activated) { + emit_signal("item_activated"); + propagate_mouse_activated = false; + } + } else { range_click_timer->stop(); } @@ -1723,7 +1750,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool if (p_doubleclick && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check - emit_signal("item_activated"); + propagate_mouse_activated = true; + incr_search.clear(); return -1; } @@ -1957,6 +1985,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool item_h += child_h; } } + if (p_item == root && p_button == BUTTON_RIGHT) { + emit_signal("empty_rmb", get_local_mouse_position()); + } } return item_h; // nothing found @@ -2008,7 +2039,9 @@ void Tree::text_editor_enter(String p_text) { //popup_edited_item->edited_signal.call( popup_edited_item_col ); } break; - default: { ERR_FAIL(); } + default: { + ERR_FAIL(); + } } item_edited(popup_edited_item_col, popup_edited_item); @@ -2251,7 +2284,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { next = _n; } else { - return; + break; } } if (next == selected_item) @@ -2289,7 +2322,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { prev = _n; } else { - return; + break; } } if (prev == selected_item) @@ -2591,6 +2624,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { click_handled = false; pressing_for_editor = false; + propagate_mouse_activated = false; blocked++; propagate_mouse_event(pos + cache.offset, 0, 0, b->is_doubleclick(), root, b->get_button_index(), b); @@ -2628,6 +2662,11 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } } + if (propagate_mouse_activated) { + emit_signal("item_activated"); + propagate_mouse_activated = false; + } + } break; case BUTTON_WHEEL_UP: { @@ -2686,8 +2725,8 @@ bool Tree::edit_selected() { popup_menu->clear(); for (int i = 0; i < c.text.get_slice_count(","); i++) { - String s = c.text.get_slicec(',', i); - popup_menu->add_item(s.get_slicec(':', 0), s.get_slicec(':', 1).empty() ? i : s.get_slicec(':', 1).to_int()); + String s2 = c.text.get_slicec(',', i); + popup_menu->add_item(s2.get_slicec(':', 0), s2.get_slicec(':', 1).empty() ? i : s2.get_slicec(':', 1).to_int()); } popup_menu->set_size(Size2(rect.size.width, 0)); @@ -2829,7 +2868,7 @@ void Tree::_notification(int p_what) { if (p_what == NOTIFICATION_DRAG_BEGIN) { single_select_defer = NULL; - if (cache.scroll_speed > 0 && get_rect().has_point(get_viewport()->get_mouse_position() - get_global_position())) { + if (cache.scroll_speed > 0) { scrolling = true; set_physics_process_internal(true); } @@ -2876,22 +2915,22 @@ void Tree::_notification(int p_what) { } } - if (scrolling) { - Point2 point = get_viewport()->get_mouse_position() - get_global_position(); - if (point.x < cache.scroll_border) { - point.x -= cache.scroll_border; - } else if (point.x > get_size().width - cache.scroll_border) { - point.x -= get_size().width - cache.scroll_border; - } else { - point.x = 0; + Point2 mouse_position = get_viewport()->get_mouse_position() - get_global_position(); + if (scrolling && get_rect().grow(cache.scroll_border).has_point(mouse_position)) { + Point2 point; + + if ((ABS(mouse_position.x) < ABS(mouse_position.x - get_size().width)) && (ABS(mouse_position.x) < cache.scroll_border)) { + point.x = mouse_position.x - cache.scroll_border; + } else if (ABS(mouse_position.x - get_size().width) < cache.scroll_border) { + point.x = mouse_position.x - (get_size().width - cache.scroll_border); } - if (point.y < cache.scroll_border) { - point.y -= cache.scroll_border; - } else if (point.y > get_size().height - cache.scroll_border) { - point.y -= get_size().height - cache.scroll_border; - } else { - point.y = 0; + + if ((ABS(mouse_position.y) < ABS(mouse_position.y - get_size().height)) && (ABS(mouse_position.y) < cache.scroll_border)) { + point.y = mouse_position.y - cache.scroll_border; + } else if (ABS(mouse_position.y - get_size().height) < cache.scroll_border) { + point.y = mouse_position.y - (get_size().height - cache.scroll_border); } + point *= cache.scroll_speed * get_physics_process_delta_time(); point += get_scroll(); h_scroll->set_value(point.x); @@ -2939,14 +2978,14 @@ void Tree::_notification(int p_what) { if (show_column_titles) { //title buttons - int ofs = cache.bg->get_margin(MARGIN_LEFT); + int ofs2 = cache.bg->get_margin(MARGIN_LEFT); for (int i = 0; i < columns.size(); i++) { Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? cache.title_button_hover : cache.title_button); Ref<Font> f = cache.tb_font; - Rect2 tbrect = Rect2(ofs - cache.offset.x, bg->get_margin(MARGIN_TOP), get_column_width(i), tbh); + Rect2 tbrect = Rect2(ofs2 - cache.offset.x, bg->get_margin(MARGIN_TOP), get_column_width(i), tbh); sb->draw(ci, tbrect); - ofs += tbrect.size.width; + ofs2 += tbrect.size.width; //text int clip_w = tbrect.size.width - sb->get_minimum_size().width; f->draw_halign(ci, tbrect.position + Point2i(sb->get_offset().x, (tbrect.size.height - f->get_height()) / 2 + f->get_ascent()), HALIGN_CENTER, clip_w, columns[i].title, cache.title_button_color); @@ -3367,10 +3406,13 @@ void Tree::ensure_cursor_is_visible() { int h = compute_item_height(selected) + cache.vseparation; int screenh = get_size().height - h_scroll->get_combined_minimum_size().height; - if (ofs + h > v_scroll->get_value() + screenh) + if (h > screenh) { //screen size is too small, maybe it was not resized yet. + v_scroll->set_value(ofs); + } else if (ofs + h > v_scroll->get_value() + screenh) { v_scroll->call_deferred("set_value", ofs - screenh + h); - else if (ofs < v_scroll->get_value()) + } else if (ofs < v_scroll->get_value()) { v_scroll->set_value(ofs); + } } int Tree::get_pressed_button() const { @@ -3464,6 +3506,7 @@ void Tree::scroll_to_item(TreeItem *p_item) { TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_col, bool p_selectable, bool p_backwards) { + TreeItem *from = p_at; while (p_at) { for (int i = 0; i < columns.size(); i++) { @@ -3475,9 +3518,12 @@ TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_c } if (p_backwards) - p_at = p_at->get_prev_visible(); + p_at = p_at->get_prev_visible(true); else - p_at = p_at->get_next_visible(); + p_at = p_at->get_next_visible(true); + + if ((p_at) == from) + break; } return NULL; @@ -3485,10 +3531,14 @@ TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_c TreeItem *Tree::search_item_text(const String &p_find, int *r_col, bool p_selectable) { - if (!root) + TreeItem *from = get_selected(); + + if (!from) + from = root; + if (!from) return NULL; - return _search_item_text(root, p_find, r_col, p_selectable); + return _search_item_text(from->get_next_visible(true), p_find, r_col, p_selectable); } void Tree::_do_incr_search(const String &p_add) { @@ -3497,7 +3547,7 @@ void Tree::_do_incr_search(const String &p_add) { uint64_t diff = time - last_keypress; if (diff > uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000))) incr_search = p_add; - else + else if (incr_search != p_add) incr_search += p_add; last_keypress = time; @@ -3670,6 +3720,10 @@ String Tree::get_tooltip(const Point2 &p_pos) const { const TreeItem::Cell &c = it->cells[col]; int col_width = get_column_width(col); + + for (int i = 0; i < col; i++) + pos.x -= get_column_width(i); + for (int j = c.buttons.size() - 1; j >= 0; j--) { Ref<Texture> b = c.buttons[j].texture; Size2 size = b->get_size() + cache.button_pressed->get_minimum_size(); @@ -3829,6 +3883,7 @@ void Tree::_bind_methods() { ADD_SIGNAL(MethodInfo("cell_selected")); ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::BOOL, "selected"))); ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::VECTOR2, "position"))); + ADD_SIGNAL(MethodInfo("empty_rmb", PropertyInfo(Variant::VECTOR2, "position"))); ADD_SIGNAL(MethodInfo("empty_tree_rmb_selected", PropertyInfo(Variant::VECTOR2, "position"))); ADD_SIGNAL(MethodInfo("item_edited")); ADD_SIGNAL(MethodInfo("item_rmb_edited")); @@ -3914,7 +3969,6 @@ Tree::Tree() { cache.click_item = NULL; cache.click_column = 0; cache.hover_cell = -1; - cache.hover_index = -1; last_keypress = 0; focus_in_id = 0; @@ -3945,6 +3999,7 @@ Tree::Tree() { cache.hover_cell = -1; allow_reselect = false; + propagate_mouse_activated = false; } Tree::~Tree() { diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 8622184bf8..45d451eb72 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -238,8 +238,8 @@ public: TreeItem *get_parent(); TreeItem *get_children(); - TreeItem *get_prev_visible(); - TreeItem *get_next_visible(); + TreeItem *get_prev_visible(bool p_wrap = false); + TreeItem *get_next_visible(bool p_wrap = false); void remove_child(TreeItem *p_item); @@ -329,6 +329,8 @@ private: bool range_drag_enabled; Vector2 range_drag_capture_pos; + bool propagate_mouse_activated; + //TreeItem *cursor_item; //int cursor_column; diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index 812ca0042b..5768f58977 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h index 5c379b5620..62fb7838b6 100644 --- a/scene/gui/video_player.h +++ b/scene/gui/video_player.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp index 8e0d1cdd38..3f7a110c1b 100644 --- a/scene/gui/viewport_container.cpp +++ b/scene/gui/viewport_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/gui/viewport_container.h b/scene/gui/viewport_container.h index 60aec25959..b4ecc583ba 100644 --- a/scene/gui/viewport_container.h +++ b/scene/gui/viewport_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 89bc8c1226..8cab1b1280 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -153,6 +153,7 @@ void CanvasLayer::_notification(int p_what) { VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas); VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent()); VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform); + _update_follow_viewport(); } break; case NOTIFICATION_EXIT_TREE: { @@ -160,6 +161,7 @@ void CanvasLayer::_notification(int p_what) { vp->_canvas_layer_remove(this); VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas); viewport = RID(); + _update_follow_viewport(false); } break; case NOTIFICATION_MOVED_IN_PARENT: { @@ -235,6 +237,41 @@ RID CanvasLayer::get_canvas() const { return canvas; } + +void CanvasLayer::set_follow_viewport(bool p_enable) { + if (follow_viewport == p_enable) { + return; + } + + follow_viewport = p_enable; + _update_follow_viewport(); +} + +bool CanvasLayer::is_following_viewport() const { + return follow_viewport; +} + +void CanvasLayer::set_follow_viewport_scale(float p_ratio) { + follow_viewport_scale = p_ratio; + _update_follow_viewport(); +} + +float CanvasLayer::get_follow_viewport_scale() const { + return follow_viewport_scale; +} + +void CanvasLayer::_update_follow_viewport(bool p_force_exit) { + + if (!is_inside_tree()) { + return; + } + if (p_force_exit || !follow_viewport) { + VS::get_singleton()->canvas_set_parent(canvas, RID(), 1.0); + } else { + VS::get_singleton()->canvas_set_parent(canvas, vp->get_world_2d()->get_canvas(), follow_viewport_scale); + } +} + void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer); @@ -255,18 +292,30 @@ void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_scale", "scale"), &CanvasLayer::set_scale); ClassDB::bind_method(D_METHOD("get_scale"), &CanvasLayer::get_scale); + ClassDB::bind_method(D_METHOD("set_follow_viewport", "enable"), &CanvasLayer::set_follow_viewport); + ClassDB::bind_method(D_METHOD("is_following_viewport"), &CanvasLayer::is_following_viewport); + + ClassDB::bind_method(D_METHOD("set_follow_viewport_scale", "scale"), &CanvasLayer::set_follow_viewport_scale); + ClassDB::bind_method(D_METHOD("get_follow_viewport_scale"), &CanvasLayer::get_follow_viewport_scale); + ClassDB::bind_method(D_METHOD("set_custom_viewport", "viewport"), &CanvasLayer::set_custom_viewport); ClassDB::bind_method(D_METHOD("get_custom_viewport"), &CanvasLayer::get_custom_viewport); ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasLayer::get_canvas); + ADD_GROUP("Layer", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer"); + ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); 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", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); + ADD_GROUP("", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport"); + ADD_GROUP("Follow Viewport", "follow_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale"); } CanvasLayer::CanvasLayer() { @@ -280,6 +329,8 @@ CanvasLayer::CanvasLayer() { custom_viewport = NULL; custom_viewport_id = 0; sort_index = 0; + follow_viewport = false; + follow_viewport_scale = 1.0; } CanvasLayer::~CanvasLayer() { diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index aae23fbb12..fa2558556c 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -55,8 +55,12 @@ class CanvasLayer : public Node { int sort_index; + bool follow_viewport; + float follow_viewport_scale; + void _update_xform(); void _update_locrotscale(); + void _update_follow_viewport(bool p_force_exit = false); protected: void _notification(int p_what); @@ -91,6 +95,12 @@ public: void reset_sort_index(); int get_sort_index(); + void set_follow_viewport(bool p_enable); + bool is_following_viewport() const; + + void set_follow_viewport_scale(float p_ratio); + float get_follow_viewport_scale() const; + RID get_canvas() const; CanvasLayer(); diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index a9b7fba9c7..e65314644e 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -220,13 +220,12 @@ bool HTTPRequest::_handle_response(bool *ret_value) { Error err; if (new_request.begins_with("http")) { // New url, request all again - err = _parse_url(new_request); + _parse_url(new_request); } else { request_string = new_request; } err = _request(); - if (err == OK) { request_sent = false; got_response = false; @@ -287,7 +286,7 @@ bool HTTPRequest::_update_connection() { call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, PoolByteArray()); return true; } - if (got_response && body_len < 0) { + if (body_len < 0) { // Chunked transfer is done call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); return true; diff --git a/scene/main/http_request.h b/scene/main/http_request.h index de09d2afda..baabda4010 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp index 0ee5648de2..71addd6fea 100644 --- a/scene/main/instance_placeholder.cpp +++ b/scene/main/instance_placeholder.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h index 2158257c93..3d0e879b2b 100644 --- a/scene/main/instance_placeholder.h +++ b/scene/main/instance_placeholder.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/main/node.cpp b/scene/main/node.cpp index ea50e7289d..ee23b24b3c 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -39,8 +39,14 @@ #include "scene/scene_string_names.h" #include "viewport.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif + VARIANT_ENUM_CAST(Node::PauseMode); +int Node::orphan_node_count = 0; + void Node::_notification(int p_notification) { switch (p_notification) { @@ -84,11 +90,14 @@ void Node::_notification(int p_notification) { add_to_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id())); get_tree()->node_count++; + orphan_node_count--; } break; case NOTIFICATION_EXIT_TREE: { get_tree()->node_count--; + orphan_node_count++; + if (data.input) remove_from_group("_vp_input" + itos(get_viewport()->get_instance_id())); if (data.unhandled_input) @@ -940,6 +949,7 @@ void Node::set_name(const String &p_name) { if (is_inside_tree()) { emit_signal("renamed"); + get_tree()->node_renamed(this); get_tree()->tree_changed(); } } @@ -959,7 +969,9 @@ void Node::set_human_readable_collision_renaming(bool p_enabled) { #ifdef TOOLS_ENABLED String Node::validate_child_name(Node *p_child) { - return _generate_serial_child_name(p_child); + StringName name = p_child->data.name; + _generate_serial_child_name(p_child, name); + return name; } #endif @@ -972,7 +984,9 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) { //this approach to autoset node names is human readable but very slow //it's turned on while running in the editor - p_child->data.name = _generate_serial_child_name(p_child); + StringName name = p_child->data.name; + _generate_serial_child_name(p_child, name); + p_child->data.name = name; } else { @@ -1034,68 +1048,92 @@ String increase_numeric_string(const String &s) { return res; } -String Node::_generate_serial_child_name(Node *p_child) { - - String name = p_child->data.name; +void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const { - if (name == "") { + if (name == StringName()) { + //no name and a new nade is needed, create one. name = p_child->get_class(); // Adjust casing according to project setting. The current type name is expected to be in PascalCase. switch (ProjectSettings::get_singleton()->get("node/name_casing").operator int()) { case NAME_CASING_PASCAL_CASE: break; - case NAME_CASING_CAMEL_CASE: - name[0] = name.to_lower()[0]; - break; + case NAME_CASING_CAMEL_CASE: { + String n = name; + n[0] = n.to_lower()[0]; + name = n; + } break; case NAME_CASING_SNAKE_CASE: - name = name.camelcase_to_underscore(true); + name = String(name).camelcase_to_underscore(true); break; } } + //quickly test if proposed name exists + int cc = data.children.size(); //children count + const Node *const *children_ptr = data.children.ptr(); + + { + + bool exists = false; + + for (int i = 0; i < cc; i++) { + if (children_ptr[i] == p_child) { //exclude self in renaming if its already a child + continue; + } + if (children_ptr[i]->data.name == name) { + exists = true; + } + } + + if (!exists) { + return; //if it does not exist, it does not need validation + } + } + // Extract trailing number + String name_string = name; String nums; - for (int i = name.length() - 1; i >= 0; i--) { - CharType n = name[i]; + for (int i = name_string.length() - 1; i >= 0; i--) { + CharType n = name_string[i]; if (n >= '0' && n <= '9') { - nums = String::chr(name[i]) + nums; + nums = String::chr(name_string[i]) + nums; } else { break; } } String nnsep = _get_name_num_separator(); - int name_last_index = name.length() - nnsep.length() - nums.length(); + int name_last_index = name_string.length() - nnsep.length() - nums.length(); // Assign the base name + separator to name if we have numbers preceded by a separator - if (nums.length() > 0 && name.substr(name_last_index, nnsep.length()) == nnsep) { - name = name.substr(0, name_last_index + nnsep.length()).strip_edges(); + if (nums.length() > 0 && name_string.substr(name_last_index, nnsep.length()) == nnsep) { + name_string = name_string.substr(0, name_last_index + nnsep.length()); } else { nums = ""; } - Vector<String> children_names; + for (;;) { + StringName attempt = name_string + nums; + bool exists = false; - for (int i = 0; i < data.children.size(); i++) { - String child_name = data.children[i]->data.name; - if (data.children[i] == p_child) - continue; - if (child_name.begins_with(name)) { - children_names.push_back(child_name); + for (int i = 0; i < cc; i++) { + if (children_ptr[i] == p_child) { + continue; + } + if (children_ptr[i]->data.name == attempt) { + exists = true; + } } - } - for (;;) { - String attempt = name + nums; - - if (children_names.find(attempt) == -1) { - return attempt; + if (!exists) { + name = attempt; + return; } else { if (nums.length() == 0) { // Name was undecorated so skip to 2 for a more natural result nums = "2"; - name += nnsep; // Add separator because nums.length() > 0 was false + name_string += nnsep; // Add separator because nums.length() > 0 was false } else { nums = increase_numeric_string(nums); } @@ -1127,7 +1165,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name) { ERR_FAIL_NULL(p_child); if (p_child == this) { - ERR_EXPLAIN("Can't add child '" + p_child->get_name() + "' to itself.") + ERR_EXPLAIN("Can't add child '" + p_child->get_name() + "' to itself."); ERR_FAIL_COND(p_child == this); // adding to itself! } @@ -1161,7 +1199,7 @@ void Node::add_child_below_node(Node *p_node, Node *p_child, bool p_legible_uniq if (is_a_parent_of(p_node)) { move_child(p_child, p_node->get_position_in_parent() + 1); } else { - WARN_PRINTS("Cannot move under node " + p_node->get_name() + " as " + p_child->get_name() + " does not share a parent.") + WARN_PRINTS("Cannot move under node " + p_node->get_name() + " as " + p_child->get_name() + " does not share a parent."); } } @@ -1283,7 +1321,11 @@ Node *Node::_get_child_by_name(const StringName &p_name) const { return NULL; } -Node *Node::_get_node(const NodePath &p_path) const { +Node *Node::get_node_or_null(const NodePath &p_path) const { + + if (p_path.is_empty()) { + return NULL; + } if (!data.inside_tree && p_path.is_absolute()) { ERR_EXPLAIN("Can't use get_node() with absolute paths from outside the active scene tree."); @@ -1348,7 +1390,7 @@ Node *Node::_get_node(const NodePath &p_path) const { Node *Node::get_node(const NodePath &p_path) const { - Node *node = _get_node(p_path); + Node *node = get_node_or_null(p_path); if (!node) { ERR_EXPLAIN("Node not found: " + p_path); ERR_FAIL_COND_V(!node, NULL); @@ -1358,7 +1400,7 @@ Node *Node::get_node(const NodePath &p_path) const { bool Node::has_node(const NodePath &p_path) const { - return _get_node(p_path) != NULL; + return get_node_or_null(p_path) != NULL; } Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const { @@ -2035,7 +2077,9 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const } } - node->set_name(get_name()); + if (get_name() != String()) { + node->set_name(get_name()); + } #ifdef TOOLS_ENABLED if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap) @@ -2389,7 +2433,7 @@ void Node::_replace_connections_target(Node *p_new_target) { if (c.flags & CONNECT_PERSIST) { c.source->disconnect(c.signal, this, c.method); - bool valid = p_new_target->has_method(c.method) || p_new_target->get_script().is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.method); + bool valid = p_new_target->has_method(c.method) || Ref<Script>(p_new_target->get_script()).is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.method); ERR_EXPLAIN("Attempt to connect signal \'" + c.source->get_class() + "." + c.signal + "\' to nonexistent method \'" + c.target->get_class() + "." + c.method + "\'"); ERR_CONTINUE(!valid); c.source->connect(c.signal, p_new_target, c.method, c.binds, c.flags); @@ -2600,10 +2644,16 @@ NodePath Node::get_import_path() const { static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) { +#ifdef TOOLS_ENABLED + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\""; +#else + const String quote_style = "\""; +#endif + if (p_node != p_base && !p_node->get_owner()) return; String n = p_base->get_path_to(p_node); - r_options->push_back("\"" + n + "\""); + r_options->push_back(quote_style + n + quote_style); for (int i = 0; i < p_node->get_child_count(); i++) { _add_nodes_to_options(p_base, p_node->get_child(i), r_options); } @@ -2681,6 +2731,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_child", "idx"), &Node::get_child); ClassDB::bind_method(D_METHOD("has_node", "path"), &Node::has_node); ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node); + ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null); ClassDB::bind_method(D_METHOD("get_parent"), &Node::get_parent); ClassDB::bind_method(D_METHOD("find_node", "mask", "recursive", "owned"), &Node::find_node, DEFVAL(true), DEFVAL(true)); ClassDB::bind_method(D_METHOD("find_parent", "mask"), &Node::find_parent); @@ -2726,6 +2777,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process); ClassDB::bind_method(D_METHOD("print_stray_nodes"), &Node::_print_stray_nodes); ClassDB::bind_method(D_METHOD("get_position_in_parent"), &Node::get_position_in_parent); + ClassDB::bind_method(D_METHOD("set_display_folded", "fold"), &Node::set_display_folded); ClassDB::bind_method(D_METHOD("is_displayed_folded"), &Node::is_displayed_folded); @@ -2801,10 +2853,22 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN); BIND_CONSTANT(NOTIFICATION_DRAG_END); BIND_CONSTANT(NOTIFICATION_PATH_CHANGED); - BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS); BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS); + BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER); + BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT); + BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN); + BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT); + BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST); + BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST); + BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST); + BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING); + BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); + BIND_CONSTANT(NOTIFICATION_WM_ABOUT); + BIND_CONSTANT(NOTIFICATION_CRASH); + BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE); + BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT); BIND_ENUM_CONSTANT(PAUSE_MODE_STOP); BIND_ENUM_CONSTANT(PAUSE_MODE_PROCESS); @@ -2826,7 +2890,12 @@ void Node::_bind_methods() { //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), "set_process_unhandled_input","is_processing_unhandled_input" ) ; ADD_GROUP("Pause", "pause_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_display_folded", "is_displayed_folded"); + +#ifdef ENABLE_DEPRECATED + //no longer exists, but remains for compatibility (keep previous scenes folded + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", 0), "set_display_folded", "is_displayed_folded"); +#endif + ADD_PROPERTY(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner"); @@ -2887,6 +2956,8 @@ Node::Node() { data.use_placeholder = false; data.display_folded = false; data.ready_first = true; + + orphan_node_count++; } Node::~Node() { @@ -2897,6 +2968,8 @@ Node::~Node() { ERR_FAIL_COND(data.parent); ERR_FAIL_COND(data.children.size()); + + orphan_node_count--; } //////////////////////////////// diff --git a/scene/main/node.h b/scene/main/node.h index 78db12dda9..9b9ca06455 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -75,6 +75,8 @@ public: bool operator()(const Node *p_a, const Node *p_b) const { return p_b->data.process_priority == p_a->data.process_priority ? p_b->is_greater_than(p_a) : p_b->data.process_priority > p_a->data.process_priority; } }; + static int orphan_node_count; + private: struct GroupData { @@ -153,13 +155,12 @@ private: void _print_tree_pretty(const String prefix, const bool last); void _print_tree(const Node *p_node); - Node *_get_node(const NodePath &p_path) const; Node *_get_child_by_name(const StringName &p_name) const; void _replace_connections_target(Node *p_new_target); void _validate_child_name(Node *p_child, bool p_force_human_readable = false); - String _generate_serial_child_name(Node *p_child); + void _generate_serial_child_name(const Node *p_child, StringName &name) const; void _propagate_reverse_notification(int p_notification); void _propagate_deferred_notification(int p_notification, bool p_reverse); @@ -217,6 +218,7 @@ protected: public: enum { + // you can make your own, but don't use the same numbers as other notifications in other nodes NOTIFICATION_ENTER_TREE = 10, NOTIFICATION_EXIT_TREE = 11, @@ -232,10 +234,23 @@ public: NOTIFICATION_DRAG_BEGIN = 21, NOTIFICATION_DRAG_END = 22, NOTIFICATION_PATH_CHANGED = 23, - NOTIFICATION_TRANSLATION_CHANGED = 24, + //NOTIFICATION_TRANSLATION_CHANGED = 24, moved below NOTIFICATION_INTERNAL_PROCESS = 25, NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26, NOTIFICATION_POST_ENTER_TREE = 27, + //keep these linked to node + NOTIFICATION_WM_MOUSE_ENTER = MainLoop::NOTIFICATION_WM_MOUSE_ENTER, + NOTIFICATION_WM_MOUSE_EXIT = MainLoop::NOTIFICATION_WM_MOUSE_EXIT, + NOTIFICATION_WM_FOCUS_IN = MainLoop::NOTIFICATION_WM_FOCUS_IN, + NOTIFICATION_WM_FOCUS_OUT = MainLoop::NOTIFICATION_WM_FOCUS_OUT, + NOTIFICATION_WM_QUIT_REQUEST = MainLoop::NOTIFICATION_WM_QUIT_REQUEST, + NOTIFICATION_WM_GO_BACK_REQUEST = MainLoop::NOTIFICATION_WM_GO_BACK_REQUEST, + NOTIFICATION_WM_UNFOCUS_REQUEST = MainLoop::NOTIFICATION_WM_UNFOCUS_REQUEST, + NOTIFICATION_OS_MEMORY_WARNING = MainLoop::NOTIFICATION_OS_MEMORY_WARNING, + NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED, + NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT, + NOTIFICATION_CRASH = MainLoop::NOTIFICATION_CRASH, + NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE }; @@ -252,6 +267,7 @@ public: Node *get_child(int p_index) const; bool has_node(const NodePath &p_path) const; Node *get_node(const NodePath &p_path) const; + Node *get_node_or_null(const NodePath &p_path) const; Node *find_node(const String &p_mask, bool p_recursive = true, bool p_owned = true) const; bool has_node_and_resource(const NodePath &p_path) const; Node *get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const; diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp index dbe7daa604..cb1168b73e 100644 --- a/scene/main/resource_preloader.cpp +++ b/scene/main/resource_preloader.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/main/resource_preloader.h b/scene/main/resource_preloader.h index 98c7b21f37..3e3be4ac82 100644 --- a/scene/main/resource_preloader.h +++ b/scene/main/resource_preloader.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index be4878588e..7f0cebd492 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -105,6 +105,11 @@ void SceneTree::node_removed(Node *p_node) { call_skip.insert(p_node); } +void SceneTree::node_renamed(Node *p_node) { + + emit_signal(node_renamed_name, p_node); +} + SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_node) { Map<StringName, Group>::Element *E = group_map.find(p_group); @@ -369,8 +374,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group } void SceneTree::call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) { - - call_group_flags(0, p_group, VARIANT_ARG_PASS); + call_group_flags(0, p_group, p_function, VARIANT_ARG_PASS); } void SceneTree::notify_group(const StringName &p_group, int p_notification) { @@ -484,6 +488,14 @@ bool SceneTree::iteration(float p_time) { return _quit; } +void SceneTree::_update_font_oversampling(float p_ratio) { + + if (use_font_oversampling) { + DynamicFontAtSize::font_oversampling = p_ratio; + DynamicFont::update_oversampling(); + } +} + bool SceneTree::idle(float p_time) { //print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage())); @@ -515,12 +527,6 @@ bool SceneTree::idle(float p_time) { last_screen_size = win_size; _update_root_rect(); - - if (use_font_oversampling) { - DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width; - DynamicFont::update_oversampling(); - } - emit_signal("screen_resized"); } @@ -656,13 +662,15 @@ void SceneTree::_notification(int p_notification) { } break; case NOTIFICATION_TRANSLATION_CHANGED: { if (!Engine::get_singleton()->is_editor_hint()) { - get_root()->propagate_notification(Node::NOTIFICATION_TRANSLATION_CHANGED); + get_root()->propagate_notification(p_notification); } } break; case NOTIFICATION_WM_UNFOCUS_REQUEST: { notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST); + get_root()->propagate_notification(p_notification); + } break; case NOTIFICATION_WM_ABOUT: { @@ -1133,10 +1141,12 @@ void SceneTree::_update_root_rect() { if (stretch_mode == STRETCH_MODE_DISABLED) { + _update_font_oversampling(1.0); root->set_size((last_screen_size / stretch_shrink).floor()); root->set_attach_to_screen_rect(Rect2(Point2(), last_screen_size)); root->set_size_override_stretch(false); root->set_size_override(false, Size2()); + root->update_canvas_items(); return; //user will take care } @@ -1150,7 +1160,11 @@ void SceneTree::_update_root_rect() { float viewport_aspect = desired_res.aspect(); float video_mode_aspect = video_mode.aspect(); - if (stretch_aspect == STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect) < CMP_EPSILON) { + if (use_font_oversampling && stretch_aspect == STRETCH_ASPECT_IGNORE) { + WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'."); + } + + if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) { //same aspect or ignore aspect viewport_size = desired_res; screen_size = video_mode; @@ -1208,21 +1222,30 @@ void SceneTree::_update_root_rect() { switch (stretch_mode) { case STRETCH_MODE_DISABLED: { // Already handled above + _update_font_oversampling(1.0); } break; case STRETCH_MODE_2D: { + _update_font_oversampling(screen_size.x / viewport_size.x); //screen / viewport radio drives oversampling root->set_size((screen_size / stretch_shrink).floor()); root->set_attach_to_screen_rect(Rect2(margin, screen_size)); root->set_size_override_stretch(true); root->set_size_override(true, (viewport_size / stretch_shrink).floor()); + root->update_canvas_items(); //force them to update just in case } break; case STRETCH_MODE_VIEWPORT: { + _update_font_oversampling(1.0); root->set_size((viewport_size / stretch_shrink).floor()); root->set_attach_to_screen_rect(Rect2(margin, screen_size)); root->set_size_override_stretch(false); root->set_size_override(false, Size2()); + root->update_canvas_items(); //force them to update just in case + + if (use_font_oversampling) { + WARN_PRINT("Font oversampling does not work in 'Viewport' stretch mode, only '2D'."); + } } break; } @@ -1877,6 +1900,7 @@ void SceneTree::_bind_methods() { ADD_SIGNAL(MethodInfo("tree_changed")); ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("screen_resized")); ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); @@ -1925,12 +1949,11 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) { void SceneTree::set_use_font_oversampling(bool p_oversampling) { + if (use_font_oversampling == p_oversampling) + return; + use_font_oversampling = p_oversampling; - if (use_font_oversampling) { - DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width; - } else { - DynamicFontAtSize::font_oversampling = 1.0; - } + _update_root_rect(); } bool SceneTree::is_using_font_oversampling() const { @@ -1944,6 +1967,7 @@ SceneTree::SceneTree() { accept_quit = true; quit_on_go_back = true; initialized = false; + use_font_oversampling = false; #ifdef DEBUG_ENABLED debug_collisions_hint = false; debug_navigation_hint = false; @@ -1965,6 +1989,7 @@ SceneTree::SceneTree() { tree_changed_name = "tree_changed"; node_added_name = "node_added"; node_removed_name = "node_removed"; + node_renamed_name = "node_renamed"; ugc_locked = false; call_lock = 0; root_lock = 0; @@ -2079,8 +2104,6 @@ SceneTree::SceneTree() { live_edit_root = NodePath("/root"); #endif - - use_font_oversampling = false; } SceneTree::~SceneTree() { diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index d59cbe05fb..0bcb724929 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -43,7 +43,6 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class SceneTree; class PackedScene; class Node; class Viewport; @@ -127,6 +126,7 @@ private: StringName tree_changed_name; StringName node_added_name; StringName node_removed_name; + StringName node_renamed_name; bool use_font_oversampling; int64_t current_frame; @@ -153,6 +153,7 @@ private: Size2i stretch_min; real_t stretch_shrink; + void _update_font_oversampling(float p_ratio); void _update_root_rect(); List<ObjectID> delete_queue; @@ -201,6 +202,7 @@ private: void tree_changed(); void node_added(Node *p_node); void node_removed(Node *p_node); + void node_renamed(Node *p_node); Group *add_to_group(const StringName &p_group, Node *p_node); void remove_from_group(const StringName &p_group, Node *p_node); @@ -287,7 +289,7 @@ protected: public: enum { - NOTIFICATION_TRANSFORM_CHANGED = 29 + NOTIFICATION_TRANSFORM_CHANGED = 2000 }; enum GroupCallFlags { diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index 227840531e..2ae950dad5 100755 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/main/timer.h b/scene/main/timer.h index 2f42252a7e..c492c6b61c 100755 --- a/scene/main/timer.h +++ b/scene/main/timer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 7f5dd39302..f8a0db18b1 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,8 +37,8 @@ #include "scene/3d/camera.h" #include "scene/3d/collision_object.h" #include "scene/3d/listener.h" -#include "scene/3d/scenario_fx.h" #include "scene/3d/spatial.h" +#include "scene/3d/world_environment.h" #include "scene/gui/control.h" #include "scene/gui/label.h" #include "scene/gui/menu_button.h" @@ -148,7 +148,7 @@ void ViewportTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene); ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport"), "set_viewport_path_in_scene", "get_viewport_path_in_scene"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene"); } ViewportTexture::ViewportTexture() { @@ -172,14 +172,16 @@ ViewportTexture::~ViewportTexture() { class TooltipPanel : public PanelContainer { - GDCLASS(TooltipPanel, PanelContainer) + GDCLASS(TooltipPanel, PanelContainer); + public: TooltipPanel(){}; }; class TooltipLabel : public Label { - GDCLASS(TooltipLabel, Label) + GDCLASS(TooltipLabel, Label); + public: TooltipLabel(){}; }; @@ -232,16 +234,16 @@ void Viewport::update_worlds() { find_world()->_update(get_tree()->get_frame()); } -void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape, bool p_discard_empty_motion) { +void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { Transform object_transform = p_object->get_global_transform(); Transform camera_transform = p_camera->get_global_transform(); ObjectID id = p_object->get_instance_id(); - if (p_discard_empty_motion) { - //avoid sending the event unnecesarily if nothing really changed in the context + //avoid sending the fake event unnecessarily if nothing really changed in the context + if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) { Ref<InputEventMouseMotion> mm = p_input_event; - if (mm.is_valid() && object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) { + if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { return; //discarded } } @@ -251,31 +253,6 @@ void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera * physics_last_id = id; } -void Viewport::_test_new_mouseover(ObjectID new_collider) { -#ifndef _3D_DISABLED - if (new_collider != physics_object_over) { - - if (physics_object_over) { - - CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over)); - if (co) { - co->_mouse_exit(); - } - } - - if (new_collider) { - - CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider)); - if (co) { - co->_mouse_enter(); - } - } - - physics_object_over = new_collider; - } -#endif -} - void Viewport::_notification(int p_what) { switch (p_what) { @@ -416,28 +393,30 @@ void Viewport::_notification(int p_what) { if (physics_object_picking && (to_screen_rect == Rect2() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) { +#ifndef _3D_DISABLED Vector2 last_pos(1e20, 1e20); CollisionObject *last_object = NULL; ObjectID last_id = 0; +#endif PhysicsDirectSpaceState::RayResult result; Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); - bool discard_empty_motion = false; - - { // if no motion event exists, create a new one. This is necessary because objects or camera may have moved. - // while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecesary motion events every frame - bool has_mouse_motion = false; + if (physics_has_last_mousepos) { + // if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved. + // while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame + bool has_mouse_event = false; for (List<Ref<InputEvent> >::Element *E = physics_picking_events.front(); E; E = E->next()) { - Ref<InputEventMouseMotion> mm = E->get(); - if (mm.is_valid()) { - has_mouse_motion = true; + Ref<InputEventMouse> m = E->get(); + if (m.is_valid()) { + has_mouse_event = true; break; } } - if (!has_mouse_motion && physics_has_last_mousepos) { + if (!has_mouse_event) { Ref<InputEventMouseMotion> mm; mm.instance(); + mm->set_device(InputEvent::DEVICE_ID_INTERNAL); mm->set_global_position(physics_last_mousepos); mm->set_position(physics_last_mousepos); mm->set_alt(physics_last_mouse_state.alt); @@ -446,25 +425,24 @@ void Viewport::_notification(int p_what) { mm->set_metakey(physics_last_mouse_state.meta); mm->set_button_mask(physics_last_mouse_state.mouse_mask); physics_picking_events.push_back(mm); - discard_empty_motion = true; } } - bool motion_tested = false; - while (physics_picking_events.size()) { Ref<InputEvent> ev = physics_picking_events.front()->get(); physics_picking_events.pop_front(); Vector2 pos; + bool is_mouse = false; Ref<InputEventMouseMotion> mm = ev; if (mm.is_valid()) { pos = mm->get_position(); - motion_tested = true; + is_mouse = true; + physics_has_last_mousepos = true; physics_last_mousepos = pos; physics_last_mouse_state.alt = mm->get_alt(); @@ -477,7 +455,12 @@ void Viewport::_notification(int p_what) { Ref<InputEventMouseButton> mb = ev; if (mb.is_valid()) { + pos = mb->get_position(); + is_mouse = true; + + physics_has_last_mousepos = true; + physics_last_mousepos = pos; physics_last_mouse_state.alt = mb->get_alt(); physics_last_mouse_state.shift = mb->get_shift(); physics_last_mouse_state.control = mb->get_control(); @@ -487,6 +470,11 @@ void Viewport::_notification(int p_what) { physics_last_mouse_state.mouse_mask |= (1 << (mb->get_button_index() - 1)); } else { physics_last_mouse_state.mouse_mask &= ~(1 << (mb->get_button_index() - 1)); + + // If touch mouse raised, assume we don't know last mouse pos until new events come + if (mb->get_device() == InputEvent::DEVICE_ID_TOUCH_MOUSE) { + physics_has_last_mousepos = false; + } } } @@ -539,40 +527,51 @@ void Viewport::_notification(int p_what) { if (res[i].collider_id && res[i].collider) { CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider); if (co) { - - Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.find(res[i].collider_id); - if (!E) { - E = physics_2d_mouseover.insert(res[i].collider_id, frame); - co->_mouse_enter(); - } else { - E->get() = frame; + bool send_event = true; + if (is_mouse) { + Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id); + + if (!F) { + F = physics_2d_mouseover.insert(res[i].collider_id, frame); + co->_mouse_enter(); + } else { + F->get() = frame; + // It was already hovered, so don't send the event if it's faked + if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { + send_event = false; + } + } } - co->_input_event(this, ev, res[i].shape); + if (send_event) { + co->_input_event(this, ev, res[i].shape); + } } } } } - List<Map<ObjectID, uint64_t>::Element *> to_erase; + if (is_mouse) { + List<Map<ObjectID, uint64_t>::Element *> to_erase; - for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) { - if (E->get() != frame) { - Object *o = ObjectDB::get_instance(E->key()); - if (o) { + for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) { + if (E->get() != frame) { + Object *o = ObjectDB::get_instance(E->key()); + if (o) { - CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); - if (co) { - co->_mouse_exit(); + CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); + if (co) { + co->_mouse_exit(); + } } + to_erase.push_back(E); } - to_erase.push_back(E); } - } - while (to_erase.size()) { - physics_2d_mouseover.erase(to_erase.front()->get()); - to_erase.pop_front(); + while (to_erase.size()) { + physics_2d_mouseover.erase(to_erase.front()->get()); + to_erase.pop_front(); + } } } @@ -583,7 +582,7 @@ void Viewport::_notification(int p_what) { CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture)); if (co) { - _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0, discard_empty_motion); + _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0); captured = true; if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) { physics_object_capture = 0; @@ -601,7 +600,7 @@ void Viewport::_notification(int p_what) { if (last_id) { if (ObjectDB::get_instance(last_id) && last_object) { //good, exists - _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape, discard_empty_motion); + _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape); if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { physics_object_capture = last_id; } @@ -624,7 +623,7 @@ void Viewport::_notification(int p_what) { CollisionObject *co = Object::cast_to<CollisionObject>(result.collider); if (co) { - _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape, discard_empty_motion); + _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape); last_object = co; last_id = result.collider_id; new_collider = last_id; @@ -634,42 +633,41 @@ void Viewport::_notification(int p_what) { } } - if (mm.is_valid()) { - _test_new_mouseover(new_collider); - } - } + if (is_mouse && new_collider != physics_object_over) { - last_pos = pos; - } - } - } + if (physics_object_over) { - if (!motion_tested && camera && physics_has_last_mousepos) { + CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over)); + if (co) { + co->_mouse_exit(); + } + } - //test anyway for mouseenter/exit because objects might move - Vector3 from = camera->project_ray_origin(physics_last_mousepos); - Vector3 dir = camera->project_ray_normal(physics_last_mousepos); + if (new_collider) { - PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space()); - if (space) { + CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider)); + if (co) { + co->_mouse_enter(); + } + } - bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true); - ObjectID new_collider = 0; - if (col) { - CollisionObject *co = Object::cast_to<CollisionObject>(result.collider); - if (co) { - new_collider = result.collider_id; + physics_object_over = new_collider; + } } - } - _test_new_mouseover(new_collider); + last_pos = pos; + } } #endif } } } break; + case SceneTree::NOTIFICATION_WM_MOUSE_EXIT: case SceneTree::NOTIFICATION_WM_FOCUS_OUT: { + + _drop_physics_mouseover(); + if (gui.mouse_focus) { //if mouse is being pressed, send a release event _drop_mouse_focus(); @@ -693,6 +691,13 @@ bool Viewport::use_arvr() { return arvr; } +void Viewport::update_canvas_items() { + if (!is_inside_tree()) + return; + + _update_canvas_items(this); +} + void Viewport::set_size(const Size2 &p_size) { if (size == p_size.floor()) @@ -883,7 +888,7 @@ void Viewport::_camera_set(Camera *p_camera) { if (camera == p_camera) return; - if (camera && find_world().is_valid()) { + if (camera) { camera->notification(Camera::NOTIFICATION_LOST_CURRENT); } camera = p_camera; @@ -892,7 +897,7 @@ void Viewport::_camera_set(Camera *p_camera) { else VisualServer::get_singleton()->viewport_attach_camera(viewport, RID()); - if (camera && find_world().is_valid()) { + if (camera) { camera->notification(Camera::NOTIFICATION_BECAME_CURRENT); } @@ -911,9 +916,7 @@ void Viewport::_camera_remove(Camera *p_camera) { cameras.erase(p_camera); if (camera == p_camera) { - if (camera && find_world().is_valid()) { - camera->notification(Camera::NOTIFICATION_LOST_CURRENT); - } + camera->notification(Camera::NOTIFICATION_LOST_CURRENT); camera = NULL; } } @@ -1010,7 +1013,7 @@ void Viewport::_propagate_enter_world(Node *p_node) { Viewport *v = Object::cast_to<Viewport>(p_node); if (v) { - if (v->world.is_valid()) + if (v->world.is_valid() || v->own_world.is_valid()) return; } } @@ -1047,7 +1050,7 @@ void Viewport::_propagate_exit_world(Node *p_node) { Viewport *v = Object::cast_to<Viewport>(p_node); if (v) { - if (v->world.is_valid()) + if (v->world.is_valid() || v->own_world.is_valid()) return; } } @@ -1067,23 +1070,11 @@ void Viewport::set_world(const Ref<World> &p_world) { if (is_inside_tree()) _propagate_exit_world(this); -#ifndef _3D_DISABLED - if (find_world().is_valid() && camera) - camera->notification(Camera::NOTIFICATION_LOST_CURRENT); -#endif - world = p_world; if (is_inside_tree()) _propagate_enter_world(this); -#ifndef _3D_DISABLED - if (find_world().is_valid() && camera) - camera->notification(Camera::NOTIFICATION_BECAME_CURRENT); -#endif - - //propagate exit - if (is_inside_tree()) { VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario()); } @@ -1128,6 +1119,26 @@ Transform2D Viewport::get_final_transform() const { return stretch_transform * global_canvas_transform; } +void Viewport::_update_canvas_items(Node *p_node) { + if (p_node != this) { + + Viewport *vp = Object::cast_to<Viewport>(p_node); + if (vp) + return; + + CanvasItem *ci = Object::cast_to<CanvasItem>(p_node); + if (ci) { + ci->update(); + } + } + + int cc = p_node->get_child_count(); + + for (int i = 0; i < cc; i++) { + _update_canvas_items(p_node->get_child(i)); + } +} + void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vector2 &p_margin) { if (size_override == p_enable && p_size == size_override_size) @@ -1459,7 +1470,8 @@ void Viewport::_gui_show_tooltip() { gui.tooltip_popup->set_as_toplevel(true); //gui.tooltip_popup->hide(); - Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_popup->get_minimum_size()); + Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset"); + Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size()); Rect2 vr = gui.tooltip_popup->get_viewport_rect(); if (r.size.x + r.position.x > vr.size.x) r.position.x = vr.size.x - r.size.x; @@ -1533,6 +1545,35 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu //_unblock(); } +void Viewport::_gui_call_notification(Control *p_control, int p_what) { + + CanvasItem *ci = p_control; + while (ci) { + + Control *control = Object::cast_to<Control>(ci); + if (control) { + + if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) { + control->notification(p_what); + } + + if (!control->is_inside_tree()) + break; + + if (!control->is_inside_tree() || control->is_set_as_toplevel()) + break; + if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) + break; + } + + if (ci->is_set_as_toplevel()) + break; + + ci = ci->get_parent_item(); + } + + //_unblock(); +} Control *Viewport::_gui_find_control(const Point2 &p_global) { _gui_prepare_subwindows(); @@ -1691,8 +1732,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { while (!gui.modal_stack.empty()) { Control *top = gui.modal_stack.back()->get(); - Vector2 pos = top->get_global_transform_with_canvas().affine_inverse().xform(mpos); - if (!top->has_point(pos)) { + Vector2 pos2 = top->get_global_transform_with_canvas().affine_inverse().xform(mpos); + if (!top->has_point(pos2)) { if (top->data.modal_exclusive || top->data.modal_frame == Engine::get_singleton()->get_frames_drawn()) { //cancel event, sorry, modal exclusive EATS UP ALL @@ -1727,13 +1768,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { */ gui.mouse_focus = _gui_find_control(pos); - gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1); gui.last_mouse_focus = gui.mouse_focus; if (!gui.mouse_focus) { + gui.mouse_focus_mask = 0; return; } + gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1); + if (mb->get_button_index() == BUTTON_LEFT) { gui.drag_accum = Vector2(); gui.drag_attempted = false; @@ -1975,13 +2018,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (over != gui.mouse_over) { - if (gui.mouse_over) - gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT); + if (gui.mouse_over) { + _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT); + } _gui_cancel_tooltip(); - if (over) - over->notification(Control::NOTIFICATION_MOUSE_ENTER); + if (over) { + _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER); + } } gui.mouse_over = over; @@ -2245,32 +2290,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (from && p_event->is_pressed()) { Control *next = NULL; - if (p_event->is_action("ui_focus_next")) { + if (p_event->is_action_pressed("ui_focus_next")) { next = from->find_next_valid_focus(); } - if (p_event->is_action("ui_focus_prev")) { + if (p_event->is_action_pressed("ui_focus_prev")) { next = from->find_prev_valid_focus(); } - if (!mods && p_event->is_action("ui_up")) { + if (!mods && p_event->is_action_pressed("ui_up")) { next = from->_get_focus_neighbour(MARGIN_TOP); } - if (!mods && p_event->is_action("ui_left")) { + if (!mods && p_event->is_action_pressed("ui_left")) { next = from->_get_focus_neighbour(MARGIN_LEFT); } - if (!mods && p_event->is_action("ui_right")) { + if (!mods && p_event->is_action_pressed("ui_right")) { next = from->_get_focus_neighbour(MARGIN_RIGHT); } - if (!mods && p_event->is_action("ui_down")) { + if (!mods && p_event->is_action_pressed("ui_down")) { next = from->_get_focus_neighbour(MARGIN_BOTTOM); } @@ -2425,11 +2470,7 @@ void Viewport::_gui_hid_control(Control *p_control) { if (gui.mouse_over == p_control) gui.mouse_over = NULL; if (gui.tooltip == p_control) - gui.tooltip = NULL; - if (gui.tooltip == p_control) { - gui.tooltip = NULL; _gui_cancel_tooltip(); - } } void Viewport::_gui_remove_control(Control *p_control) { @@ -2438,6 +2479,9 @@ void Viewport::_gui_remove_control(Control *p_control) { gui.mouse_focus = NULL; gui.mouse_focus_mask = 0; } + if (gui.last_mouse_focus == p_control) { + gui.last_mouse_focus = NULL; + } if (gui.key_focus == p_control) gui.key_focus = NULL; if (gui.mouse_over == p_control) @@ -2507,6 +2551,31 @@ void Viewport::_drop_mouse_focus() { } } +void Viewport::_drop_physics_mouseover() { + + physics_has_last_mousepos = false; + + while (physics_2d_mouseover.size()) { + Object *o = ObjectDB::get_instance(physics_2d_mouseover.front()->key()); + if (o) { + CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); + co->_mouse_exit(); + } + physics_2d_mouseover.erase(physics_2d_mouseover.front()); + } + +#ifndef _3D_DISABLED + if (physics_object_over) { + CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over)); + if (co) { + co->_mouse_exit(); + } + } + + physics_object_over = physics_object_capture = 0; +#endif +} + List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) { gui.modal_stack.push_back(p_control); @@ -2641,11 +2710,6 @@ void Viewport::set_use_own_world(bool p_world) { if (is_inside_tree()) _propagate_exit_world(this); -#ifndef _3D_DISABLED - if (find_world().is_valid() && camera) - camera->notification(Camera::NOTIFICATION_LOST_CURRENT); -#endif - if (!p_world) own_world = Ref<World>(); else @@ -2654,13 +2718,6 @@ void Viewport::set_use_own_world(bool p_world) { if (is_inside_tree()) _propagate_enter_world(this); -#ifndef _3D_DISABLED - if (find_world().is_valid() && camera) - camera->notification(Camera::NOTIFICATION_BECAME_CURRENT); -#endif - - //propagate exit - if (is_inside_tree()) { VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario()); } @@ -2684,6 +2741,19 @@ Rect2 Viewport::get_attach_to_screen_rect() const { return to_screen_rect; } +void Viewport::set_use_render_direct_to_screen(bool p_render_direct_to_screen) { + + if (p_render_direct_to_screen == render_direct_to_screen) + return; + + render_direct_to_screen = p_render_direct_to_screen; + VS::get_singleton()->viewport_set_render_direct_to_screen(viewport, p_render_direct_to_screen); +} + +bool Viewport::is_using_render_direct_to_screen() const { + return render_direct_to_screen; +} + void Viewport::set_physics_object_picking(bool p_enable) { physics_object_picking = p_enable; @@ -2862,6 +2932,13 @@ bool Viewport::is_handling_input_locally() const { return handle_input_locally; } +void Viewport::_validate_property(PropertyInfo &property) const { + + if (VisualServer::get_singleton()->is_low_end() && property.name == "hdr") { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } +} + void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr); @@ -2942,6 +3019,8 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d); ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d); ClassDB::bind_method(D_METHOD("set_attach_to_screen_rect", "rect"), &Viewport::set_attach_to_screen_rect); + ClassDB::bind_method(D_METHOD("set_use_render_direct_to_screen", "enable"), &Viewport::set_use_render_direct_to_screen); + ClassDB::bind_method(D_METHOD("is_using_render_direct_to_screen"), &Viewport::is_using_render_direct_to_screen); ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position); ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse); @@ -2996,6 +3075,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear"); ADD_PROPERTY(PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_ENUM, "2D,2D No-Sampling,3D,3D No-Effects"), "set_usage", "get_usage"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_direct_to_screen"), "set_use_render_direct_to_screen", "is_using_render_direct_to_screen"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); ADD_GROUP("Render Target", "render_target_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_target_v_flip"), "set_vflip", "get_vflip"); @@ -3078,6 +3158,8 @@ Viewport::Viewport() { texture_rid = VisualServer::get_singleton()->viewport_get_texture(viewport); texture_flags = 0; + render_direct_to_screen = false; + default_texture.instance(); default_texture->vp = const_cast<Viewport *>(this); viewport_textures.insert(default_texture.ptr()); @@ -3132,7 +3214,7 @@ Viewport::Viewport() { gui.tooltip_timer = -1; //gui.tooltip_timer->force_parent_owned(); - gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.7); + gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5); ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::REAL, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers gui.tooltip = NULL; @@ -3141,6 +3223,8 @@ Viewport::Viewport() { gui.drag_attempted = false; gui.canvas_sort_index = 0; gui.roots_order_dirty = false; + gui.mouse_focus = NULL; + gui.last_mouse_focus = NULL; msaa = MSAA_DISABLED; hdr = true; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index b75ebeeec5..b7160d5139 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -182,6 +182,7 @@ private: Size2 size; Rect2 to_screen_rect; + bool render_direct_to_screen; RID contact_2d_debug; RID contact_3d_debug_multimesh; @@ -221,12 +222,11 @@ private: } physics_last_mouse_state; - void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape, bool p_discard_empty_motion); + void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape); bool handle_input_locally; bool local_input_handled; - void _test_new_mouseover(ObjectID new_collider); Map<ObjectID, uint64_t> physics_2d_mouseover; Ref<World2D> world_2d; @@ -305,6 +305,8 @@ private: bool disable_input; void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input); + void _gui_call_notification(Control *p_control, int p_what); + void _gui_prepare_subwindows(); void _gui_sort_subwindows(); void _gui_sort_roots(); @@ -382,10 +384,14 @@ private: void _canvas_layer_remove(CanvasLayer *p_canvas_layer); void _drop_mouse_focus(); + void _drop_physics_mouseover(); + + void _update_canvas_items(Node *p_node); protected: void _notification(int p_what); static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const; public: Listener *get_listener() const; @@ -401,6 +407,7 @@ public: bool is_audio_listener_2d() const; void set_size(const Size2 &p_size); + void update_canvas_items(); Size2 get_size() const; Rect2 get_visible_rect() const; @@ -475,6 +482,9 @@ public: void set_attach_to_screen_rect(const Rect2 &p_rect); Rect2 get_attach_to_screen_rect() const; + void set_use_render_direct_to_screen(bool p_render_direct_to_screen); + bool is_using_render_direct_to_screen() const; + Vector2 get_mouse_position() const; void warp_mouse(const Vector2 &p_pos); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index ae6211a3df..0423fcb5f0 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -48,7 +48,8 @@ #include "scene/2d/light_occluder_2d.h" #include "scene/2d/line_2d.h" #include "scene/2d/mesh_instance_2d.h" -#include "scene/2d/navigation2d.h" +#include "scene/2d/multimesh_instance_2d.h" +#include "scene/2d/navigation_2d.h" #include "scene/2d/parallax_background.h" #include "scene/2d/parallax_layer.h" #include "scene/2d/particles_2d.h" @@ -58,10 +59,10 @@ #include "scene/2d/position_2d.h" #include "scene/2d/ray_cast_2d.h" #include "scene/2d/remote_transform_2d.h" -#include "scene/2d/screen_button.h" #include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite.h" #include "scene/2d/tile_map.h" +#include "scene/2d/touch_screen_button.h" #include "scene/2d/visibility_notifier_2d.h" #include "scene/2d/y_sort.h" #include "scene/animation/animation_blend_space_1d.h" @@ -73,7 +74,7 @@ #include "scene/animation/animation_tree_player.h" #include "scene/animation/root_motion_view.h" #include "scene/animation/tween.h" -#include "scene/audio/audio_player.h" +#include "scene/audio/audio_stream_player.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/center_container.h" @@ -125,12 +126,11 @@ #include "scene/main/timer.h" #include "scene/main/viewport.h" #include "scene/resources/audio_stream_sample.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" #include "scene/resources/box_shape.h" #include "scene/resources/capsule_shape.h" #include "scene/resources/capsule_shape_2d.h" #include "scene/resources/circle_shape_2d.h" -#include "scene/resources/color_ramp.h" #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape.h" @@ -139,21 +139,23 @@ #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" #include "scene/resources/material.h" #include "scene/resources/mesh.h" #include "scene/resources/mesh_data_tool.h" -#include "scene/resources/mesh_library.h" #include "scene/resources/packed_scene.h" #include "scene/resources/particles_material.h" +#include "scene/resources/physics_material.h" #include "scene/resources/plane_shape.h" #include "scene/resources/polygon_path_finder.h" #include "scene/resources/primitive_meshes.h" #include "scene/resources/ray_shape.h" #include "scene/resources/rectangle_shape_2d.h" -#include "scene/resources/scene_format_text.h" +#include "scene/resources/resource_format_text.h" #include "scene/resources/segment_shape_2d.h" -#include "scene/resources/shape_line_2d.h" -#include "scene/resources/sky_box.h" +#include "scene/resources/sky.h" #include "scene/resources/sphere_shape.h" #include "scene/resources/surface_tool.h" #include "scene/resources/text_file.h" @@ -166,8 +168,8 @@ #include "scene/resources/world_2d.h" #include "scene/scene_string_names.h" -#include "scene/3d/scenario_fx.h" #include "scene/3d/spatial.h" +#include "scene/3d/world_environment.h" #ifndef _3D_DISABLED #include "scene/3d/area.h" @@ -207,7 +209,7 @@ #include "scene/3d/visibility_notifier.h" #include "scene/animation/skeleton_ik.h" #include "scene/resources/environment.h" -#include "scene/resources/physics_material.h" +#include "scene/resources/mesh_library.h" #endif static Ref<ResourceFormatSaverText> resource_saver_text; @@ -452,7 +454,6 @@ void register_scene_types() { ClassDB::register_class<Curve3D>(); ClassDB::register_class<Path>(); ClassDB::register_class<PathFollow>(); - ClassDB::register_class<OrientedPathFollow>(); ClassDB::register_class<VisibilityNotifier>(); ClassDB::register_class<VisibilityEnabler>(); ClassDB::register_class<WorldEnvironment>(); @@ -468,7 +469,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init #endif - ClassDB::register_class<MeshLibrary>(); + AcceptDialog::set_swap_ok_cancel(GLOBAL_DEF("gui/common/swap_ok_cancel", bool(OS::get_singleton()->get_swap_ok_cancel()))); ClassDB::register_class<Shader>(); @@ -476,7 +477,9 @@ void register_scene_types() { ClassDB::register_virtual_class<VisualShaderNode>(); ClassDB::register_class<VisualShaderNodeInput>(); ClassDB::register_virtual_class<VisualShaderNodeOutput>(); + ClassDB::register_class<VisualShaderNodeGroupBase>(); ClassDB::register_class<VisualShaderNodeScalarConstant>(); + ClassDB::register_class<VisualShaderNodeBooleanConstant>(); ClassDB::register_class<VisualShaderNodeColorConstant>(); ClassDB::register_class<VisualShaderNodeVec3Constant>(); ClassDB::register_class<VisualShaderNodeTransformConstant>(); @@ -487,8 +490,23 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeTransformVecMult>(); ClassDB::register_class<VisualShaderNodeScalarFunc>(); ClassDB::register_class<VisualShaderNodeVectorFunc>(); + ClassDB::register_class<VisualShaderNodeColorFunc>(); + ClassDB::register_class<VisualShaderNodeTransformFunc>(); ClassDB::register_class<VisualShaderNodeDotProduct>(); ClassDB::register_class<VisualShaderNodeVectorLen>(); + ClassDB::register_class<VisualShaderNodeDeterminant>(); + ClassDB::register_class<VisualShaderNodeScalarDerivativeFunc>(); + ClassDB::register_class<VisualShaderNodeVectorDerivativeFunc>(); + ClassDB::register_class<VisualShaderNodeScalarClamp>(); + ClassDB::register_class<VisualShaderNodeVectorClamp>(); + ClassDB::register_class<VisualShaderNodeFaceForward>(); + ClassDB::register_class<VisualShaderNodeOuterProduct>(); + ClassDB::register_class<VisualShaderNodeVectorScalarStep>(); + ClassDB::register_class<VisualShaderNodeScalarSmoothStep>(); + ClassDB::register_class<VisualShaderNodeVectorSmoothStep>(); + ClassDB::register_class<VisualShaderNodeVectorScalarSmoothStep>(); + ClassDB::register_class<VisualShaderNodeVectorDistance>(); + ClassDB::register_class<VisualShaderNodeVectorRefract>(); ClassDB::register_class<VisualShaderNodeScalarInterp>(); ClassDB::register_class<VisualShaderNodeVectorInterp>(); ClassDB::register_class<VisualShaderNodeVectorCompose>(); @@ -499,11 +517,16 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeCubeMap>(); ClassDB::register_virtual_class<VisualShaderNodeUniform>(); ClassDB::register_class<VisualShaderNodeScalarUniform>(); + ClassDB::register_class<VisualShaderNodeBooleanUniform>(); ClassDB::register_class<VisualShaderNodeColorUniform>(); ClassDB::register_class<VisualShaderNodeVec3Uniform>(); ClassDB::register_class<VisualShaderNodeTransformUniform>(); ClassDB::register_class<VisualShaderNodeTextureUniform>(); ClassDB::register_class<VisualShaderNodeCubeMapUniform>(); + ClassDB::register_class<VisualShaderNodeIf>(); + ClassDB::register_class<VisualShaderNodeSwitch>(); + ClassDB::register_class<VisualShaderNodeFresnel>(); + ClassDB::register_class<VisualShaderNodeExpression>(); ClassDB::register_class<ShaderMaterial>(); ClassDB::register_virtual_class<CanvasItem>(); @@ -521,6 +544,7 @@ void register_scene_types() { ClassDB::register_class<Position2D>(); ClassDB::register_class<Line2D>(); ClassDB::register_class<MeshInstance2D>(); + ClassDB::register_class<MultiMeshInstance2D>(); ClassDB::register_virtual_class<CollisionObject2D>(); ClassDB::register_virtual_class<PhysicsBody2D>(); ClassDB::register_class<StaticBody2D>(); @@ -565,9 +589,13 @@ void register_scene_types() { SceneTree::add_idle_callback(ParticlesMaterial::flush_changes); ParticlesMaterial::init_shaders(); -#ifndef _3D_DISABLED ClassDB::register_virtual_class<Mesh>(); ClassDB::register_class<ArrayMesh>(); + ClassDB::register_class<MultiMesh>(); + ClassDB::register_class<SurfaceTool>(); + ClassDB::register_class<MeshDataTool>(); + +#ifndef _3D_DISABLED ClassDB::register_virtual_class<PrimitiveMesh>(); ClassDB::register_class<CapsuleMesh>(); ClassDB::register_class<CubeMesh>(); @@ -581,7 +609,6 @@ void register_scene_types() { SceneTree::add_idle_callback(SpatialMaterial::flush_changes); SpatialMaterial::init_shaders(); - ClassDB::register_class<MultiMesh>(); ClassDB::register_class<MeshLibrary>(); OS::get_singleton()->yield(); //may take time to init @@ -592,19 +619,17 @@ void register_scene_types() { ClassDB::register_class<BoxShape>(); ClassDB::register_class<CapsuleShape>(); ClassDB::register_class<CylinderShape>(); + ClassDB::register_class<HeightMapShape>(); ClassDB::register_class<PlaneShape>(); ClassDB::register_class<ConvexPolygonShape>(); ClassDB::register_class<ConcavePolygonShape>(); - ClassDB::register_class<SurfaceTool>(); - ClassDB::register_class<MeshDataTool>(); - OS::get_singleton()->yield(); //may take time to init ClassDB::register_class<SpatialVelocityTracker>(); - ClassDB::register_class<PhysicsMaterial>(); #endif + ClassDB::register_class<PhysicsMaterial>(); ClassDB::register_class<World>(); ClassDB::register_class<Environment>(); ClassDB::register_class<World2D>(); @@ -615,11 +640,13 @@ void register_scene_types() { ClassDB::register_class<StreamTexture>(); ClassDB::register_class<ImageTexture>(); ClassDB::register_class<AtlasTexture>(); + ClassDB::register_class<MeshTexture>(); ClassDB::register_class<LargeTexture>(); ClassDB::register_class<CurveTexture>(); ClassDB::register_class<GradientTexture>(); ClassDB::register_class<ProxyTexture>(); ClassDB::register_class<AnimatedTexture>(); + ClassDB::register_class<CameraTexture>(); ClassDB::register_class<CubeMap>(); ClassDB::register_virtual_class<TextureLayered>(); ClassDB::register_class<Texture3D>(); @@ -746,29 +773,26 @@ void unregister_scene_types() { DynamicFont::finish_dynamic_fonts(); - if (resource_saver_text.is_valid()) { - ResourceSaver::remove_resource_format_saver(resource_saver_text); - resource_saver_text.unref(); - } - if (resource_loader_text.is_valid()) { - ResourceLoader::remove_resource_format_loader(resource_loader_text); - resource_loader_text.unref(); - } + ResourceSaver::remove_resource_format_saver(resource_saver_text); + resource_saver_text.unref(); - if (resource_saver_shader.is_valid()) { - ResourceSaver::remove_resource_format_saver(resource_saver_shader); - resource_saver_shader.unref(); - } - if (resource_loader_shader.is_valid()) { - ResourceLoader::remove_resource_format_loader(resource_loader_shader); - resource_loader_shader.unref(); - } - if (resource_loader_bmfont.is_valid()) { - ResourceLoader::remove_resource_format_loader(resource_loader_bmfont); - resource_loader_bmfont.unref(); - } + ResourceLoader::remove_resource_format_loader(resource_loader_text); + resource_loader_text.unref(); + + ResourceSaver::remove_resource_format_saver(resource_saver_shader); + resource_saver_shader.unref(); + + ResourceLoader::remove_resource_format_loader(resource_loader_shader); + resource_loader_shader.unref(); + ResourceLoader::remove_resource_format_loader(resource_loader_bmfont); + resource_loader_bmfont.unref(); + + //SpatialMaterial is not initialised when 3D is disabled, so it shouldn't be cleaned up either +#ifndef _3D_DISABLED SpatialMaterial::finish_shaders(); +#endif // _3D_DISABLED + ParticlesMaterial::finish_shaders(); CanvasItemMaterial::finish_shaders(); SceneStringNames::free(); diff --git a/scene/register_scene_types.h b/scene/register_scene_types.h index 9121c015fd..3645f88807 100644 --- a/scene/register_scene_types.h +++ b/scene/register_scene_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 803c85ef34..1ca643cd7a 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "animation.h" +#include "scene/scene_string_names.h" #include "core/math/geometry.h" @@ -92,7 +93,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { TransformTrack *tt = static_cast<TransformTrack *>(tracks[track]); PoolVector<float> values = p_value; int vcount = values.size(); - ERR_FAIL_COND_V(vcount % 12, false); // shuld be multiple of 11 + ERR_FAIL_COND_V(vcount % 12, false); // should be multiple of 11 PoolVector<float>::Read r = values.read(); @@ -268,19 +269,19 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { for (int i = 0; i < valcount; i++) { - Dictionary d = clips[i]; - if (!d.has("start_offset")) + Dictionary d2 = clips[i]; + if (!d2.has("start_offset")) continue; - if (!d.has("end_offset")) + if (!d2.has("end_offset")) continue; - if (!d.has("stream")) + if (!d2.has("stream")) continue; TKey<AudioKey> ak; ak.time = rt[i]; - ak.value.start_offset = d["start_offset"]; - ak.value.end_offset = d["end_offset"]; - ak.value.stream = d["stream"]; + ak.value.start_offset = d2["start_offset"]; + ak.value.end_offset = d2["end_offset"]; + ak.value.stream = d2["stream"]; ad->values.push_back(ak); } @@ -668,6 +669,7 @@ int Animation::add_track(TrackType p_type, int p_at_pos) { } } emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); return p_at_pos; } @@ -719,6 +721,7 @@ void Animation::remove_track(int p_track) { memdelete(t); tracks.remove(p_track); emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); } int Animation::get_track_count() const { @@ -737,6 +740,7 @@ void Animation::track_set_path(int p_track, const NodePath &p_path) { ERR_FAIL_INDEX(p_track, tracks.size()); tracks[p_track]->path = p_path; emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); } NodePath Animation::track_get_path(int p_track) const { @@ -815,15 +819,17 @@ int Animation::_insert(float p_time, T &p_keys, const V &p_value) { while (true) { - if (idx == 0 || p_keys[idx - 1].time < p_time) { - //condition for insertion. - p_keys.insert(idx, p_value); - return idx; - } else if (p_keys[idx - 1].time == p_time) { + // Condition for replacement. + if (idx > 0 && Math::is_equal_approx(p_keys[idx - 1].time, p_time)) { - // condition for replacing. p_keys.write[idx - 1] = p_value; return idx - 1; + + // Condition for insert. + } else if (idx == 0 || p_keys[idx - 1].time < p_time) { + + p_keys.insert(idx, p_value); + return idx; } idx--; @@ -1292,6 +1298,78 @@ float Animation::track_get_key_time(int p_track, int p_key_idx) const { ERR_FAIL_V(-1); } +void Animation::track_set_key_time(int p_track, int p_key_idx, float p_time) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + + switch (t->type) { + + case TYPE_TRANSFORM: { + + TransformTrack *tt = static_cast<TransformTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); + TKey<TransformKey> key = tt->transforms[p_key_idx]; + key.time = p_time; + tt->transforms.remove(p_key_idx); + _insert(p_time, tt->transforms, key); + return; + } + case TYPE_VALUE: { + + ValueTrack *vt = static_cast<ValueTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, vt->values.size()); + TKey<Variant> key = vt->values[p_key_idx]; + key.time = p_time; + vt->values.remove(p_key_idx); + _insert(p_time, vt->values, key); + return; + } + case TYPE_METHOD: { + + MethodTrack *mt = static_cast<MethodTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, mt->methods.size()); + MethodKey key = mt->methods[p_key_idx]; + key.time = p_time; + mt->methods.remove(p_key_idx); + _insert(p_time, mt->methods, key); + return; + } + case TYPE_BEZIER: { + + BezierTrack *bt = static_cast<BezierTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, bt->values.size()); + TKey<BezierKey> key = bt->values[p_key_idx]; + key.time = p_time; + bt->values.remove(p_key_idx); + _insert(p_time, bt->values, key); + return; + } + case TYPE_AUDIO: { + + AudioTrack *at = static_cast<AudioTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, at->values.size()); + TKey<AudioKey> key = at->values[p_key_idx]; + key.time = p_time; + at->values.remove(p_key_idx); + _insert(p_time, at->values, key); + return; + } + case TYPE_ANIMATION: { + + AnimationTrack *at = static_cast<AnimationTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, at->values.size()); + TKey<StringName> key = at->values[p_key_idx]; + key.time = p_time; + at->values.remove(p_key_idx); + _insert(p_time, at->values, key); + return; + } + } + + ERR_FAIL(); +} + float Animation::track_get_key_transition(int p_track, int p_key_idx) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); @@ -1347,7 +1425,9 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); + Dictionary d = p_value; + if (d.has("location")) tt->transforms.write[p_key_idx].value.loc = d["location"]; if (d.has("rotation")) @@ -1360,6 +1440,7 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX(p_key_idx, vt->values.size()); + vt->values.write[p_key_idx].value = p_value; } break; @@ -1367,11 +1448,14 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p MethodTrack *mt = static_cast<MethodTrack *>(t); ERR_FAIL_INDEX(p_key_idx, mt->methods.size()); + Dictionary d = p_value; + if (d.has("method")) mt->methods.write[p_key_idx].method = d["method"]; if (d.has("args")) mt->methods.write[p_key_idx].params = d["args"]; + } break; case TYPE_BEZIER: { @@ -1391,6 +1475,7 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p case TYPE_AUDIO: { AudioTrack *at = static_cast<AudioTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, at->values.size()); Dictionary k = p_value; ERR_FAIL_COND(!k.has("start_offset")); @@ -1405,11 +1490,14 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p case TYPE_ANIMATION: { AnimationTrack *at = static_cast<AnimationTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, at->values.size()); at->values.write[p_key_idx].value = p_value; } break; } + + emit_changed(); } void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_transition) { @@ -1445,6 +1533,8 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra // they don't use transition } break; } + + emit_changed(); } template <class K> @@ -1458,7 +1548,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const { int high = len - 1; int middle = 0; -#if DEBUG_ENABLED +#ifdef DEBUG_ENABLED if (low > high) ERR_PRINT("low > high, this may be a bug"); #endif @@ -1469,7 +1559,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const { middle = (low + high) / 2; - if (Math::abs(p_time - keys[middle].time) < CMP_EPSILON) { //match + if (Math::is_equal_approx(p_time, keys[middle].time)) { //match return middle; } else if (p_time < keys[middle].time) high = middle - 1; //search low end of array @@ -1672,10 +1762,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol float delta = p_keys[next].time - p_keys[idx].time; float from = p_time - p_keys[idx].time; - if (Math::absf(delta) > CMP_EPSILON) - c = from / delta; - else + if (Math::is_zero_approx(delta)) c = 0; + else + c = from / delta; } else { @@ -1683,10 +1773,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol float delta = (length - p_keys[idx].time) + p_keys[next].time; float from = p_time - p_keys[idx].time; - if (Math::absf(delta) > CMP_EPSILON) - c = from / delta; - else + if (Math::is_zero_approx(delta)) c = 0; + else + c = from / delta; } } else { @@ -1699,10 +1789,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol float delta = endtime + p_keys[next].time; float from = endtime + p_time; - if (Math::absf(delta) > CMP_EPSILON) - c = from / delta; - else + if (Math::is_zero_approx(delta)) c = 0; + else + c = from / delta; } } else { // no loop @@ -1715,10 +1805,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol float delta = p_keys[next].time - p_keys[idx].time; float from = p_time - p_keys[idx].time; - if (Math::absf(delta) > CMP_EPSILON) - c = from / delta; - else + if (Math::is_zero_approx(delta)) c = 0; + else + c = from / delta; } else { @@ -1815,7 +1905,7 @@ Variant Animation::value_track_interpolate(int p_track, float p_time) const { bool ok = false; - Variant res = _interpolate(vt->values, p_time, vt->update_mode == UPDATE_CONTINUOUS ? vt->interpolation : INTERPOLATION_NEAREST, vt->loop_wrap, &ok); + Variant res = _interpolate(vt->values, p_time, (vt->update_mode == UPDATE_CONTINUOUS || vt->update_mode == UPDATE_CAPTURE) ? vt->interpolation : INTERPOLATION_NEAREST, vt->loop_wrap, &ok); if (ok) { @@ -1828,9 +1918,14 @@ Variant Animation::value_track_interpolate(int p_track, float p_time) const { void Animation::_value_track_get_key_indices_in_range(const ValueTrack *vt, float from_time, float to_time, List<int> *p_indices) const { if (from_time != length && to_time == length) - to_time = length * 1.01; //include a little more if at the end + to_time = length * 1.001; //include a little more if at the end int to = _find(vt->values, to_time); + if (to >= 0 && from_time == to_time && vt->values[to].time == from_time) { + //find exact (0 delta), return if found + p_indices->push_back(to); + return; + } // can't really send the events == time, will be sent in the next frame. // if event>=len then it will probably never be requested by the anim player. @@ -1876,7 +1971,7 @@ void Animation::value_track_get_key_indices(int p_track, float p_time, float p_d if (from_time > to_time) { // handle loop by splitting - _value_track_get_key_indices_in_range(vt, length - from_time, length, p_indices); + _value_track_get_key_indices_in_range(vt, from_time, length, p_indices); _value_track_get_key_indices_in_range(vt, 0, to_time, p_indices); return; } @@ -2332,7 +2427,7 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const { float duration = bt->values[idx + 1].time - bt->values[idx].time; // time duration between our two keyframes float low = 0; // 0% of the current animation segment float high = 1; // 100% of the current animation segment - float middle = 0; + float middle; Vector2 start(0, bt->values[idx].value.value); Vector2 start_out = start + bt->values[idx].value.out_handle; @@ -2546,16 +2641,6 @@ bool Animation::has_loop() const { return loop; } -void Animation::track_move_up(int p_track) { - - if (p_track >= 0 && p_track < (tracks.size() - 1)) { - - SWAP(tracks.write[p_track], tracks.write[p_track + 1]); - } - - emit_changed(); -} - void Animation::track_set_imported(int p_track, bool p_imported) { ERR_FAIL_INDEX(p_track, tracks.size()); @@ -2581,13 +2666,42 @@ bool Animation::track_is_enabled(int p_track) const { return tracks[p_track]->enabled; } +void Animation::track_move_up(int p_track) { + + if (p_track >= 0 && p_track < (tracks.size() - 1)) { + + SWAP(tracks.write[p_track], tracks.write[p_track + 1]); + } + + emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); +} + void Animation::track_move_down(int p_track) { if (p_track > 0 && p_track < tracks.size()) { SWAP(tracks.write[p_track], tracks.write[p_track - 1]); } + + emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); +} + +void Animation::track_move_to(int p_track, int p_to_index) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + ERR_FAIL_INDEX(p_to_index, tracks.size() + 1); + if (p_track == p_to_index || p_track == p_to_index - 1) + return; + + Track *track = tracks.get(p_track); + tracks.remove(p_track); + // Take into account that the position of the tracks that come after the one removed will change. + tracks.insert(p_to_index > p_track ? p_to_index - 1 : p_to_index, track); + emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); } void Animation::track_swap(int p_track, int p_with_track) { @@ -2597,7 +2711,9 @@ void Animation::track_swap(int p_track, int p_with_track) { if (p_track == p_with_track) return; SWAP(tracks.write[p_track], tracks.write[p_with_track]); + emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); } void Animation::set_step(float p_step) { @@ -2622,6 +2738,7 @@ void Animation::copy_track(int p_track, Ref<Animation> p_to_animation) { p_to_animation->track_set_enabled(dst_track, track_is_enabled(p_track)); p_to_animation->track_set_interpolation_type(dst_track, track_get_interpolation_type(p_track)); p_to_animation->track_set_interpolation_loop_wrap(dst_track, track_get_interpolation_loop_wrap(p_track)); + p_to_animation->value_track_set_update_mode(dst_track, value_track_get_update_mode(p_track)); for (int i = 0; i < track_get_key_count(p_track); i++) { p_to_animation->track_insert_key(dst_track, track_get_key_time(p_track, i), track_get_key_value(p_track, i), track_get_key_transition(p_track, i)); } @@ -2639,6 +2756,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_move_up", "idx"), &Animation::track_move_up); ClassDB::bind_method(D_METHOD("track_move_down", "idx"), &Animation::track_move_down); + ClassDB::bind_method(D_METHOD("track_move_to", "idx", "to_idx"), &Animation::track_move_to); ClassDB::bind_method(D_METHOD("track_swap", "idx", "with_idx"), &Animation::track_swap); ClassDB::bind_method(D_METHOD("track_set_imported", "idx", "imported"), &Animation::track_set_imported); @@ -2653,6 +2771,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_remove_key_at_position", "idx", "position"), &Animation::track_remove_key_at_position); ClassDB::bind_method(D_METHOD("track_set_key_value", "idx", "key", "value"), &Animation::track_set_key_value); ClassDB::bind_method(D_METHOD("track_set_key_transition", "idx", "key_idx", "transition"), &Animation::track_set_key_transition); + ClassDB::bind_method(D_METHOD("track_set_key_time", "idx", "key_idx", "time"), &Animation::track_set_key_time); ClassDB::bind_method(D_METHOD("track_get_key_transition", "idx", "key_idx"), &Animation::track_get_key_transition); ClassDB::bind_method(D_METHOD("track_get_key_count", "idx"), &Animation::track_get_key_count); @@ -2716,6 +2835,8 @@ void Animation::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "step", PROPERTY_HINT_RANGE, "0,4096,0.001"), "set_step", "get_step"); + ADD_SIGNAL(MethodInfo("tracks_changed")); + BIND_ENUM_CONSTANT(TYPE_VALUE); BIND_ENUM_CONSTANT(TYPE_TRANSFORM); BIND_ENUM_CONSTANT(TYPE_METHOD); @@ -2740,6 +2861,8 @@ void Animation::clear() { tracks.clear(); loop = false; length = 1; + emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); } bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err, float p_alowed_angular_err, float p_max_optimizable_angle, const Vector3 &p_norm) { @@ -2753,9 +2876,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons const Vector3 &v1 = t1.value.loc; const Vector3 &v2 = t2.value.loc; - if (v0.distance_to(v2) < CMP_EPSILON) { + if (Math::is_zero_approx(v0.distance_to(v2))) { //0 and 2 are close, let's see if 1 is close - if (v0.distance_to(v1) > CMP_EPSILON) { + if (!Math::is_zero_approx(v0.distance_to(v1))) { //not close, not optimizable return false; } @@ -2792,9 +2915,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons //localize both to rotation from q0 - if ((q0 - q2).length() < CMP_EPSILON) { + if (Math::is_zero_approx((q0 - q2).length())) { - if ((q0 - q1).length() > CMP_EPSILON) + if (!Math::is_zero_approx((q0 - q1).length())) return false; } else { @@ -2842,9 +2965,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons const Vector3 &v1 = t1.value.scale; const Vector3 &v2 = t2.value.scale; - if (v0.distance_to(v2) < CMP_EPSILON) { + if (Math::is_zero_approx(v0.distance_to(v2))) { //0 and 2 are close, let's see if 1 is close - if (v0.distance_to(v1) > CMP_EPSILON) { + if (!Math::is_zero_approx(v0.distance_to(v1))) { //not close, not optimizable return false; } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 6eec2c8bc7..59f2ae24c7 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -93,7 +93,6 @@ private: template <class T> struct TKey : public Key { - float time; T value; }; @@ -294,6 +293,7 @@ public: void track_move_up(int p_track); void track_move_down(int p_track); + void track_move_to(int p_track, int p_to_index); void track_swap(int p_track, int p_with_track); void track_set_imported(int p_track, bool p_imported); @@ -305,6 +305,7 @@ public: void track_insert_key(int p_track, float p_time, const Variant &p_key, float p_transition = 1); void track_set_key_transition(int p_track, int p_key_idx, float p_transition); void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value); + void track_set_key_time(int p_track, int p_key_idx, float p_time); int track_find_key(int p_track, float p_time, bool p_exact = false) const; void track_remove_key(int p_track, int p_idx); void track_remove_key_at_position(int p_track, float p_pos); diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index 35132c1195..4b3e392013 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -515,10 +515,10 @@ PoolVector<uint8_t> AudioStreamSample::get_data() const { return pv; } -void AudioStreamSample::save_to_wav(String p_path) { +Error AudioStreamSample::save_to_wav(const String &p_path) { if (format == AudioStreamSample::FORMAT_IMA_ADPCM) { WARN_PRINTS("Saving IMA_ADPC samples are not supported yet"); - return; + return ERR_UNAVAILABLE; } int sub_chunk_2_size = data_bytes; //Subchunk2Size = Size of data in bytes @@ -544,8 +544,9 @@ void AudioStreamSample::save_to_wav(String p_path) { file_path += ".wav"; } - Error err; - FileAccess *file = FileAccess::open(file_path, FileAccess::WRITE, &err); //Overrides existing file if present + FileAccessRef file = FileAccess::open(file_path, FileAccess::WRITE); //Overrides existing file if present + + ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); // Create WAV Header file->store_string("RIFF"); //ChunkID @@ -583,6 +584,8 @@ void AudioStreamSample::save_to_wav(String p_path) { } file->close(); + + return OK; } Ref<AudioStreamPlayback> AudioStreamSample::instance_playback() { diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h index 2c39e0a11e..bb25b60835 100644 --- a/scene/resources/audio_stream_sample.h +++ b/scene/resources/audio_stream_sample.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,7 +37,7 @@ class AudioStreamSample; class AudioStreamPlaybackSample : public AudioStreamPlayback { - GDCLASS(AudioStreamPlaybackSample, AudioStreamPlayback) + GDCLASS(AudioStreamPlaybackSample, AudioStreamPlayback); enum { MIX_FRAC_BITS = 13, MIX_FRAC_LEN = (1 << MIX_FRAC_BITS), @@ -81,7 +81,7 @@ public: }; class AudioStreamSample : public AudioStream { - GDCLASS(AudioStreamSample, AudioStream) + GDCLASS(AudioStreamSample, AudioStream); RES_BASE_EXTENSION("sample") public: @@ -141,7 +141,7 @@ public: void set_data(const PoolVector<uint8_t> &p_data); PoolVector<uint8_t> get_data() const; - void save_to_wav(String p_path); + Error save_to_wav(const String &p_path); virtual Ref<AudioStreamPlayback> instance_playback(); virtual String get_stream_name() const; diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_map.cpp index 587ab73dce..e4a64a1de1 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_map.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* bit_mask.cpp */ +/* bit_map.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "bit_mask.h" +#include "bit_map.h" #include "core/io/image_loader.h" @@ -96,7 +96,7 @@ int BitMap::get_true_bit_count() const { const uint8_t *d = bitmask.ptr(); int c = 0; - //fast, almot branchless version + //fast, almost branchless version for (int i = 0; i < ds; i++) { @@ -106,6 +106,7 @@ int BitMap::get_true_bit_count() const { c += (d[i] & (1 << 4)) >> 4; c += (d[i] & (1 << 3)) >> 3; c += (d[i] & (1 << 2)) >> 2; + c += (d[i] & (1 << 1)) >> 1; c += d[i] & 1; } @@ -332,7 +333,7 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) prevx = stepx; prevy = stepy; - ERR_FAIL_COND_V(count > width * height, _points); + ERR_FAIL_COND_V((int)count > width * height, _points); } while (curx != startx || cury != starty); return _points; } @@ -594,6 +595,62 @@ Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) con return result_array; } +void BitMap::resize(const Size2 &p_new_size) { + + Ref<BitMap> new_bitmap; + new_bitmap.instance(); + new_bitmap->create(p_new_size); + int lw = MIN(width, p_new_size.width); + int lh = MIN(height, p_new_size.height); + for (int x = 0; x < lw; x++) { + for (int y = 0; y < lh; y++) { + new_bitmap->set_bit(Vector2(x, y), get_bit(Vector2(x, y))); + } + } + + width = new_bitmap->width; + height = new_bitmap->height; + bitmask = new_bitmap->bitmask; +} + +Ref<Image> BitMap::convert_to_image() const { + + Ref<Image> image; + image.instance(); + image->create(width, height, false, Image::FORMAT_L8); + image->lock(); + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + image->set_pixel(i, j, get_bit(Point2(i, j)) ? Color(1, 1, 1) : Color(0, 0, 0)); + } + } + + image->unlock(); + + return image; +} +void BitMap::blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap) { + + int x = p_pos.x; + int y = p_pos.y; + int w = p_bitmap->get_size().width; + int h = p_bitmap->get_size().height; + + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + int px = x + i; + int py = y + j; + if (px < 0 || px >= width) + continue; + if (py < 0 || py >= height) + continue; + if (p_bitmap->get_bit(Vector2(i, j))) { + set_bit(Vector2(x, y), true); + } + } + } +} + void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); @@ -602,7 +659,7 @@ void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit); ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit); - ClassDB::bind_method(D_METHOD("set_bit_rect", "p_rect", "bit"), &BitMap::set_bit_rect); + ClassDB::bind_method(D_METHOD("set_bit_rect", "rect", "bit"), &BitMap::set_bit_rect); ClassDB::bind_method(D_METHOD("get_true_bit_count"), &BitMap::get_true_bit_count); ClassDB::bind_method(D_METHOD("get_size"), &BitMap::get_size); diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_map.h index 04191a7774..daf24affb1 100644 --- a/scene/resources/bit_mask.h +++ b/scene/resources/bit_map.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* bit_mask.h */ +/* bit_map.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BIT_MASK_H -#define BIT_MASK_H +#ifndef BIT_MAP_H +#define BIT_MAP_H #include "core/image.h" #include "core/io/resource_loader.h" @@ -64,12 +64,16 @@ public: int get_true_bit_count() const; Size2 get_size() const; + void resize(const Size2 &p_new_size); void grow_mask(int p_pixels, const Rect2 &p_rect); + void blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap); + Ref<Image> convert_to_image() const; + Vector<Vector<Vector2> > clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const; BitMap(); }; -#endif // BIT_MASK_H +#endif // BIT_MAP_H diff --git a/scene/resources/box_shape.cpp b/scene/resources/box_shape.cpp index e9e01ed98a..d819e9f776 100644 --- a/scene/resources/box_shape.cpp +++ b/scene/resources/box_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -51,6 +51,7 @@ Vector<Vector3> BoxShape::_gen_debug_mesh_lines() { void BoxShape::_update_shape() { PhysicsServer::get_singleton()->shape_set_data(get_shape(), extents); + Shape::_update_shape(); } void BoxShape::set_extents(const Vector3 &p_extents) { diff --git a/scene/resources/box_shape.h b/scene/resources/box_shape.h index 5ef16b4766..42d54310a8 100644 --- a/scene/resources/box_shape.h +++ b/scene/resources/box_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/canvas.cpp b/scene/resources/canvas.cpp index 8da1da9541..0fc8b22046 100644 --- a/scene/resources/canvas.cpp +++ b/scene/resources/canvas.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/canvas.h b/scene/resources/canvas.h index cd37ea3583..4324b6227c 100644 --- a/scene/resources/canvas.h +++ b/scene/resources/canvas.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/capsule_shape.cpp b/scene/resources/capsule_shape.cpp index 101970bad8..669b261bfe 100644 --- a/scene/resources/capsule_shape.cpp +++ b/scene/resources/capsule_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -75,6 +75,7 @@ void CapsuleShape::_update_shape() { d["radius"] = radius; d["height"] = height; PhysicsServer::get_singleton()->shape_set_data(get_shape(), d); + Shape::_update_shape(); } void CapsuleShape::set_radius(float p_radius) { diff --git a/scene/resources/capsule_shape.h b/scene/resources/capsule_shape.h index f89d07c5f1..6bca53f783 100644 --- a/scene/resources/capsule_shape.h +++ b/scene/resources/capsule_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index 95ab34abb2..fde05bfb7f 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h index 04d663c010..3bedf7618d 100644 --- a/scene/resources/capsule_shape_2d.h +++ b/scene/resources/capsule_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index 1c7bb76b26..76c1440861 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h index 06bb433170..e2624ac8ed 100644 --- a/scene/resources/circle_shape_2d.h +++ b/scene/resources/circle_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp index bc9e2848b3..b4cc38c8c0 100644 --- a/scene/resources/concave_polygon_shape.cpp +++ b/scene/resources/concave_polygon_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -65,6 +65,7 @@ Vector<Vector3> ConcavePolygonShape::_gen_debug_mesh_lines() { } void ConcavePolygonShape::_update_shape() { + Shape::_update_shape(); } void ConcavePolygonShape::set_faces(const PoolVector<Vector3> &p_faces) { diff --git a/scene/resources/concave_polygon_shape.h b/scene/resources/concave_polygon_shape.h index 2cc9095abf..1b8ddfc308 100644 --- a/scene/resources/concave_polygon_shape.h +++ b/scene/resources/concave_polygon_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp index d4343680ef..51dd91fff5 100644 --- a/scene/resources/concave_polygon_shape_2d.cpp +++ b/scene/resources/concave_polygon_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h index e8fa7369ac..8e3267dc2a 100644 --- a/scene/resources/concave_polygon_shape_2d.h +++ b/scene/resources/concave_polygon_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp index 39488760cd..499688a185 100644 --- a/scene/resources/convex_polygon_shape.cpp +++ b/scene/resources/convex_polygon_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -58,7 +58,7 @@ Vector<Vector3> ConvexPolygonShape::_gen_debug_mesh_lines() { void ConvexPolygonShape::_update_shape() { PhysicsServer::get_singleton()->shape_set_data(get_shape(), points); - emit_changed(); + Shape::_update_shape(); } void ConvexPolygonShape::set_points(const PoolVector<Vector3> &p_points) { @@ -83,6 +83,4 @@ void ConvexPolygonShape::_bind_methods() { ConvexPolygonShape::ConvexPolygonShape() : Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON)) { - - //set_points(Vector3(1,1,1)); } diff --git a/scene/resources/convex_polygon_shape.h b/scene/resources/convex_polygon_shape.h index 62567fc031..5c192476d3 100644 --- a/scene/resources/convex_polygon_shape.h +++ b/scene/resources/convex_polygon_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp index fc3d3f3334..d424fb2814 100644 --- a/scene/resources/convex_polygon_shape_2d.cpp +++ b/scene/resources/convex_polygon_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -99,10 +99,4 @@ Rect2 ConvexPolygonShape2D::get_rect() const { ConvexPolygonShape2D::ConvexPolygonShape2D() : Shape2D(Physics2DServer::get_singleton()->convex_polygon_shape_create()) { - - int pcount = 3; - for (int i = 0; i < pcount; i++) - points.push_back(Vector2(Math::sin(i * Math_PI * 2 / pcount), -Math::cos(i * Math_PI * 2 / pcount)) * 10); - - _update_shape(); } diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h index 69c237a0e6..8625b800ed 100644 --- a/scene/resources/convex_polygon_shape_2d.h +++ b/scene/resources/convex_polygon_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 9188d890f7..950518aa6e 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -268,7 +268,7 @@ void Curve::update_auto_tangents(int i) { } if (i + 1 < _points.size()) { - if (p.right_mode == TANGENT_LINEAR && i + 1 < _points.size()) { + if (p.right_mode == TANGENT_LINEAR) { Vector2 v = (_points[i + 1].pos - p.pos).normalized(); p.right_tangent = v.y / v.x; } @@ -761,8 +761,8 @@ Vector2 Curve2D::interpolate_baked(float p_offset, bool p_cubic) const { //validate// int pc = baked_point_cache.size(); if (pc == 0) { - ERR_EXPLAIN("No points in Curve2D"); - ERR_FAIL_COND_V(pc == 0, Vector2()); + ERR_EXPLAIN("No points in Curve2D."); + ERR_FAIL_V(Vector2()); } if (pc == 1) @@ -782,7 +782,8 @@ Vector2 Curve2D::interpolate_baked(float p_offset, bool p_cubic) const { if (idx >= bpc - 1) { return r[bpc - 1]; } else if (idx == bpc - 2) { - frac /= Math::fmod(baked_max_ofs, bake_interval); + if (frac > 0) + frac /= Math::fmod(baked_max_ofs, bake_interval); } else { frac /= bake_interval; } @@ -826,8 +827,8 @@ Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const { //validate// int pc = baked_point_cache.size(); if (pc == 0) { - ERR_EXPLAIN("No points in Curve2D"); - ERR_FAIL_COND_V(pc == 0, Vector2()); + ERR_EXPLAIN("No points in Curve2D."); + ERR_FAIL_V(Vector2()); } if (pc == 1) @@ -865,8 +866,8 @@ float Curve2D::get_closest_offset(const Vector2 &p_to_point) const { //validate// int pc = baked_point_cache.size(); if (pc == 0) { - ERR_EXPLAIN("No points in Curve2D"); - ERR_FAIL_COND_V(pc == 0, 0.0f); + ERR_EXPLAIN("No points in Curve2D."); + ERR_FAIL_V(0.0f); } if (pc == 1) @@ -1331,8 +1332,8 @@ Vector3 Curve3D::interpolate_baked(float p_offset, bool p_cubic) const { //validate// int pc = baked_point_cache.size(); if (pc == 0) { - ERR_EXPLAIN("No points in Curve3D"); - ERR_FAIL_COND_V(pc == 0, Vector3()); + ERR_EXPLAIN("No points in Curve3D."); + ERR_FAIL_V(Vector3()); } if (pc == 1) @@ -1352,7 +1353,8 @@ Vector3 Curve3D::interpolate_baked(float p_offset, bool p_cubic) const { if (idx >= bpc - 1) { return r[bpc - 1]; } else if (idx == bpc - 2) { - frac /= Math::fmod(baked_max_ofs, bake_interval); + if (frac > 0) + frac /= Math::fmod(baked_max_ofs, bake_interval); } else { frac /= bake_interval; } @@ -1375,8 +1377,8 @@ float Curve3D::interpolate_baked_tilt(float p_offset) const { //validate// int pc = baked_tilt_cache.size(); if (pc == 0) { - ERR_EXPLAIN("No tilts in Curve3D"); - ERR_FAIL_COND_V(pc == 0, 0); + ERR_EXPLAIN("No tilts in Curve3D."); + ERR_FAIL_V(0); } if (pc == 1) @@ -1396,7 +1398,8 @@ float Curve3D::interpolate_baked_tilt(float p_offset) const { if (idx >= bpc - 1) { return r[bpc - 1]; } else if (idx == bpc - 2) { - frac /= Math::fmod(baked_max_ofs, bake_interval); + if (frac > 0) + frac /= Math::fmod(baked_max_ofs, bake_interval); } else { frac /= bake_interval; } @@ -1413,8 +1416,8 @@ Vector3 Curve3D::interpolate_baked_up_vector(float p_offset, bool p_apply_tilt) // curve may not have baked up vectors int count = baked_up_vector_cache.size(); if (count == 0) { - ERR_EXPLAIN("No up vectors in Curve3D"); - ERR_FAIL_COND_V(count == 0, Vector3(0, 1, 0)); + ERR_EXPLAIN("No up vectors in Curve3D."); + ERR_FAIL_V(Vector3(0, 1, 0)); } if (count == 1) @@ -1484,8 +1487,8 @@ Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const { //validate// int pc = baked_point_cache.size(); if (pc == 0) { - ERR_EXPLAIN("No points in Curve3D"); - ERR_FAIL_COND_V(pc == 0, Vector3()); + ERR_EXPLAIN("No points in Curve3D."); + ERR_FAIL_V(Vector3()); } if (pc == 1) @@ -1523,8 +1526,8 @@ float Curve3D::get_closest_offset(const Vector3 &p_to_point) const { //validate// int pc = baked_point_cache.size(); if (pc == 0) { - ERR_EXPLAIN("No points in Curve3D"); - ERR_FAIL_COND_V(pc == 0, 0.0f); + ERR_EXPLAIN("No points in Curve3D."); + ERR_FAIL_V(0.0f); } if (pc == 1) diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 234e3a6779..bb12baca48 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -35,7 +35,8 @@ // y(x) curve class Curve : public Resource { - GDCLASS(Curve, Resource) + GDCLASS(Curve, Resource); + public: static const int MIN_X = 0.f; static const int MAX_X = 1.f; diff --git a/scene/resources/cylinder_shape.cpp b/scene/resources/cylinder_shape.cpp index f760462d49..f60f7ab376 100644 --- a/scene/resources/cylinder_shape.cpp +++ b/scene/resources/cylinder_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -68,6 +68,7 @@ void CylinderShape::_update_shape() { d["radius"] = radius; d["height"] = height; PhysicsServer::get_singleton()->shape_set_data(get_shape(), d); + Shape::_update_shape(); } void CylinderShape::set_radius(float p_radius) { diff --git a/scene/resources/cylinder_shape.h b/scene/resources/cylinder_shape.h index f510758e91..58a4f5a817 100644 --- a/scene/resources/cylinder_shape.h +++ b/scene/resources/cylinder_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 7d7bf8a750..2c5dfc375c 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -359,7 +359,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("focus", "CheckButton", focus); theme->set_icon("on", "CheckButton", make_icon(toggle_on_png)); + theme->set_icon("on_disabled", "CheckButton", make_icon(toggle_on_disabled_png)); theme->set_icon("off", "CheckButton", make_icon(toggle_off_png)); + theme->set_icon("off_disabled", "CheckButton", make_icon(toggle_off_disabled_png)); theme->set_font("font", "CheckButton", default_font); @@ -423,6 +425,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); theme->set_icon("tab", "TextEdit", make_icon(tab_png)); + theme->set_icon("space", "TextEdit", make_icon(space_png)); + theme->set_icon("folded", "TextEdit", make_icon(arrow_right_png)); + theme->set_icon("fold", "TextEdit", make_icon(arrow_down_png)); theme->set_font("font", "TextEdit", default_font); @@ -436,7 +441,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color_selected", "TextEdit", Color(0, 0, 0)); theme->set_color("selection_color", "TextEdit", font_color_selection); theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4)); + theme->set_color("bookmark_color", "TextEdit", Color(0.08, 0.49, 0.98)); theme->set_color("breakpoint_color", "TextEdit", Color(0.8, 0.8, 0.4, 0.2)); + theme->set_color("executing_line_color", "TextEdit", Color(0.2, 0.8, 0.2, 0.4)); theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8)); theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8)); theme->set_color("caret_color", "TextEdit", control_font_color); @@ -534,8 +541,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // File Dialog - theme->set_icon("reload", "FileDialog", make_icon(icon_reload_png)); theme->set_icon("parent_folder", "FileDialog", make_icon(icon_parent_folder_png)); + theme->set_icon("reload", "FileDialog", make_icon(icon_reload_png)); + theme->set_icon("toggle_hidden", "FileDialog", make_icon(icon_visibility_png)); // Popup @@ -575,14 +583,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // GraphNode - Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png, 6, 24, 6, 5, 16, 24, 16, 5); - Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_png, 6, 24, 6, 5, 16, 24, 16, 5); - Ref<StyleBoxTexture> graphsbcommentselected = make_stylebox(graph_node_comment_focus_png, 6, 24, 6, 5, 16, 24, 16, 5); - Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png, 6, 24, 6, 5, 16, 24, 16, 5); + Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png, 6, 24, 6, 5, 16, 24, 16, 6); + Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_png, 6, 24, 6, 5, 16, 24, 16, 6); + Ref<StyleBoxTexture> graphsbcommentselected = make_stylebox(graph_node_comment_focus_png, 6, 24, 6, 5, 16, 24, 16, 6); + Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png, 6, 24, 6, 5, 16, 24, 16, 6); Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png, 4, 4, 4, 4, 6, 4, 4, 4); Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png, 4, 4, 4, 4, 6, 4, 4, 4); - Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png, 6, 24, 6, 5, 16, 24, 16, 5); - Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png, 6, 24, 6, 5, 16, 24, 16, 5); + Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png, 6, 24, 6, 5, 16, 24, 16, 6); + Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png, 6, 24, 6, 5, 16, 24, 16, 6); //graphsb->set_expand_margin_size(MARGIN_LEFT,10); //graphsb->set_expand_margin_size(MARGIN_RIGHT,10); @@ -682,6 +690,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("tab_fg", "TabContainer", sb_expand(make_stylebox(tab_current_png, 4, 4, 4, 1, 16, 4, 16, 4), 2, 2, 2, 2)); theme->set_stylebox("tab_bg", "TabContainer", sb_expand(make_stylebox(tab_behind_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3)); + theme->set_stylebox("tab_disabled", "TabContainer", sb_expand(make_stylebox(tab_disabled_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3)); theme->set_stylebox("panel", "TabContainer", tc_sb); theme->set_icon("increment", "TabContainer", make_icon(scroll_button_right_png)); @@ -707,6 +716,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("tab_fg", "Tabs", sb_expand(make_stylebox(tab_current_png, 4, 3, 4, 1, 16, 3, 16, 2), 2, 2, 2, 2)); theme->set_stylebox("tab_bg", "Tabs", sb_expand(make_stylebox(tab_behind_png, 5, 4, 5, 1, 16, 5, 16, 2), 3, 3, 3, 3)); + theme->set_stylebox("tab_disabled", "Tabs", sb_expand(make_stylebox(tab_disabled_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3)); theme->set_stylebox("panel", "Tabs", tc_sb); theme->set_stylebox("button_pressed", "Tabs", make_stylebox(button_pressed_png, 4, 4, 4, 4)); theme->set_stylebox("button", "Tabs", make_stylebox(button_normal_png, 4, 4, 4, 4)); @@ -793,7 +803,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font("bold_italics_font", "RichTextLabel", default_font); theme->set_font("mono_font", "RichTextLabel", default_font); - theme->set_color("default_color", "RichTextLabel", control_font_color); + theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1)); theme->set_color("font_color_selected", "RichTextLabel", font_color_selection); theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8)); @@ -828,14 +838,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("autohide", "HSplitContainer", 1 * scale); theme->set_constant("autohide", "VSplitContainer", 1 * scale); - // ReferenceRect - - Ref<StyleBoxTexture> ttnc = make_stylebox(full_panel_bg_png, 8, 8, 8, 8); - ttnc->set_draw_center(false); - - theme->set_stylebox("panelnc", "Panel", ttnc); - theme->set_stylebox("panelf", "Panel", tc_sb); - Ref<StyleBoxTexture> sb_pc = make_stylebox(tab_container_bg_png, 4, 4, 4, 4, 7, 7, 7, 7); theme->set_stylebox("panel", "PanelContainer", sb_pc); diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index 8f211af35b..cbf0cc1b79 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/default_theme/font_hidpi.inc b/scene/resources/default_theme/font_hidpi.inc index 2fc0f56c3f..4860149e6b 100644 --- a/scene/resources/default_theme/font_hidpi.inc +++ b/scene/resources/default_theme/font_hidpi.inc @@ -1,3 +1,4 @@ +/* clang-format off */ static const int _hidpi_font_height=25; static const int _hidpi_font_ascent=19; static const int _hidpi_font_charcount=191; @@ -25459,3 +25460,4 @@ static const unsigned char _hidpi_font_img_data[25255]={ 96, 130, }; +/* clang-format on */ diff --git a/scene/resources/default_theme/font_lodpi.inc b/scene/resources/default_theme/font_lodpi.inc index 8eae45a8a7..959e2c1d7b 100644 --- a/scene/resources/default_theme/font_lodpi.inc +++ b/scene/resources/default_theme/font_lodpi.inc @@ -1,3 +1,4 @@ +/* clang-format off */ static const int _lodpi_font_height=14; static const int _lodpi_font_ascent=11; static const int _lodpi_font_charcount=191; @@ -13113,3 +13114,4 @@ static const unsigned char _lodpi_font_img_data[12909]={ 96, 130, }; +/* clang-format on */ diff --git a/scene/resources/default_theme/icon_visibility.png b/scene/resources/default_theme/icon_visibility.png Binary files differnew file mode 100644 index 0000000000..6402571f3e --- /dev/null +++ b/scene/resources/default_theme/icon_visibility.png diff --git a/scene/resources/default_theme/make_header.py b/scene/resources/default_theme/make_header.py index 73b1ae0b0b..bd5a723b23 100755 --- a/scene/resources/default_theme/make_header.py +++ b/scene/resources/default_theme/make_header.py @@ -1,8 +1,6 @@ #!/usr/bin/env python -import os import glob -import string enc = "utf-8" diff --git a/scene/resources/default_theme/space.png b/scene/resources/default_theme/space.png Binary files differnew file mode 100644 index 0000000000..7e458a6c45 --- /dev/null +++ b/scene/resources/default_theme/space.png diff --git a/scene/resources/default_theme/tab_disabled.png b/scene/resources/default_theme/tab_disabled.png Binary files differnew file mode 100644 index 0000000000..97157a58dd --- /dev/null +++ b/scene/resources/default_theme/tab_disabled.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 353e7eddbe..5e13a6625a 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -71,7 +71,7 @@ static const unsigned char dropdown_png[] = { }; static const unsigned char error_icon_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x4, 0x0, 0x0, 0x0, 0xd9, 0x73, 0xb2, 0x7f, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x36, 0x18, 0x5, 0xa3, 0x60, 0x14, 0xfc, 0x87, 0x40, 0x38, 0xb, 0x21, 0x6, 0x6, 0x18, 0x62, 0x98, 0x6, 0xa0, 0xb1, 0xfe, 0xe3, 0x67, 0xd1, 0xc2, 0x0, 0x10, 0xc4, 0xc5, 0x82, 0x91, 0x43, 0xc0, 0xb, 0xb8, 0x15, 0x63, 0x78, 0x6, 0x5, 0x8c, 0x82, 0x51, 0x30, 0xa, 0x0, 0x35, 0xa3, 0x4c, 0xb4, 0x7c, 0x8a, 0x7, 0x6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe2, 0xb, 0xf, 0x0, 0x22, 0x18, 0xc, 0x35, 0xef, 0x18, 0x0, 0x0, 0x0, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x0, 0x1, 0x0, 0x2, 0x10, 0x0, 0x1, 0x14, 0xc2, 0xc0, 0x92, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char focus_png[] = { @@ -194,6 +194,10 @@ static const unsigned char icon_stop_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, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x2, 0x7c, 0x60, 0x26, 0x28, 0xf3, 0xf0, 0x3f, 0x76, 0x8, 0x94, 0xa2, 0x97, 0x82, 0x51, 0x5, 0x84, 0x23, 0x8b, 0x30, 0x0, 0x0, 0x66, 0x60, 0x11, 0xdc, 0x92, 0xb3, 0xb7, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char icon_visibility_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, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x3, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0xdb, 0xe1, 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0x96, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xdf, 0xdf, 0xdf, 0xe3, 0xe3, 0xe3, 0xe6, 0xe6, 0xe6, 0xd5, 0xd5, 0xd5, 0xd8, 0xd8, 0xd8, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xe1, 0xe1, 0xe1, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xde, 0xde, 0xde, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xb7, 0x7e, 0xd, 0xb6, 0x0, 0x0, 0x0, 0x32, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x8, 0x9, 0xa, 0xc, 0xd, 0xe, 0xf, 0x11, 0x12, 0x13, 0x2e, 0x2f, 0x32, 0x33, 0x36, 0x37, 0x38, 0x48, 0x49, 0x4b, 0x50, 0x53, 0x55, 0x56, 0x6c, 0x6d, 0x6e, 0x70, 0x77, 0x79, 0x7b, 0x7c, 0xc5, 0xd7, 0xd8, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1, 0xe2, 0xe3, 0xf0, 0xf2, 0xf3, 0xf4, 0xfe, 0x5e, 0x62, 0x1a, 0x26, 0x0, 0x0, 0x0, 0x86, 0x49, 0x44, 0x41, 0x54, 0x18, 0x19, 0x8d, 0xc1, 0xb, 0x16, 0x42, 0x40, 0x0, 0x86, 0xd1, 0x2f, 0xa2, 0x77, 0x2a, 0x85, 0xde, 0x91, 0x5e, 0x33, 0x8a, 0x7f, 0xff, 0x9b, 0xcb, 0x99, 0x63, 0x1, 0xee, 0xa5, 0x9f, 0xc1, 0x3e, 0x6f, 0xea, 0xfc, 0xe0, 0xd1, 0x99, 0xdd, 0xe5, 0x94, 0xb, 0x9c, 0xf9, 0x57, 0x26, 0x9, 0x82, 0x5d, 0xa1, 0xdf, 0x92, 0x96, 0xf7, 0x94, 0x99, 0xd0, 0x1a, 0x1b, 0x7d, 0x7c, 0xe0, 0x2c, 0x25, 0x6c, 0x2b, 0x1b, 0x93, 0x4a, 0x17, 0xa0, 0x94, 0x2, 0xac, 0x64, 0x8, 0xa5, 0x12, 0x78, 0x48, 0x1, 0x56, 0x32, 0x8c, 0xa4, 0x7, 0x70, 0x93, 0x76, 0xc4, 0xd6, 0x6c, 0xc8, 0xa4, 0x2b, 0x30, 0xac, 0x54, 0x8c, 0x69, 0x4d, 0xad, 0xcc, 0x90, 0xd6, 0xba, 0x91, 0x49, 0xc3, 0x30, 0xb3, 0x6a, 0x22, 0x9c, 0xd5, 0x5b, 0xce, 0x2b, 0xa2, 0xe3, 0x9f, 0xf2, 0xba, 0xce, 0x8f, 0x3e, 0xbd, 0xfc, 0x1, 0xdb, 0xf3, 0x10, 0xc5, 0x78, 0x85, 0x14, 0x89, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char icon_zoom_less_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, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x13, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0x31, 0xe0, 0xc1, 0x7f, 0x3c, 0x90, 0xb0, 0x82, 0x11, 0x2, 0x0, 0xbf, 0x57, 0x36, 0x25, 0x52, 0x24, 0x7b, 0x26, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -358,6 +362,10 @@ static const unsigned char selection_oof_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, 0x0, 0x2d, 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, 0x2c, 0x2, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xaf, 0xdf, 0x90, 0xa5, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0x3, 0x20, 0x25, 0x16, 0xc, 0x1f, 0x74, 0xbf, 0x74, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x2f, 0x33, 0x4, 0x32, 0xde, 0xce, 0x64, 0xf4, 0x68, 0x53, 0x0, 0x32, 0xfe, 0xcd, 0xa0, 0x90, 0x1, 0x37, 0x10, 0x6e, 0x5, 0xdc, 0x52, 0xb8, 0x33, 0x0, 0xcc, 0x7, 0x26, 0xff, 0x1f, 0x38, 0x23, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char space_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, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc4, 0xf, 0xbe, 0x8b, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x63, 0x60, 0xa0, 0x2a, 0xf8, 0xff, 0xff, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0x5, 0x91, 0xc5, 0x58, 0x90, 0x24, 0x85, 0x18, 0x18, 0x18, 0x14, 0xa0, 0x6c, 0x6, 0x46, 0x46, 0xc6, 0xf7, 0xc, 0xc, 0xc, 0xc, 0x4c, 0x14, 0x5b, 0x41, 0x39, 0x0, 0x0, 0x71, 0x1a, 0x13, 0x5d, 0x87, 0xfe, 0x9e, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char spinbox_updown_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, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0xdc, 0x4f, 0x7f, 0x98, 0x86, 0x47, 0xfa, 0x81, 0xe5, 0x83, 0x1f, 0xf, 0x7e, 0x3d, 0xb2, 0xc5, 0xa5, 0x5b, 0xe2, 0xc1, 0x93, 0x7, 0xff, 0x81, 0xf0, 0xf9, 0x63, 0x69, 0x2c, 0xd2, 0x67, 0x58, 0xef, 0x1f, 0x2, 0x4a, 0x42, 0xe0, 0xf1, 0xdb, 0xec, 0x98, 0xfa, 0x67, 0x2, 0x25, 0xe0, 0xf0, 0xe1, 0x2, 0x86, 0x41, 0x7, 0x30, 0x1d, 0x39, 0x3, 0xbf, 0x37, 0x8f, 0xdd, 0x66, 0x27, 0x29, 0xa0, 0x10, 0x4a, 0x2c, 0xa0, 0x41, 0x8d, 0x1b, 0x3c, 0x4c, 0x3, 0x46, 0x16, 0x69, 0x0, 0x0, 0x87, 0x2a, 0x58, 0xb5, 0x18, 0xe9, 0x80, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -386,6 +394,10 @@ static const unsigned char tab_current_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, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x99, 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, 0x3f, 0x3d, 0x48, 0x5b, 0x58, 0x66, 0x5b, 0x57, 0x65, 0x57, 0x54, 0x62, 0x55, 0x53, 0x62, 0x4a, 0x46, 0x52, 0x46, 0x41, 0x4e, 0x45, 0x41, 0x4d, 0x55, 0x52, 0x60, 0x44, 0x41, 0x4c, 0x53, 0x50, 0x5e, 0x43, 0x40, 0x4b, 0x52, 0x4e, 0x5d, 0x41, 0x3e, 0x4a, 0x4f, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x4e, 0x4b, 0x59, 0x3e, 0x3c, 0x47, 0x4d, 0x4a, 0x58, 0x3d, 0x3b, 0x46, 0x4b, 0x49, 0x54, 0x3c, 0x3a, 0x44, 0x4b, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x3b, 0x39, 0x42, 0x3b, 0x38, 0x43, 0x3b, 0x38, 0x42, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3a, 0x38, 0x41, 0x39, 0x36, 0x3f, 0x38, 0x36, 0x3f, 0x39, 0x36, 0x40, 0x38, 0x36, 0x40, 0x37, 0x35, 0x3e, 0x37, 0x34, 0x3e, 0x36, 0x35, 0x3d, 0xd7, 0x41, 0xa4, 0x19, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xa3, 0x31, 0x6b, 0xc2, 0x0, 0x0, 0x0, 0x60, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0xca, 0x85, 0xd, 0xc0, 0x40, 0x14, 0xc3, 0x50, 0x27, 0xf7, 0xd5, 0xfd, 0xd7, 0x2d, 0xa6, 0x4c, 0x16, 0x3f, 0xb9, 0xd0, 0x11, 0x90, 0xa3, 0x52, 0x77, 0x49, 0x8e, 0x86, 0xd2, 0x26, 0x16, 0x7b, 0x59, 0x32, 0x68, 0x3, 0x37, 0x5d, 0xe0, 0x59, 0x3b, 0x74, 0x31, 0x67, 0x4b, 0x3b, 0xf, 0x71, 0xe5, 0xe8, 0xf, 0xec, 0xc0, 0x1f, 0x28, 0xf8, 0x2, 0x14, 0xf9, 0x42, 0xa8, 0xfc, 0x21, 0x3b, 0xe4, 0x1, 0x6f, 0x0, 0x18, 0x11, 0xac, 0x99, 0xc0, 0xe, 0x25, 0x22, 0x2d, 0x76, 0xc6, 0x13, 0x1a, 0x8, 0xac, 0x78, 0xfc, 0x1c, 0x70, 0x30, 0x2b, 0xba, 0xe9, 0x31, 0x70, 0xc1, 0x7f, 0x3b, 0x77, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char tab_disabled_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, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x3, 0xa7, 0x7a, 0x54, 0x58, 0x74, 0x52, 0x61, 0x77, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x78, 0x69, 0x66, 0x0, 0x0, 0x78, 0xda, 0xcd, 0x96, 0x59, 0x92, 0xe3, 0x2a, 0x10, 0x45, 0xff, 0x59, 0x45, 0x2f, 0x81, 0xcc, 0x24, 0x19, 0x96, 0x83, 0x18, 0x22, 0x7a, 0x7, 0x6f, 0xf9, 0x7d, 0xc1, 0x48, 0x1e, 0xab, 0x5c, 0x65, 0xfb, 0xe3, 0x89, 0xb0, 0x40, 0x29, 0x48, 0xae, 0xee, 0x41, 0xc8, 0xa6, 0xfd, 0xf7, 0xb7, 0x9b, 0x3f, 0x38, 0x28, 0x45, 0x6f, 0x9c, 0x86, 0xe8, 0x93, 0xf7, 0x16, 0x87, 0x4b, 0x2e, 0x71, 0x46, 0x23, 0xda, 0xd3, 0x71, 0xaa, 0xc9, 0xba, 0x79, 0x5e, 0x17, 0x76, 0x6f, 0x5c, 0xc5, 0xcd, 0x71, 0x83, 0x11, 0x12, 0xd4, 0x72, 0xba, 0xf4, 0x6d, 0xf5, 0xcf, 0x88, 0xeb, 0x79, 0x40, 0x70, 0x2b, 0xbe, 0x5d, 0xc7, 0x4d, 0x28, 0x2b, 0x4f, 0x5c, 0x89, 0xe8, 0x48, 0x3c, 0xf, 0x19, 0x33, 0x8f, 0xf6, 0xea, 0x17, 0x57, 0x22, 0xe1, 0x53, 0x9c, 0xd6, 0xb5, 0x49, 0x6b, 0x5c, 0x76, 0x17, 0x8f, 0xb3, 0x7e, 0x5c, 0x56, 0xda, 0x95, 0xfc, 0xf6, 0xda, 0x5, 0x98, 0x51, 0x15, 0xf9, 0x84, 0xd, 0x37, 0x21, 0xb1, 0x38, 0xc7, 0x31, 0x8b, 0x40, 0x81, 0x24, 0xc9, 0x32, 0xda, 0x79, 0xde, 0x19, 0x91, 0x80, 0xb6, 0x43, 0x9d, 0x45, 0x84, 0x1e, 0x7b, 0x67, 0x8e, 0xe6, 0x8d, 0x79, 0x47, 0xeb, 0xc6, 0x3b, 0x9b, 0x57, 0x5c, 0xae, 0xad, 0x30, 0xd6, 0xaf, 0xe, 0xfe, 0xc6, 0xa3, 0x15, 0x27, 0xbd, 0x89, 0xcb, 0x31, 0xd, 0xdf, 0x52, 0xdb, 0x67, 0xbe, 0xba, 0x91, 0xcb, 0x31, 0xc5, 0x9d, 0x77, 0xbd, 0xd7, 0xd8, 0x7b, 0x3b, 0x3d, 0x5d, 0x76, 0x1e, 0x4e, 0x79, 0xb3, 0x1e, 0x6a, 0x7f, 0x94, 0xd9, 0x42, 0xc7, 0xd, 0x56, 0xca, 0x1c, 0xe6, 0x51, 0x2, 0x7e, 0x8a, 0x76, 0x98, 0x25, 0xa1, 0x44, 0x3c, 0x62, 0x1, 0xb1, 0xa, 0x9a, 0x1b, 0x4a, 0x31, 0x94, 0x88, 0xe1, 0x69, 0x27, 0x47, 0x95, 0x32, 0x75, 0x6a, 0xb3, 0x2e, 0x54, 0x20, 0xd1, 0x71, 0xe3, 0x80, 0x9a, 0xb9, 0xb0, 0xcc, 0x58, 0x94, 0xc0, 0x89, 0xcb, 0x84, 0xe2, 0x46, 0xa1, 0xce, 0x1, 0x78, 0xaa, 0x91, 0x8, 0x3e, 0x5, 0xd4, 0x4, 0x61, 0x3e, 0xb4, 0xd0, 0x9c, 0x37, 0xcd, 0xf9, 0xa, 0x45, 0xcc, 0x5c, 0x9, 0x3d, 0x99, 0x90, 0x8c, 0x30, 0xe2, 0xae, 0x98, 0x47, 0xc1, 0x57, 0xca, 0x91, 0xa8, 0xf7, 0xb1, 0x74, 0x89, 0x6c, 0x3c, 0xbc, 0x82, 0x2e, 0x1e, 0x6b, 0x1a, 0x32, 0x6, 0xb9, 0x71, 0x46, 0x2f, 0x0, 0xa1, 0xbe, 0x3c, 0xd5, 0xe9, 0xef, 0x2c, 0xe6, 0x62, 0xdd, 0xd8, 0xb, 0xb0, 0x2, 0x82, 0x3a, 0x6d, 0x8e, 0x78, 0xc0, 0x6c, 0xb7, 0x53, 0x8a, 0x4d, 0xe9, 0xbc, 0xb6, 0x64, 0x72, 0x16, 0xf4, 0x53, 0xeb, 0x8c, 0x3d, 0xbd, 0x1a, 0x14, 0xea, 0x4a, 0x0, 0x8b, 0x30, 0xb7, 0x42, 0xc, 0x9, 0x8, 0x58, 0x4f, 0xa2, 0xe4, 0xc9, 0x6, 0xe6, 0x40, 0x4, 0x1f, 0x23, 0xf8, 0x64, 0x28, 0x67, 0x71, 0xbc, 0x81, 0x0, 0xa9, 0x72, 0x25, 0xd3, 0xc1, 0x46, 0xc4, 0x3, 0x4e, 0xe4, 0x31, 0x37, 0xc6, 0x4, 0x9a, 0x7d, 0x59, 0xf9, 0x14, 0xc6, 0xd6, 0x2, 0x10, 0x2a, 0x1e, 0xaf, 0x4a, 0x1c, 0x2f, 0x10, 0x60, 0x39, 0xa7, 0x58, 0x3f, 0xc1, 0x45, 0xac, 0xa1, 0xac, 0xa2, 0xce, 0xa8, 0xaa, 0xd7, 0xa0, 0x51, 0x93, 0x66, 0x2f, 0xde, 0x79, 0xf5, 0xde, 0x7, 0x3f, 0xf6, 0xa8, 0x1c, 0x24, 0xb8, 0xa0, 0xc1, 0x87, 0x10, 0x62, 0x48, 0x21, 0x47, 0x89, 0x2e, 0x6a, 0xf4, 0x31, 0xc4, 0x18, 0x53, 0xcc, 0x89, 0x93, 0x60, 0xb, 0xd3, 0xe4, 0x53, 0x30, 0x29, 0xa6, 0x94, 0x72, 0xc6, 0xa4, 0x19, 0xa9, 0x33, 0x46, 0x67, 0xf4, 0xc8, 0x79, 0xe3, 0x4d, 0x36, 0xb7, 0xe9, 0xe6, 0xb7, 0xb0, 0xc5, 0x2d, 0x6d, 0xb9, 0x60, 0xf9, 0x14, 0x57, 0xb4, 0xf8, 0x12, 0x4a, 0x2c, 0xa9, 0xe4, 0xca, 0x55, 0x2a, 0x5e, 0xff, 0xea, 0x6b, 0x30, 0x35, 0xd6, 0x54, 0x73, 0xa3, 0x86, 0xa5, 0xd4, 0x5c, 0xd3, 0xe6, 0x5b, 0x68, 0xb1, 0xa5, 0x96, 0x3b, 0xd6, 0x5a, 0x97, 0xee, 0xba, 0x76, 0xdf, 0x43, 0x8f, 0x3d, 0xf5, 0x7c, 0x50, 0x5b, 0x54, 0xaf, 0xa9, 0xd1, 0xd, 0xb9, 0xef, 0xa9, 0xd1, 0xa2, 0x36, 0x88, 0xb9, 0xd9, 0x2f, 0x9c, 0xa9, 0x21, 0x1c, 0xc2, 0x9e, 0x82, 0xc6, 0x76, 0xa2, 0x83, 0x19, 0x88, 0xb1, 0x23, 0x10, 0xf, 0x83, 0x0, 0x16, 0x34, 0xf, 0x66, 0x36, 0x92, 0x73, 0x3c, 0xc8, 0xd, 0x66, 0x36, 0x31, 0x5e, 0xa, 0x65, 0x50, 0x23, 0x1d, 0x70, 0x2a, 0xd, 0x62, 0x20, 0xe8, 0x1a, 0xb1, 0x76, 0x3a, 0xd8, 0x9d, 0xc9, 0x7d, 0xcb, 0xcd, 0xa8, 0xfb, 0x15, 0x37, 0xfe, 0x8a, 0x9c, 0x19, 0xe8, 0x3e, 0x41, 0xce, 0xc, 0x74, 0x8b, 0xdc, 0x3d, 0xb7, 0x7, 0xd4, 0x6a, 0x9e, 0x5f, 0x14, 0x99, 0x80, 0xc6, 0x5b, 0x38, 0x3c, 0xb5, 0xd2, 0xb1, 0xb1, 0xa1, 0x43, 0x8b, 0x99, 0x63, 0x1e, 0xdf, 0xa4, 0x97, 0x6b, 0xf3, 0x6e, 0x82, 0xff, 0x59, 0xa2, 0x76, 0x98, 0x52, 0xcd, 0x96, 0x67, 0xd4, 0xe2, 0x7b, 0x78, 0x6a, 0xd8, 0xd7, 0x6a, 0x83, 0x5d, 0x64, 0x45, 0x84, 0x8e, 0x89, 0x9e, 0x4a, 0xe9, 0x9a, 0xf6, 0x51, 0x92, 0x67, 0xc, 0xd4, 0xe2, 0x2e, 0xcf, 0xfd, 0x52, 0xb, 0xf9, 0x35, 0x30, 0x1d, 0x1e, 0xe1, 0x3, 0xb4, 0xf2, 0x97, 0x94, 0x9f, 0x8a, 0x71, 0x37, 0x62, 0x3e, 0x48, 0xd, 0x42, 0xcc, 0xae, 0x24, 0xb7, 0xa7, 0x4a, 0xf8, 0x50, 0xd2, 0x3e, 0x8d, 0xbf, 0xda, 0xc3, 0x12, 0xb3, 0xf9, 0xa7, 0x4a, 0xe8, 0x91, 0x27, 0x9f, 0x51, 0x74, 0x1, 0x67, 0x5b, 0xc9, 0xcd, 0xd7, 0x4a, 0x5c, 0xff, 0xce, 0x93, 0xf7, 0x14, 0x5d, 0x78, 0x52, 0x6e, 0xee, 0x99, 0x7, 0x4a, 0xea, 0xfe, 0xd6, 0x44, 0x25, 0xa7, 0xe3, 0x6f, 0xeb, 0xf, 0x6a, 0xf3, 0x93, 0x8e, 0x14, 0xf6, 0x67, 0xeb, 0xc2, 0x5f, 0x2c, 0x73, 0x73, 0x88, 0xad, 0xb2, 0x6b, 0xca, 0x73, 0xb8, 0x8e, 0xff, 0xd0, 0x3f, 0xaf, 0xcd, 0x77, 0x1d, 0xb4, 0x9f, 0x2d, 0x79, 0xe6, 0xb7, 0xe9, 0x2e, 0xbf, 0x62, 0xc9, 0x5d, 0x6d, 0x9e, 0x58, 0xa2, 0x4f, 0x76, 0x0, 0xa9, 0xec, 0xf7, 0x6d, 0xe4, 0x25, 0x4b, 0xee, 0x6a, 0xf3, 0xd8, 0x92, 0xfa, 0x74, 0x33, 0x71, 0xe9, 0x7a, 0xb9, 0x9a, 0xcf, 0x6c, 0xfd, 0xa7, 0x44, 0x17, 0xeb, 0xf5, 0xf7, 0x4a, 0x2e, 0x13, 0xbd, 0xbd, 0xad, 0xd9, 0x99, 0xe8, 0x4d, 0x25, 0x9f, 0x50, 0x74, 0x65, 0x89, 0x79, 0x57, 0xc9, 0x3b, 0x8a, 0x1e, 0xc2, 0xd9, 0x15, 0x75, 0xfc, 0x61, 0x49, 0xe6, 0x1f, 0xbf, 0x1c, 0xa8, 0x52, 0x2b, 0xb1, 0xc9, 0xd4, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0x2e, 0x23, 0x0, 0x0, 0x2e, 0x23, 0x1, 0x78, 0xa5, 0x3f, 0x76, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe3, 0x2, 0xa, 0x13, 0x29, 0x21, 0x5f, 0x36, 0xe2, 0x14, 0x0, 0x0, 0x0, 0xaf, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x7d, 0x91, 0x41, 0xa, 0xc2, 0x40, 0x10, 0x4, 0x6b, 0x92, 0x61, 0x37, 0xb0, 0x87, 0xec, 0x39, 0x3e, 0xc6, 0x3f, 0xf8, 0x9a, 0x3c, 0xc1, 0xd7, 0xf8, 0x3, 0xf, 0x3e, 0xc6, 0xab, 0x44, 0x50, 0x30, 0x26, 0x66, 0x3c, 0x2c, 0x6, 0x3, 0xd9, 0xf4, 0x69, 0xa0, 0xab, 0x9b, 0x86, 0x11, 0x14, 0x87, 0xa7, 0xc2, 0x51, 0x52, 0x90, 0x34, 0xf1, 0xe1, 0xcd, 0x8b, 0x9e, 0xb7, 0xe2, 0x8, 0x44, 0x6a, 0x2, 0x1e, 0x41, 0x0, 0xc3, 0xe8, 0x79, 0x72, 0xa7, 0x3, 0xc5, 0x13, 0xf7, 0x87, 0x5d, 0x3b, 0x46, 0x16, 0xd2, 0xee, 0x7a, 0xbc, 0x9c, 0x18, 0x95, 0x8a, 0xba, 0x69, 0x6f, 0x71, 0xc4, 0xfe, 0x6c, 0x41, 0x63, 0xd3, 0x72, 0xe6, 0xa1, 0x38, 0xc2, 0x10, 0x87, 0x65, 0x1c, 0x63, 0x60, 0x88, 0x4, 0x9c, 0x52, 0xe2, 0xa7, 0x45, 0x9a, 0x79, 0x29, 0x9e, 0x52, 0x29, 0x10, 0x63, 0x5a, 0x1, 0xc, 0x84, 0x42, 0x1, 0xc9, 0x36, 0x8, 0x68, 0x3a, 0x33, 0x0, 0x9, 0x30, 0x5b, 0x5, 0xc, 0x6c, 0x6e, 0x98, 0x36, 0x1b, 0x24, 0xdb, 0xf0, 0xdb, 0xc0, 0x2a, 0x90, 0x54, 0x6c, 0xba, 0x96, 0x0, 0xc9, 0x2, 0xc2, 0xfc, 0xe0, 0xac, 0xbe, 0xe, 0x38, 0x38, 0x83, 0xbf, 0x35, 0x30, 0x94, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char tab_menu_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, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x5, 0xa3, 0xe0, 0xc1, 0x7f, 0x54, 0x48, 0x3, 0x5, 0xf, 0xe3, 0x1e, 0x7c, 0x81, 0x4b, 0x7f, 0x7b, 0x98, 0x86, 0xc5, 0x15, 0xf7, 0x35, 0xee, 0x5f, 0x2, 0x4b, 0x5f, 0x7f, 0xac, 0x8b, 0xc3, 0xa1, 0x2f, 0xb8, 0x1f, 0xce, 0x7f, 0x38, 0xff, 0x5, 0x37, 0x75, 0xbd, 0xf, 0x0, 0x52, 0xd4, 0x48, 0xb8, 0x2d, 0x78, 0x5a, 0x91, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -398,10 +410,18 @@ static const unsigned char toggle_off_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x7a, 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, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x27, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1e, 0x0, 0x0, 0x0, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x2d, 0x26, 0x2c, 0x4d, 0x2b, 0x37, 0x63, 0x2f, 0x3f, 0x6e, 0x31, 0x43, 0x71, 0x32, 0x44, 0x6c, 0x31, 0x42, 0x51, 0x2c, 0x39, 0x47, 0x2a, 0x35, 0x66, 0x30, 0x40, 0x4d, 0x2b, 0x38, 0x32, 0x26, 0x2e, 0x26, 0x25, 0x2a, 0x2e, 0x25, 0x2c, 0x3c, 0x28, 0x31, 0x52, 0x2c, 0x39, 0x68, 0x30, 0x40, 0x27, 0x25, 0x2a, 0x50, 0x2c, 0x38, 0x5f, 0x2e, 0x3d, 0x35, 0x27, 0x2f, 0x38, 0x27, 0x30, 0x5e, 0x2e, 0x3d, 0x43, 0x2a, 0x34, 0x5f, 0x2f, 0x3e, 0x2f, 0x25, 0x2c, 0x44, 0x2a, 0x34, 0x2b, 0x26, 0x2c, 0x64, 0x2f, 0x3f, 0x36, 0x27, 0x30, 0x37, 0x27, 0x30, 0x66, 0x2f, 0x40, 0x2c, 0x26, 0x2c, 0x46, 0x2a, 0x35, 0x53, 0x2c, 0x39, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x32, 0x32, 0x37, 0x5d, 0x2e, 0x3d, 0x3e, 0x29, 0x32, 0xc9, 0xc9, 0xca, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x69, 0x30, 0x41, 0x2f, 0x26, 0x2d, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x4e, 0x4e, 0x52, 0x48, 0x2b, 0x36, 0x2c, 0x26, 0x2b, 0x97, 0xb0, 0x86, 0xb4, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x98, 0xe5, 0xfa, 0xfe, 0x8, 0x17, 0x35, 0x86, 0xf3, 0x7, 0x3a, 0xb4, 0xb9, 0xb, 0x28, 0x8a, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xe6, 0x37, 0xf, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xe5, 0x7c, 0xf3, 0x66, 0x0, 0x0, 0x2, 0x29, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x95, 0x3, 0x93, 0x24, 0x4b, 0x14, 0x85, 0x5f, 0xb9, 0xaa, 0x6d, 0x8e, 0x6d, 0xdb, 0x73, 0x2b, 0xb3, 0xe7, 0xad, 0x6d, 0xab, 0xdd, 0x63, 0xe3, 0xbf, 0x6f, 0x67, 0x65, 0xbb, 0xb4, 0xbb, 0x81, 0xc5, 0x97, 0x11, 0x27, 0x78, 0x4f, 0xea, 0xe2, 0xbf, 0x3f, 0x9, 0x86, 0xe5, 0x38, 0xde, 0x16, 0x8e, 0x63, 0x19, 0xc3, 0x70, 0x96, 0x17, 0x44, 0x49, 0x56, 0x1c, 0x36, 0x28, 0xb2, 0x24, 0xa, 0x3c, 0xab, 0xdf, 0x9d, 0x77, 0xca, 0x2e, 0xb7, 0xc7, 0xeb, 0xf3, 0x7, 0x2c, 0xf1, 0xfb, 0xbc, 0x1e, 0xb7, 0x4b, 0x76, 0xf2, 0x2d, 0xa7, 0x60, 0x83, 0xa1, 0x70, 0x24, 0x1a, 0x8b, 0x27, 0xb6, 0xc1, 0x86, 0xed, 0x44, 0x3c, 0x16, 0x8d, 0x84, 0x43, 0x41, 0xb6, 0x29, 0x3e, 0xd9, 0xd6, 0xde, 0xd1, 0xa9, 0x22, 0x84, 0x31, 0x6, 0xd, 0x4c, 0x40, 0x38, 0x85, 0xd, 0x4d, 0x3a, 0x3b, 0xda, 0xdb, 0x92, 0xd, 0xe, 0x4c, 0x97, 0xd2, 0xdd, 0xa3, 0xa2, 0x9d, 0xff, 0x6f, 0xdd, 0xbe, 0x43, 0xb9, 0x7b, 0x6f, 0x47, 0x73, 0x49, 0x21, 0x93, 0x73, 0xf4, 0x74, 0x2b, 0x5d, 0x4c, 0xfd, 0xfe, 0x92, 0xbb, 0x57, 0xc5, 0xf7, 0x1f, 0x3c, 0x7c, 0xf4, 0x18, 0x8, 0x8f, 0x9f, 0x3c, 0x7d, 0xf6, 0xfc, 0xfe, 0xb, 0xed, 0x24, 0x66, 0x37, 0xe9, 0x75, 0x4b, 0xb5, 0x77, 0x60, 0xfb, 0xfa, 0x7, 0x54, 0xfc, 0xf2, 0xd5, 0x6b, 0x68, 0xe0, 0xcd, 0xdb, 0x97, 0x2f, 0x2c, 0xdf, 0x62, 0xb0, 0xbf, 0xaf, 0x7a, 0x9, 0xbe, 0xcd, 0x33, 0x84, 0xde, 0xbd, 0x7f, 0x2, 0x4d, 0x7c, 0x78, 0xff, 0xf1, 0x31, 0x58, 0x30, 0x34, 0xdc, 0x36, 0x42, 0x8f, 0xc0, 0x8, 0xae, 0x51, 0xf4, 0xe9, 0xf3, 0x17, 0x68, 0xe1, 0xeb, 0xb7, 0x34, 0x58, 0x31, 0xea, 0x12, 0xa8, 0x1, 0x2b, 0xba, 0xc7, 0x50, 0xe6, 0x19, 0xe8, 0xc8, 0x66, 0x80, 0x92, 0xcb, 0x17, 0x8a, 0x25, 0xd8, 0x2d, 0x94, 0xd1, 0x64, 0xf, 0x8, 0xe3, 0x13, 0x93, 0xf4, 0xe, 0x9c, 0xe4, 0x89, 0xe3, 0xfd, 0x3, 0xd0, 0x71, 0xb0, 0xf, 0x94, 0xc3, 0xa3, 0xdc, 0x71, 0x21, 0xb7, 0x4b, 0x2, 0x35, 0xa1, 0x4c, 0xd, 0x4b, 0x1c, 0x35, 0x90, 0xa7, 0x67, 0xf0, 0xc9, 0x29, 0xe8, 0x38, 0x3d, 0xa9, 0x1c, 0x80, 0x4, 0x1d, 0x9d, 0xed, 0x9e, 0x13, 0x3, 0x22, 0x94, 0xed, 0x59, 0x99, 0xa7, 0x6, 0x6d, 0x73, 0x2a, 0xbe, 0x6d, 0xf0, 0x60, 0x8f, 0x6f, 0x13, 0x25, 0x41, 0x65, 0xb9, 0xc8, 0xef, 0x1e, 0x1e, 0x1e, 0xee, 0x69, 0x2, 0x94, 0xf9, 0xb6, 0x8a, 0x81, 0xec, 0x55, 0x2d, 0x4f, 0xb0, 0x47, 0x4e, 0x90, 0xbf, 0xdc, 0x25, 0x91, 0x44, 0x74, 0x27, 0x90, 0x3c, 0xb, 0xc8, 0xf2, 0xd, 0xce, 0xcf, 0x60, 0xaf, 0x58, 0xaa, 0x18, 0xe8, 0xdf, 0x80, 0x15, 0x27, 0x6c, 0x7e, 0x61, 0xb7, 0x78, 0x5e, 0xcc, 0x43, 0xab, 0x1, 0xfd, 0x5, 0x9a, 0x7, 0x8b, 0x36, 0x79, 0xb0, 0x77, 0x76, 0x5, 0x90, 0x2b, 0xed, 0x55, 0x84, 0xb2, 0x18, 0x16, 0x98, 0x5a, 0x26, 0x2e, 0xe1, 0x5f, 0xce, 0x44, 0x5a, 0xb, 0x83, 0x3f, 0x5f, 0xb, 0xcb, 0xb4, 0x16, 0xcc, 0xab, 0xf1, 0x9a, 0xc6, 0xdb, 0x57, 0x23, 0xed, 0x7, 0x2b, 0xab, 0x2a, 0xba, 0x69, 0xed, 0x7, 0xe6, 0x6c, 0xaf, 0xae, 0xd5, 0xfa, 0x1, 0xed, 0x48, 0x8a, 0x7b, 0x7d, 0x3, 0xa5, 0x10, 0x6d, 0x48, 0xb8, 0x2, 0x2a, 0x2f, 0x30, 0xa2, 0x73, 0xdd, 0xad, 0x24, 0x9b, 0x7b, 0x5a, 0x97, 0x14, 0xf6, 0x44, 0x63, 0x53, 0xdb, 0x60, 0xcb, 0xf6, 0x54, 0x2c, 0xea, 0x9, 0x4b, 0x5d, 0x6c, 0x6b, 0x57, 0xee, 0x93, 0x5d, 0x13, 0xc3, 0xb3, 0x9b, 0x1, 0x1b, 0x36, 0x67, 0x87, 0x27, 0x5c, 0x72, 0x1f, 0xcf, 0xe8, 0xa7, 0xca, 0x88, 0x30, 0xb9, 0xd5, 0x66, 0x3f, 0x17, 0xda, 0xb6, 0x26, 0x85, 0x11, 0x96, 0x31, 0x99, 0x4c, 0xfc, 0xf, 0x40, 0x27, 0xd3, 0xbf, 0xc4, 0x77, 0x82, 0xde, 0x40, 0xde, 0x4b, 0x3f, 0xe2, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char toggle_off_disabled_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0x4e, 0xe8, 0x1b, 0x92, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x12, 0x0, 0x0, 0xb, 0x12, 0x1, 0xd2, 0xdd, 0x7e, 0xfc, 0x0, 0x0, 0x6, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x58, 0x47, 0xed, 0x59, 0x4b, 0x6f, 0x1b, 0x55, 0x14, 0x3e, 0xb6, 0xc7, 0x8e, 0xed, 0xf1, 0x2b, 0x7e, 0x84, 0xb8, 0x49, 0x8a, 0x48, 0x36, 0x55, 0x37, 0x48, 0x5d, 0x64, 0xc1, 0x3a, 0x42, 0x82, 0x14, 0x89, 0x56, 0x14, 0x16, 0x48, 0xfc, 0x1, 0xca, 0x1f, 0x40, 0x20, 0x81, 0x90, 0xf8, 0x1, 0xd0, 0x25, 0x8b, 0x8a, 0x25, 0xa0, 0x82, 0x8a, 0x10, 0x12, 0x42, 0x8, 0x29, 0x5d, 0x15, 0xa9, 0x12, 0x8b, 0x4a, 0x20, 0x51, 0x50, 0x1b, 0xcb, 0x79, 0xf8, 0xed, 0x8c, 0xdf, 0xe3, 0x31, 0xe7, 0xbb, 0x99, 0xeb, 0x4c, 0x26, 0x33, 0xb6, 0x13, 0xbb, 0xb4, 0x42, 0xbd, 0xd2, 0xc9, 0x24, 0x77, 0xee, 0x39, 0x73, 0xbf, 0x7b, 0x1e, 0xf7, 0x9c, 0x13, 0xa2, 0x67, 0xe3, 0xd9, 0x9, 0xfc, 0xaf, 0x4e, 0xc0, 0x33, 0x21, 0x1a, 0xac, 0x93, 0x4, 0x96, 0x49, 0xf9, 0x26, 0x14, 0x7f, 0xe6, 0x65, 0x3, 0x93, 0x13, 0x4f, 0x49, 0x23, 0x85, 0x8d, 0xdb, 0xb8, 0x97, 0xb9, 0x41, 0x7e, 0xb, 0xf9, 0xcc, 0xb9, 0x71, 0xbc, 0x67, 0x46, 0x31, 0x21, 0x23, 0x0, 0x1a, 0x4c, 0x7d, 0xa6, 0x9e, 0x85, 0x30, 0x7, 0x72, 0x1c, 0x6e, 0x9b, 0xc6, 0x3c, 0x80, 0x5, 0x98, 0x22, 0x4c, 0x9, 0x93, 0x62, 0xfc, 0xc, 0x99, 0xe0, 0x71, 0x10, 0x4f, 0xa, 0xb4, 0x4, 0xb, 0xa0, 0x2d, 0xa6, 0x3a, 0x53, 0xd5, 0x24, 0x8d, 0x9f, 0x5d, 0xf3, 0x20, 0xa4, 0x5, 0xc, 0xc1, 0x3b, 0x6d, 0x18, 0x40, 0x14, 0x13, 0x68, 0x86, 0x9f, 0xcb, 0xe9, 0xf4, 0x73, 0xd7, 0x22, 0x91, 0xd8, 0x6b, 0x8a, 0xe2, 0xe3, 0xbf, 0x3d, 0x78, 0xe7, 0xe1, 0x31, 0xa1, 0x22, 0x1e, 0xcf, 0xb2, 0xc1, 0x40, 0x60, 0xe1, 0x1f, 0x3, 0x5d, 0xd7, 0xfb, 0x5, 0x4d, 0xab, 0x7f, 0x5f, 0x2c, 0xee, 0x7d, 0xcd, 0x73, 0x39, 0xa6, 0x2, 0x13, 0x80, 0xeb, 0x76, 0x6d, 0xdb, 0x77, 0xd, 0xb0, 0xd0, 0x6a, 0x9c, 0xe9, 0x7c, 0x22, 0x91, 0xba, 0x92, 0x4c, 0xa6, 0xdf, 0xf3, 0x7a, 0x3d, 0x91, 0x23, 0x7c, 0x56, 0x16, 0x37, 0xd0, 0x27, 0xe, 0xf6, 0x70, 0x6f, 0xc2, 0x20, 0x60, 0x6d, 0xb3, 0x37, 0xe, 0x1c, 0x80, 0x61, 0x18, 0x5a, 0xb9, 0x5c, 0xfc, 0xbc, 0x5a, 0x2d, 0x7d, 0xcb, 0x1f, 0x79, 0xc4, 0x54, 0x33, 0xb5, 0x3d, 0x34, 0x71, 0xfb, 0xee, 0x1, 0x76, 0x9e, 0x69, 0x35, 0x9b, 0x5d, 0x7e, 0x5f, 0x55, 0x23, 0x9b, 0x0, 0xea, 0xf7, 0x7b, 0x29, 0x99, 0x4c, 0x52, 0x34, 0x1a, 0xa5, 0xb9, 0xb9, 0x39, 0xf2, 0x7a, 0xb1, 0x61, 0xe7, 0xc1, 0xc7, 0x4d, 0xb5, 0x5a, 0x8d, 0xa, 0x85, 0x2, 0xf5, 0x60, 0x70, 0xc3, 0x21, 0xf, 0x1, 0xdf, 0xc6, 0x67, 0xdd, 0x65, 0x4c, 0x63, 0x13, 0x0, 0xde, 0x68, 0x1c, 0xfc, 0xb0, 0xb3, 0x93, 0xfb, 0x94, 0xe5, 0xfc, 0xcd, 0x54, 0x31, 0x41, 0x8b, 0xd, 0x48, 0xc0, 0xd2, 0x67, 0xa1, 0xd9, 0xb5, 0x73, 0xe7, 0x56, 0x3e, 0x9, 0x87, 0xd5, 0x97, 0x61, 0xb6, 0xe9, 0x74, 0x42, 0x80, 0x5, 0x88, 0x6a, 0xb5, 0x4a, 0xdd, 0x8e, 0x21, 0x74, 0x65, 0x1f, 0x10, 0xa0, 0x70, 0x68, 0xb, 0x6, 0x83, 0xe2, 0x60, 0x40, 0xa5, 0x52, 0x89, 0xca, 0xc5, 0x9a, 0x43, 0x4, 0x91, 0xda, 0x9e, 0x6, 0x9a, 0x3b, 0x2f, 0x40, 0x37, 0x9b, 0xda, 0x4f, 0xf9, 0xfc, 0xf6, 0x87, 0xbc, 0xea, 0x81, 0xa9, 0x69, 0x4, 0xb7, 0x1, 0x2, 0x13, 0x6, 0x8e, 0x3b, 0xc8, 0x94, 0x9d, 0x9f, 0x4f, 0xbf, 0x1d, 0x8f, 0x27, 0xde, 0x1, 0xd8, 0x6c, 0x36, 0x43, 0xaa, 0xaa, 0x52, 0x3e, 0x9f, 0x67, 0xb0, 0xd, 0xea, 0xf7, 0x9d, 0xa0, 0x1e, 0x7d, 0xd8, 0x60, 0xe5, 0x75, 0xbb, 0x3a, 0x1d, 0x1c, 0x34, 0xa9, 0xdd, 0x6e, 0x88, 0x83, 0xa, 0x86, 0x2, 0xd4, 0xd4, 0x9a, 0xb6, 0x43, 0x7a, 0xbc, 0xfe, 0x8f, 0xbd, 0xfb, 0xfd, 0x81, 0x35, 0x0, 0x6d, 0xb5, 0x9a, 0x7f, 0xf2, 0xb3, 0xc1, 0x4, 0x7f, 0x1e, 0x48, 0xbb, 0xc2, 0x13, 0xd1, 0x78, 0x39, 0x99, 0x4c, 0x5d, 0x87, 0x19, 0x27, 0x93, 0x31, 0xa, 0x85, 0x42, 0x94, 0xcb, 0xe5, 0xa8, 0xd5, 0xc2, 0xda, 0xd3, 0x8d, 0x46, 0xa3, 0x2b, 0x78, 0x21, 0x23, 0x91, 0x8c, 0xfe, 0xe7, 0xe1, 0x1c, 0xa0, 0xe7, 0xe7, 0x53, 0xef, 0xf2, 0xae, 0x57, 0x4c, 0x6c, 0x50, 0xae, 0x47, 0x46, 0xf, 0xdc, 0xb3, 0xf1, 0x4c, 0x66, 0xf1, 0x2d, 0xe, 0x50, 0xa1, 0x0, 0x7, 0xe2, 0x54, 0x2a, 0x45, 0x3b, 0x3b, 0x3b, 0x36, 0x3f, 0x3c, 0x1d, 0x68, 0xf8, 0xf0, 0xee, 0xee, 0xae, 0x90, 0xe5, 0x53, 0x46, 0x5b, 0xc7, 0xe9, 0x24, 0x4f, 0xb6, 0xda, 0xeb, 0xf5, 0x85, 0x18, 0xd3, 0x9b, 0xc0, 0x6, 0x8f, 0x3, 0x97, 0xb8, 0x62, 0x98, 0x0, 0x38, 0xa1, 0xaa, 0xd1, 0x4d, 0x4c, 0x46, 0x93, 0x11, 0x76, 0xfc, 0xc6, 0x99, 0x34, 0x6b, 0xdf, 0x4a, 0xb3, 0xd9, 0x63, 0x7f, 0x6a, 0x52, 0x3c, 0x1e, 0x67, 0x9f, 0xc6, 0x75, 0xe9, 0x3c, 0x7a, 0xbd, 0x36, 0xad, 0xaf, 0xaf, 0xd3, 0xc5, 0x8b, 0x17, 0xa8, 0xd3, 0xe9, 0xd0, 0xd6, 0xd6, 0x1d, 0xda, 0xdb, 0x2b, 0xb1, 0x85, 0x4, 0xe8, 0xea, 0xd5, 0xd7, 0x8f, 0x31, 0xdd, 0xba, 0xf5, 0xdd, 0x89, 0xb9, 0xdb, 0xb7, 0x7f, 0x64, 0x57, 0x3a, 0x38, 0x21, 0x1c, 0x81, 0x97, 0xe3, 0xe7, 0x17, 0xfc, 0x62, 0x8f, 0xa9, 0x63, 0x5, 0x1c, 0xe3, 0x7b, 0x36, 0xd, 0xfc, 0xb1, 0x58, 0x8c, 0xca, 0xe5, 0xf2, 0x64, 0xc7, 0x38, 0xc1, 0x2a, 0x4d, 0xd3, 0x84, 0x3f, 0x8f, 0x2, 0xbc, 0xb1, 0xb1, 0x21, 0x80, 0xde, 0xbc, 0xf9, 0x25, 0x7, 0xca, 0x34, 0x5d, 0xbe, 0xfc, 0xaa, 0xf8, 0x1d, 0x80, 0x31, 0xac, 0x80, 0x9c, 0xe6, 0xdc, 0xb6, 0xa1, 0x28, 0xa, 0x72, 0x9, 0x24, 0x4c, 0x2, 0xab, 0xf4, 0x61, 0xd8, 0x37, 0x82, 0x96, 0x50, 0x7b, 0x20, 0xc0, 0x81, 0x86, 0xb5, 0x32, 0xab, 0x1, 0x59, 0x90, 0x39, 0x4a, 0xbb, 0xcb, 0xcb, 0xe7, 0xe8, 0xfe, 0xfd, 0x3f, 0x38, 0xd8, 0x4, 0xf9, 0x46, 0xd0, 0xe8, 0xc1, 0x83, 0x7f, 0x68, 0x75, 0x75, 0x55, 0xb0, 0xec, 0xef, 0x97, 0x4e, 0xb0, 0x3a, 0xcd, 0x39, 0xcb, 0x17, 0x89, 0x12, 0xb2, 0x43, 0xe1, 0xc3, 0x2, 0x20, 0x7e, 0x91, 0x13, 0xf8, 0x83, 0x4f, 0x85, 0xf4, 0x63, 0x77, 0xe8, 0x74, 0xd0, 0x21, 0xb, 0x32, 0xdd, 0x6, 0x2c, 0xa, 0x0, 0xac, 0x26, 0x59, 0x2c, 0x16, 0x84, 0xa6, 0x8b, 0xc5, 0x22, 0x47, 0xfe, 0xe, 0x5d, 0xba, 0xf4, 0xa2, 0x60, 0xbf, 0x77, 0xef, 0x77, 0xd2, 0xf5, 0xce, 0x89, 0x39, 0x27, 0x73, 0x16, 0xc0, 0xe, 0x33, 0xa6, 0x61, 0xa6, 0x23, 0x77, 0x21, 0x73, 0x53, 0x21, 0x14, 0xc9, 0x3, 0xee, 0xd4, 0xe3, 0x89, 0xc3, 0xd9, 0x41, 0x43, 0x16, 0x64, 0xba, 0xd, 0x45, 0x99, 0xa3, 0x85, 0x85, 0x94, 0xb8, 0xbb, 0xe5, 0xc6, 0xa3, 0xd1, 0x98, 0x0, 0x25, 0x7, 0x80, 0xca, 0x77, 0xd2, 0xa4, 0xad, 0x73, 0x6e, 0xb2, 0xcd, 0x14, 0x14, 0xd9, 0x8e, 0x88, 0x9a, 0xd2, 0xa4, 0x71, 0x29, 0x73, 0x12, 0x3e, 0xe0, 0x5d, 0xd, 0xf8, 0x43, 0x5d, 0xa, 0x87, 0xc3, 0x67, 0x47, 0x68, 0xe3, 0x84, 0x2c, 0xc8, 0x74, 0x1b, 0x0, 0x2, 0xd, 0x27, 0x12, 0x51, 0xb1, 0x4, 0xc0, 0xd7, 0xd6, 0x5e, 0x10, 0xda, 0x9d, 0x7e, 0x0, 0x93, 0x28, 0x30, 0x44, 0xe2, 0x1, 0xd, 0x3, 0x39, 0xc, 0xf8, 0x40, 0xd7, 0x8d, 0x82, 0xdf, 0xef, 0xcb, 0xd6, 0xeb, 0x75, 0x91, 0x70, 0xd4, 0x6a, 0xb3, 0xf1, 0xe3, 0x48, 0x24, 0x42, 0x90, 0x39, 0x6a, 0xdc, 0xb9, 0xb3, 0x45, 0x9b, 0x9b, 0xaf, 0xd0, 0x85, 0xb, 0x1a, 0x47, 0xf4, 0x88, 0xf0, 0x61, 0x19, 0xa5, 0xa7, 0x1, 0xcd, 0x96, 0x85, 0x42, 0x2, 0x1f, 0x17, 0x89, 0x87, 0x35, 0xd3, 0xa, 0x70, 0x76, 0xb2, 0xc0, 0xa9, 0xe1, 0xa5, 0x7e, 0x5b, 0xa7, 0xcc, 0x62, 0x86, 0xaf, 0x25, 0x8d, 0x4d, 0xd1, 0xb5, 0xb4, 0x9c, 0x68, 0x1f, 0xe1, 0xb0, 0x5f, 0xdc, 0xc3, 0xb8, 0x8f, 0xd, 0xc3, 0x3d, 0xc3, 0xe2, 0x8a, 0x87, 0xb6, 0xb7, 0xf3, 0xc4, 0x55, 0xf, 0xdd, 0xbd, 0xfb, 0x1b, 0xe7, 0x0, 0xfb, 0x42, 0x7e, 0xab, 0xd5, 0x10, 0xa6, 0xdd, 0xeb, 0xf5, 0x87, 0x56, 0xe2, 0x34, 0xe7, 0x6e, 0x3d, 0xb5, 0xaf, 0x38, 0xcd, 0xfc, 0x85, 0xdf, 0xe3, 0xda, 0xd1, 0x25, 0x60, 0x61, 0xde, 0xfc, 0xa2, 0xc0, 0xa9, 0xe5, 0x35, 0xc3, 0x33, 0x60, 0xaf, 0x33, 0x28, 0x93, 0xc9, 0x88, 0xd, 0x20, 0x65, 0x3c, 0xcb, 0xf0, 0xb3, 0x94, 0xa5, 0xa5, 0x25, 0xaa, 0x54, 0x2a, 0xd4, 0xe4, 0xcc, 0x6b, 0xdc, 0x80, 0xd9, 0xd7, 0xeb, 0x7, 0x34, 0x18, 0x1c, 0x1d, 0x8c, 0xcf, 0xa7, 0x70, 0x4e, 0xd0, 0x3a, 0xe6, 0x12, 0x4e, 0x73, 0x4e, 0xb2, 0xd, 0xa3, 0xdf, 0xca, 0xe5, 0x1e, 0x7e, 0xc0, 0xef, 0x1e, 0x32, 0x21, 0xbd, 0x34, 0xac, 0x80, 0x45, 0x46, 0xcf, 0x41, 0x4d, 0xf, 0x85, 0xc2, 0x2f, 0xb5, 0xdb, 0x5d, 0x2e, 0x4, 0x2, 0xe2, 0xfe, 0xec, 0x74, 0x9a, 0xa7, 0xd6, 0xb4, 0xaa, 0x6, 0x38, 0x17, 0xcf, 0x72, 0x4e, 0xdd, 0xa6, 0x52, 0xa1, 0xea, 0x58, 0x70, 0x8c, 0x3b, 0x80, 0x69, 0xde, 0x23, 0x58, 0x55, 0x2a, 0xc5, 0xcf, 0x38, 0x97, 0xfe, 0x95, 0xe5, 0x20, 0x18, 0xe0, 0xc4, 0x87, 0x26, 0xd, 0xd9, 0xa2, 0x5d, 0xc2, 0xb, 0x76, 0x82, 0xc1, 0xd0, 0xf3, 0x7e, 0xbf, 0x7f, 0x4d, 0xe3, 0xa4, 0x5f, 0x51, 0xbc, 0xb4, 0xb8, 0xb8, 0x28, 0x9e, 0xb8, 0xe, 0xc, 0x97, 0x2, 0x42, 0xa4, 0x6b, 0xac, 0x51, 0x55, 0xd, 0xf2, 0x75, 0x32, 0x2f, 0xac, 0x43, 0x94, 0x89, 0x7b, 0x65, 0xf7, 0x7e, 0xcb, 0x34, 0x88, 0x46, 0xf0, 0xca, 0x6a, 0x69, 0x7f, 0x7f, 0xf7, 0x6, 0x2f, 0x43, 0x43, 0x40, 0x68, 0x17, 0x2c, 0x6e, 0xf5, 0x30, 0x97, 0x88, 0xe7, 0x3f, 0xe2, 0xe8, 0xba, 0x81, 0x6b, 0x4c, 0x51, 0x3c, 0xc2, 0xf, 0xa7, 0xab, 0x87, 0x1f, 0x13, 0x3a, 0x9b, 0xd8, 0x43, 0xb0, 0x8d, 0x9f, 0xf3, 0xf9, 0x47, 0x1f, 0xf3, 0xab, 0xbf, 0x98, 0x1c, 0xeb, 0x61, 0xc9, 0x26, 0x3b, 0x1e, 0xe8, 0x61, 0x9d, 0xe7, 0x6a, 0xe3, 0xa, 0xd3, 0x75, 0x9f, 0xcf, 0xcb, 0x95, 0x94, 0xac, 0x61, 0xad, 0x25, 0xb4, 0xf5, 0x6b, 0xe3, 0x8a, 0x3, 0xc9, 0x6f, 0x97, 0x33, 0xbb, 0x83, 0xe8, 0xf7, 0xfb, 0x1a, 0x9b, 0xf1, 0x8d, 0x4a, 0x65, 0xd8, 0xf1, 0x40, 0x9f, 0xb, 0xa6, 0xec, 0xd8, 0xf1, 0xb0, 0x82, 0x46, 0x31, 0x81, 0x72, 0x91, 0x73, 0x6b, 0x5a, 0xe1, 0x9e, 0xd6, 0x1b, 0x66, 0x4f, 0x6b, 0x1, 0xd9, 0xd9, 0x93, 0xee, 0x67, 0xc9, 0x8d, 0x1e, 0x26, 0x15, 0xa2, 0xa7, 0xb5, 0x6f, 0xf6, 0xb4, 0xbe, 0xe1, 0x89, 0x6d, 0xd3, 0x67, 0xd1, 0xd3, 0xc2, 0x75, 0x7b, 0x2c, 0xe4, 0x8e, 0xeb, 0x5a, 0xce, 0x31, 0x83, 0xca, 0x4, 0x8d, 0xa3, 0xf5, 0x63, 0xef, 0x5a, 0xce, 0x4e, 0x3d, 0xa7, 0x97, 0x4, 0x20, 0xd6, 0xae, 0x25, 0x4c, 0x17, 0x1a, 0x85, 0xbf, 0x22, 0x45, 0x13, 0x89, 0x86, 0x5d, 0xec, 0xa8, 0xd6, 0x3, 0xde, 0xc9, 0x1c, 0x1b, 0x9, 0xa, 0xb2, 0x7f, 0x68, 0x5e, 0x24, 0xe1, 0x26, 0x9d, 0x7e, 0x9b, 0xb3, 0xe3, 0x90, 0x8d, 0x77, 0xd9, 0x97, 0x86, 0xe9, 0x22, 0xb9, 0x90, 0x40, 0x1d, 0x7d, 0x6c, 0xd2, 0x5e, 0x8b, 0x4, 0xf8, 0x34, 0x0, 0xb5, 0x1f, 0x99, 0xf5, 0xbf, 0xe, 0xe3, 0x2, 0xc9, 0xec, 0x8e, 0xfb, 0x99, 0xa4, 0xa7, 0xf4, 0x4, 0xfe, 0x5, 0x72, 0xf1, 0x9c, 0xca, 0xa6, 0xf4, 0x2a, 0x9a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char toggle_on_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x74, 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, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x12, 0x12, 0x15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x1a, 0x1a, 0x1e, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0xb, 0xb, 0xd, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x0, 0x0, 0x0, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x2c, 0x36, 0x27, 0x49, 0x65, 0x29, 0x5d, 0x85, 0x2a, 0x66, 0x95, 0x2a, 0x68, 0x99, 0x29, 0x64, 0x92, 0x28, 0x4c, 0x6b, 0x25, 0x27, 0x2d, 0x27, 0x43, 0x5c, 0x29, 0x5f, 0x89, 0x27, 0x49, 0x66, 0x25, 0x30, 0x3e, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x25, 0x2d, 0x38, 0x25, 0x3a, 0x4c, 0x27, 0x4d, 0x6b, 0x29, 0x60, 0x8c, 0x27, 0x44, 0x5c, 0x27, 0x4b, 0x69, 0x28, 0x59, 0x7f, 0x25, 0x34, 0x43, 0x25, 0x35, 0x45, 0x28, 0x58, 0x7f, 0x25, 0x26, 0x2b, 0x27, 0x40, 0x57, 0x27, 0x41, 0x57, 0x25, 0x2a, 0x33, 0x29, 0x5d, 0x87, 0x25, 0x34, 0x44, 0x25, 0x2b, 0x34, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x4e, 0x4e, 0x52, 0xc9, 0xc9, 0xca, 0x27, 0x43, 0x5b, 0x27, 0x4d, 0x6c, 0x27, 0x4e, 0x6d, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x28, 0x56, 0x7b, 0x26, 0x3b, 0x4e, 0x26, 0x3a, 0x4e, 0x32, 0x32, 0x37, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x29, 0x61, 0x8d, 0x25, 0x2e, 0x39, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0xe4, 0xe4, 0xe5, 0x27, 0x44, 0x5d, 0xdd, 0xc9, 0xf2, 0x7e, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0x8, 0x17, 0x35, 0x73, 0xd9, 0x7, 0x3a, 0x96, 0xf9, 0x9a, 0xb, 0x28, 0x76, 0xfb, 0x77, 0xde, 0x45, 0x5, 0x82, 0xc6, 0xc6, 0x37, 0xf, 0xe9, 0x4c, 0x4e, 0x4f, 0x50, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x37, 0x21, 0x5a, 0x6c, 0x0, 0x0, 0x2, 0x4, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x95, 0x63, 0x83, 0xdc, 0x60, 0x10, 0xc7, 0x1b, 0x3c, 0xc1, 0xda, 0x3e, 0xdb, 0x36, 0xe7, 0x6c, 0xdb, 0xa, 0xcf, 0xc6, 0x7e, 0xf8, 0x2a, 0x6d, 0xb8, 0xac, 0x7b, 0xbf, 0xf7, 0xf3, 0x1f, 0xcf, 0x7c, 0xf8, 0x97, 0xc0, 0x70, 0x82, 0x20, 0xb3, 0x42, 0x10, 0x38, 0x96, 0xd2, 0x1c, 0x27, 0x11, 0x45, 0x33, 0xac, 0x2d, 0xb, 0x2c, 0x43, 0x53, 0x88, 0xc4, 0xad, 0xde, 0x49, 0x3b, 0xe3, 0x70, 0xba, 0xdc, 0x1e, 0xaf, 0x2f, 0x23, 0x5e, 0x8f, 0xdb, 0xe5, 0x74, 0x30, 0x76, 0xd2, 0x14, 0x5, 0xee, 0xf, 0x4, 0x43, 0xe1, 0x48, 0x34, 0x16, 0x87, 0x2c, 0xc4, 0x63, 0xd1, 0x48, 0x38, 0x14, 0xc, 0xf8, 0x71, 0x83, 0x7d, 0xa2, 0xa0, 0xb0, 0xa8, 0x78, 0x4, 0x72, 0x64, 0xa4, 0xb8, 0xa8, 0xb0, 0x20, 0xa1, 0x53, 0xc0, 0x4a, 0xd8, 0xd2, 0xb2, 0x72, 0xc8, 0xc4, 0xe8, 0xd8, 0xf8, 0xc4, 0xa4, 0xc2, 0xd4, 0xf4, 0x28, 0x94, 0x97, 0x95, 0xb2, 0x25, 0x98, 0x96, 0x3f, 0xed, 0xac, 0xc8, 0x18, 0xfb, 0xcc, 0xec, 0xdc, 0xfc, 0xc2, 0xe2, 0xd2, 0x17, 0x96, 0x57, 0x56, 0xd7, 0xd6, 0x37, 0x66, 0xe2, 0x15, 0x4e, 0x5a, 0xad, 0x3, 0x5e, 0x59, 0x55, 0x5d, 0x93, 0xd1, 0x7e, 0x73, 0x6b, 0x1b, 0x74, 0xec, 0xec, 0x6e, 0xce, 0xd4, 0xd4, 0x56, 0x55, 0x7e, 0x4f, 0x82, 0x2c, 0x70, 0xd5, 0x41, 0x6, 0xf6, 0xf6, 0xb7, 0x56, 0xc0, 0xc0, 0xca, 0xd6, 0xc1, 0x5e, 0x5d, 0x7d, 0x41, 0x83, 0x12, 0x2, 0x86, 0x1c, 0x8d, 0x90, 0x89, 0xc3, 0xa3, 0x63, 0x30, 0xb1, 0x33, 0x77, 0x2, 0x8d, 0xe, 0xa4, 0x8, 0xe0, 0x94, 0xb3, 0x9, 0x54, 0x4e, 0xcf, 0x38, 0x5e, 0x0, 0x91, 0x93, 0x40, 0x94, 0x41, 0xe1, 0xfc, 0x2, 0x2c, 0x5c, 0x9e, 0x43, 0x73, 0x4b, 0xab, 0x92, 0x3, 0x41, 0xbb, 0xa2, 0xa0, 0x22, 0x5f, 0x9d, 0x5e, 0x73, 0xa7, 0x22, 0x27, 0x6b, 0x2, 0x37, 0xb7, 0x60, 0xe1, 0xee, 0x6, 0xda, 0xea, 0x69, 0x42, 0x11, 0x60, 0xda, 0x63, 0x5a, 0x0, 0xdc, 0x3d, 0xc0, 0xd5, 0x83, 0xf8, 0xc8, 0x8b, 0xaa, 0xc0, 0xd3, 0x33, 0x58, 0x78, 0x7e, 0x82, 0xf2, 0xe, 0x86, 0x54, 0x4, 0xa, 0x3a, 0xb5, 0x1e, 0x8a, 0x8f, 0x0, 0xf0, 0x72, 0x26, 0xca, 0x2f, 0x8f, 0xaa, 0xc0, 0xc4, 0x22, 0x58, 0x58, 0x9c, 0x0, 0xe8, 0x2a, 0xf8, 0x26, 0xc0, 0xb8, 0xb5, 0x21, 0xba, 0xff, 0x12, 0xc1, 0xd9, 0xeb, 0x67, 0xe3, 0xb7, 0xb3, 0x9c, 0x23, 0xa0, 0x5d, 0x6d, 0xa0, 0xf2, 0xf8, 0x0, 0xf7, 0xbc, 0xf0, 0x59, 0x40, 0xe0, 0x72, 0xad, 0x1, 0x4e, 0xb5, 0xe8, 0xba, 0x20, 0xf2, 0x8f, 0xfc, 0xd9, 0xd7, 0x2, 0x3e, 0xe6, 0xda, 0x5, 0xc, 0x39, 0xba, 0x41, 0xe3, 0xfe, 0x41, 0x2, 0x38, 0x15, 0x0, 0x24, 0x21, 0xf3, 0x1c, 0x74, 0x7, 0x11, 0xf6, 0xd3, 0x93, 0xa8, 0xee, 0x42, 0x6d, 0xfe, 0xbb, 0xd0, 0xa3, 0xed, 0x42, 0xe, 0xdb, 0xb8, 0x61, 0xdc, 0xc6, 0xa4, 0xba, 0x8d, 0xea, 0x3d, 0xe8, 0xed, 0xab, 0xc9, 0xe7, 0x1e, 0xd4, 0xf4, 0xf5, 0xab, 0xf7, 0x40, 0xb9, 0x48, 0xac, 0x73, 0x60, 0x10, 0x72, 0x66, 0x70, 0xc0, 0xc9, 0x26, 0x8c, 0x37, 0xad, 0x84, 0xe, 0xba, 0xc2, 0x91, 0xb6, 0x72, 0xc8, 0x4a, 0x79, 0x5b, 0x24, 0xec, 0xa, 0xd2, 0x25, 0xb8, 0xf9, 0x2a, 0x57, 0x32, 0x8e, 0x96, 0xfa, 0x8e, 0x21, 0x5f, 0x16, 0x86, 0x3a, 0xea, 0x5b, 0x1c, 0x4c, 0x25, 0x89, 0x59, 0xbf, 0x4a, 0x3, 0x6a, 0x1d, 0x2e, 0xc8, 0xfe, 0x17, 0xa, 0x86, 0x5b, 0x51, 0x3, 0x8e, 0xa5, 0xf9, 0x4c, 0x64, 0xe, 0x68, 0x9f, 0xe9, 0xbd, 0xf0, 0x9, 0xb7, 0x71, 0x36, 0xc6, 0x9b, 0x3d, 0x7f, 0x21, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char toggle_on_disabled_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0xa2, 0x9d, 0x7e, 0x84, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x12, 0x0, 0x0, 0xb, 0x12, 0x1, 0xd2, 0xdd, 0x7e, 0xfc, 0x0, 0x0, 0x6, 0x54, 0x49, 0x44, 0x41, 0x54, 0x68, 0x43, 0xed, 0x59, 0x4b, 0x6f, 0x1b, 0x55, 0x14, 0x3e, 0x71, 0xfc, 0x9a, 0xd8, 0x4e, 0x9c, 0x38, 0x6e, 0x62, 0xe7, 0x21, 0xb5, 0x6e, 0x51, 0xd5, 0x5, 0xa8, 0xac, 0x93, 0x14, 0x89, 0x22, 0x84, 0xba, 0x60, 0x53, 0xb1, 0x29, 0x12, 0x42, 0xa0, 0xfe, 0x1, 0x7e, 0x1, 0x7b, 0xb6, 0x6c, 0xaa, 0x82, 0xa8, 0xc4, 0x96, 0x5f, 0x50, 0x21, 0x55, 0x34, 0x1b, 0x4a, 0x17, 0x65, 0x51, 0x9, 0x85, 0x3c, 0x9b, 0xb4, 0x4d, 0xfd, 0x76, 0xfc, 0x7e, 0xf3, 0x7d, 0x37, 0x33, 0xc6, 0x76, 0xed, 0xcc, 0x38, 0x4e, 0x52, 0x21, 0x7a, 0xa4, 0xa3, 0xc9, 0x4c, 0xee, 0x3d, 0xf7, 0xbc, 0xee, 0xb9, 0xdf, 0x3d, 0x16, 0x79, 0x4b, 0x6f, 0x3d, 0xf0, 0xbf, 0xf6, 0xc0, 0xc8, 0x80, 0xd6, 0x73, 0xbc, 0xc1, 0x9c, 0x3a, 0xe8, 0xfc, 0x1, 0x97, 0xb3, 0x3c, 0xbc, 0xa9, 0x8f, 0xe4, 0xd3, 0x60, 0x4b, 0x93, 0xad, 0x1a, 0x60, 0x83, 0x34, 0xb2, 0xa3, 0x8d, 0x47, 0xf5, 0x6f, 0x56, 0x65, 0x58, 0x52, 0xe8, 0x18, 0x83, 0x68, 0x70, 0x3, 0x5c, 0x7, 0x57, 0xdb, 0x98, 0xdf, 0xc8, 0x47, 0x92, 0x99, 0xf2, 0xfc, 0x3f, 0xd, 0x75, 0x82, 0xbd, 0x60, 0xbf, 0xce, 0xe3, 0x78, 0x6a, 0xba, 0x33, 0xe8, 0x18, 0x33, 0x39, 0x66, 0x7a, 0x1c, 0xf7, 0xff, 0x86, 0xf1, 0x34, 0xbc, 0x8, 0x3e, 0x0, 0xa7, 0x75, 0xce, 0xe1, 0x59, 0xd1, 0x1d, 0x63, 0x64, 0xc8, 0x6b, 0xeb, 0x1c, 0xa5, 0x38, 0xd, 0xb3, 0xeb, 0x86, 0x7, 0xf1, 0x9c, 0xf7, 0xf9, 0x26, 0x96, 0xc1, 0x1f, 0x39, 0x9d, 0xce, 0xb, 0x36, 0xdb, 0xe8, 0xb8, 0xcd, 0x66, 0xd3, 0x46, 0x40, 0xc7, 0xd5, 0xfe, 0x24, 0xe6, 0x35, 0x41, 0x8d, 0x46, 0xa3, 0xd8, 0x68, 0xd4, 0xf, 0x2a, 0x95, 0xca, 0x66, 0x36, 0x9b, 0xb9, 0xf, 0x7e, 0x8, 0xd9, 0x7b, 0xe0, 0x18, 0x98, 0x8e, 0xa8, 0xf5, 0xcb, 0x86, 0x7e, 0xca, 0xd3, 0x78, 0x46, 0x7d, 0x2, 0xbc, 0x38, 0x36, 0xe6, 0x5d, 0x9, 0x4, 0x82, 0xb7, 0x5d, 0x2e, 0xf7, 0x3b, 0x6f, 0xd8, 0x5e, 0x53, 0x9f, 0xc1, 0x1f, 0x52, 0x2e, 0x97, 0xd6, 0x12, 0x89, 0xd8, 0x9d, 0x42, 0x21, 0xf7, 0x1b, 0x26, 0x3c, 0x3, 0x67, 0xf4, 0x6c, 0x78, 0x6d, 0x4b, 0xf4, 0x72, 0x0, 0xbf, 0xd1, 0xf8, 0x49, 0xf0, 0x85, 0xc9, 0xc9, 0xe9, 0xcf, 0xa7, 0xa6, 0xa6, 0xbf, 0x42, 0xb4, 0xf9, 0xed, 0x4c, 0x49, 0xd3, 0xec, 0x32, 0x3b, 0x3b, 0x2b, 0x93, 0x93, 0x93, 0xa2, 0x69, 0x9a, 0x40, 0x87, 0xbe, 0xeb, 0xd7, 0x6a, 0x35, 0x89, 0xc7, 0xe3, 0xb2, 0xb7, 0xb7, 0x27, 0xc5, 0x62, 0x4d, 0x90, 0x15, 0x95, 0x64, 0x32, 0xfe, 0x43, 0x2a, 0x15, 0xff, 0x19, 0x93, 0x36, 0xc1, 0x29, 0xdd, 0x9, 0x1d, 0xdb, 0xa1, 0xdb, 0x1, 0xc6, 0x9e, 0x67, 0xe4, 0x23, 0x53, 0x53, 0xc1, 0xaf, 0x61, 0xfc, 0xd7, 0x67, 0x9e, 0xe6, 0xb6, 0x51, 0x59, 0x98, 0xb, 0xca, 0xcc, 0xcc, 0x8c, 0x24, 0x12, 0x9, 0x65, 0x58, 0x36, 0x87, 0x6d, 0xde, 0xec, 0x51, 0xd3, 0xb0, 0x3, 0x35, 0xb7, 0x4d, 0x3c, 0x1e, 0x8f, 0xf8, 0xfd, 0x7e, 0xe5, 0xac, 0xfd, 0xfd, 0x7d, 0xd9, 0x7d, 0x1e, 0x93, 0x66, 0xbd, 0xd6, 0x84, 0x13, 0xee, 0x26, 0x93, 0xb1, 0xbb, 0xb0, 0x67, 0x43, 0xcf, 0x4, 0x16, 0xcb, 0x96, 0x13, 0x58, 0xe0, 0xda, 0x89, 0x2e, 0x76, 0x83, 0x43, 0x1e, 0x8f, 0xef, 0xe3, 0x60, 0x70, 0xe6, 0x1b, 0x78, 0xbd, 0x7b, 0xcc, 0xe9, 0x66, 0x1, 0x96, 0x8b, 0x9c, 0x9f, 0x93, 0x89, 0x89, 0x9, 0xd9, 0xdc, 0xdc, 0x84, 0x31, 0x9, 0xa9, 0x54, 0xb8, 0x85, 0xfb, 0xd5, 0xb1, 0xa6, 0xd4, 0x6a, 0xd, 0x29, 0x14, 0xca, 0x92, 0x4c, 0x66, 0xf0, 0xcc, 0x4a, 0x28, 0x14, 0x12, 0xaf, 0xc7, 0x2d, 0xa9, 0x4c, 0x7e, 0xc4, 0xed, 0x72, 0xbd, 0x57, 0xa9, 0x94, 0xb7, 0xaa, 0xd5, 0xca, 0x2e, 0x84, 0xe4, 0xc1, 0x1d, 0xc2, 0xba, 0x8d, 0xe3, 0x3b, 0x2b, 0xfd, 0xa5, 0x50, 0x68, 0xfe, 0x5b, 0x87, 0xc3, 0x11, 0x38, 0x5d, 0x6b, 0xbb, 0xa4, 0x23, 0x9a, 0xe1, 0x50, 0x40, 0x45, 0x71, 0x6d, 0x6d, 0x4d, 0x72, 0xb9, 0xf2, 0xc0, 0xcb, 0x97, 0x4a, 0x55, 0x39, 0x38, 0x48, 0x29, 0x27, 0x8c, 0xda, 0x9a, 0x92, 0xcb, 0x97, 0x6c, 0x28, 0xda, 0x91, 0x4c, 0x26, 0xc5, 0x7a, 0xc0, 0x6d, 0x40, 0xa1, 0x2d, 0x6f, 0xb6, 0x6f, 0x2a, 0xa6, 0x3f, 0xcf, 0xf9, 0x89, 0xf1, 0x71, 0xff, 0xa, 0xa, 0xde, 0xf9, 0x81, 0x57, 0x1f, 0x72, 0x82, 0xcb, 0x39, 0xa2, 0x14, 0xdf, 0xd9, 0xd9, 0x51, 0xfb, 0xf8, 0xb8, 0xc4, 0xb9, 0x94, 0x11, 0xe, 0x87, 0x85, 0x32, 0x69, 0xb, 0x6c, 0x5a, 0xa6, 0x6d, 0x60, 0x9e, 0x6c, 0x2d, 0xea, 0xe5, 0x0, 0xbf, 0xd7, 0x3b, 0x7e, 0xdd, 0xea, 0xe2, 0x73, 0x73, 0x61, 0xb9, 0x7a, 0xf5, 0x5d, 0xb9, 0x75, 0xeb, 0x33, 0xb9, 0x79, 0xf3, 0x53, 0xec, 0xdb, 0xc3, 0xa4, 0xd1, 0x34, 0xa7, 0xfa, 0x66, 0x43, 0x14, 0x8c, 0xf7, 0x6b, 0xd7, 0x96, 0x8e, 0x14, 0x1b, 0xc, 0x6, 0x11, 0xbd, 0x3, 0x49, 0xa7, 0x99, 0xa9, 0xc3, 0x11, 0x65, 0x64, 0x32, 0x19, 0xa1, 0x4c, 0x92, 0xd7, 0xeb, 0xa3, 0x4d, 0x2c, 0xec, 0x2c, 0xe6, 0xad, 0xda, 0xd7, 0xcb, 0x1, 0xe3, 0x48, 0x19, 0xcb, 0xd1, 0xbf, 0x78, 0xf1, 0x2, 0x3c, 0xec, 0x92, 0x7, 0xf, 0x56, 0xe5, 0xfe, 0xfd, 0x5f, 0xe5, 0xfa, 0xf5, 0xf, 0x85, 0x4e, 0x31, 0x68, 0x79, 0x99, 0x8e, 0xb7, 0x46, 0x4c, 0xfd, 0x74, 0x9a, 0x38, 0xe6, 0x64, 0x88, 0xb2, 0x28, 0x93, 0xe4, 0x74, 0xba, 0x22, 0x78, 0x10, 0xc0, 0x31, 0x3, 0x7a, 0x3a, 0x80, 0xe3, 0x58, 0x3, 0xdc, 0x4, 0x39, 0x56, 0x54, 0xa0, 0xa1, 0xf3, 0xf3, 0x61, 0x79, 0xfa, 0xf4, 0x2f, 0x79, 0xfe, 0xfc, 0x5, 0x3c, 0x9e, 0x93, 0x8d, 0x8d, 0x2d, 0x44, 0xfd, 0x70, 0x76, 0x34, 0x9a, 0x40, 0x4, 0x2, 0x2a, 0x1b, 0xac, 0x10, 0x8f, 0xba, 0x7c, 0x7e, 0xf8, 0xe8, 0x1b, 0x6b, 0x51, 0x16, 0x65, 0x2a, 0xc3, 0x46, 0xed, 0xac, 0x6d, 0x7c, 0xa1, 0x8d, 0x7d, 0x1d, 0xa0, 0x8e, 0x41, 0x22, 0x3c, 0x2b, 0xa, 0xe3, 0x88, 0x51, 0x46, 0x66, 0xb3, 0xd9, 0xd6, 0xf0, 0x78, 0x3c, 0x26, 0xd3, 0xd3, 0xd3, 0xea, 0x1d, 0xd5, 0x57, 0x9e, 0x3c, 0xf9, 0x53, 0x96, 0x96, 0xac, 0x65, 0x1, 0x8a, 0xae, 0x14, 0x8a, 0xa6, 0xf0, 0xdd, 0x8a, 0x6a, 0x6a, 0xc, 0x65, 0x51, 0x26, 0x49, 0xc7, 0x31, 0xaf, 0xc1, 0xf6, 0x6e, 0x64, 0xa1, 0xb0, 0x35, 0xd0, 0x14, 0xb1, 0xb5, 0x29, 0xd9, 0xed, 0x2e, 0x39, 0x77, 0x2e, 0x20, 0x3e, 0x9f, 0xaf, 0x35, 0xd6, 0xe7, 0x1b, 0x57, 0x86, 0x1b, 0xb4, 0xbe, 0xbe, 0xcd, 0xf4, 0x93, 0xcb, 0x97, 0x2f, 0x9b, 0xca, 0xab, 0x56, 0xab, 0x32, 0xa6, 0xf5, 0x7, 0x3b, 0xa6, 0x2, 0xba, 0x6, 0x50, 0x16, 0x65, 0x92, 0x8, 0x8c, 0xf8, 0x0, 0x77, 0x9c, 0xa7, 0xdd, 0xab, 0x11, 0x24, 0x14, 0xeb, 0xf5, 0x9a, 0xa5, 0x8d, 0xc8, 0xc8, 0x33, 0x3, 0xfc, 0xfe, 0x43, 0x7, 0xd0, 0x11, 0x91, 0xc8, 0x79, 0x5, 0x5c, 0xda, 0xe9, 0xf1, 0xe3, 0xdf, 0xe5, 0xca, 0x15, 0x73, 0x7, 0x14, 0x8b, 0x45, 0x5, 0x68, 0x4e, 0x8a, 0x28, 0x8b, 0x32, 0x49, 0xba, 0x4d, 0x7c, 0xe9, 0x0, 0x42, 0xed, 0x47, 0x2, 0x3d, 0x43, 0x77, 0x65, 0x71, 0xa9, 0xd8, 0x70, 0x38, 0x9c, 0xe7, 0xac, 0x28, 0xb2, 0xba, 0xfa, 0x50, 0x6e, 0xdc, 0xf8, 0x4, 0x11, 0xce, 0x1, 0xbc, 0x78, 0x55, 0xd, 0x78, 0xf5, 0x2a, 0xd1, 0xb1, 0xef, 0xf9, 0x4e, 0x47, 0x99, 0x51, 0x2a, 0x95, 0x52, 0x68, 0x2e, 0x16, 0xb3, 0xe4, 0x7f, 0x33, 0x71, 0x4a, 0x16, 0x65, 0x92, 0x90, 0x95, 0x44, 0x82, 0xbc, 0x2d, 0x1e, 0x9, 0x84, 0xd4, 0x25, 0x8, 0xd0, 0xd7, 0x87, 0x63, 0x63, 0xc5, 0x74, 0x5, 0x4a, 0xab, 0xd5, 0x65, 0x77, 0xf7, 0x5, 0x40, 0xcb, 0x81, 0x3c, 0x7a, 0xf4, 0x87, 0xbc, 0x7c, 0x19, 0x55, 0xd3, 0x8, 0x63, 0xa3, 0xd1, 0x7d, 0x14, 0xb5, 0xc3, 0x8, 0x6c, 0x6f, 0x6f, 0x22, 0x1a, 0x85, 0xd6, 0x7b, 0x2f, 0xd9, 0xe5, 0x72, 0x51, 0x16, 0x16, 0x16, 0x30, 0x2e, 0x27, 0x4, 0x34, 0xc3, 0x90, 0xdf, 0xef, 0x51, 0x38, 0x60, 0x6b, 0x6b, 0xb, 0xd1, 0x6f, 0xc2, 0x11, 0x89, 0x7b, 0xb8, 0x24, 0x3d, 0x82, 0xcc, 0xa4, 0xee, 0x4, 0x25, 0xbe, 0x17, 0xcc, 0xb5, 0x61, 0x60, 0x11, 0xe, 0x58, 0xb6, 0xdb, 0xed, 0x87, 0x67, 0x88, 0x9, 0x21, 0x63, 0x70, 0x7e, 0x67, 0xa5, 0xd9, 0xfc, 0xf7, 0x6a, 0xc1, 0xed, 0x61, 0x18, 0xcf, 0xe9, 0xfc, 0x5f, 0xfb, 0x7b, 0x2f, 0x91, 0x75, 0xec, 0xd0, 0x11, 0x6c, 0x53, 0x2a, 0x4e, 0x34, 0x47, 0x88, 0x7b, 0x1c, 0xe2, 0x25, 0x2a, 0x12, 0x89, 0x20, 0x13, 0x5f, 0x49, 0x3a, 0x53, 0xe0, 0xed, 0x70, 0x2b, 0x1a, 0x7d, 0xf9, 0x3d, 0x64, 0xed, 0x80, 0x79, 0xcc, 0xb4, 0x4, 0xf7, 0x72, 0x0, 0xb7, 0xc2, 0x8, 0x6e, 0x57, 0x39, 0xdc, 0x7, 0x3e, 0x40, 0x36, 0x9c, 0x5c, 0x55, 0xb2, 0x60, 0x4d, 0x36, 0x5f, 0x56, 0x38, 0x9e, 0x88, 0xb0, 0x54, 0xca, 0x43, 0xf9, 0xc1, 0x32, 0x81, 0x91, 0xa7, 0xf1, 0xb9, 0x5c, 0x4e, 0x9e, 0xed, 0x45, 0xa5, 0x51, 0xaf, 0xd5, 0x62, 0xb1, 0xfd, 0xef, 0x70, 0x17, 0x60, 0xf4, 0x59, 0x9c, 0x58, 0xc, 0xfb, 0x5e, 0x86, 0xa8, 0xa2, 0x6a, 0x2f, 0x61, 0x42, 0x86, 0xc6, 0x6b, 0xda, 0xd8, 0xfb, 0x67, 0x7a, 0x1b, 0xc4, 0x7d, 0x3e, 0x5, 0x3c, 0xe1, 0x74, 0xd8, 0x64, 0x71, 0x71, 0x11, 0x20, 0xcb, 0x81, 0x14, 0xae, 0x48, 0xa5, 0x6a, 0xe8, 0xdc, 0xde, 0x96, 0xc4, 0xdf, 0x88, 0x8f, 0xa6, 0x8d, 0xaa, 0x42, 0x1c, 0xe, 0xcf, 0x2, 0x84, 0xcd, 0xa1, 0x86, 0xc4, 0x64, 0xfb, 0xd9, 0xbe, 0xba, 0xd, 0x22, 0xf5, 0x7f, 0x44, 0x36, 0xfd, 0x2, 0x9b, 0xd8, 0x20, 0xe9, 0x88, 0x3e, 0x8d, 0x35, 0xeb, 0x7, 0x44, 0xd0, 0x8, 0xf9, 0xd2, 0xef, 0xf, 0x7c, 0x81, 0x73, 0xb4, 0x3, 0x43, 0x5b, 0x8, 0xe6, 0xd0, 0x43, 0x86, 0xec, 0x7, 0xd4, 0xd2, 0xe9, 0xc4, 0x3d, 0x34, 0x46, 0x7e, 0x82, 0x22, 0xeb, 0x60, 0x4b, 0xfd, 0x0, 0x43, 0x69, 0xa3, 0x23, 0x44, 0xf4, 0xb4, 0xe8, 0xf1, 0x78, 0x57, 0xd0, 0x1b, 0xb8, 0xed, 0x76, 0x6b, 0x97, 0x86, 0xb6, 0xea, 0xc, 0x4, 0x94, 0x4a, 0xc5, 0xbf, 0xd1, 0x3, 0xb8, 0x93, 0xcf, 0xb7, 0x3a, 0x42, 0x3c, 0x56, 0xc, 0x1c, 0xd0, 0xa1, 0x81, 0x59, 0x4f, 0x90, 0x30, 0x8a, 0xcd, 0x50, 0x42, 0xbb, 0x5, 0xf4, 0x3, 0x97, 0xf4, 0x9e, 0xe0, 0x45, 0x42, 0xcb, 0x37, 0xd1, 0x25, 0xea, 0xe5, 0x3f, 0x82, 0x1c, 0x9e, 0xf3, 0x28, 0xc6, 0xeb, 0x7a, 0x4f, 0x70, 0x15, 0xe3, 0x78, 0xff, 0xe7, 0x9e, 0x67, 0x4f, 0x90, 0x85, 0xa4, 0x67, 0x45, 0x35, 0x6b, 0x68, 0x1a, 0x1d, 0x22, 0x17, 0x4, 0x10, 0xa1, 0x30, 0x23, 0x78, 0x32, 0x74, 0x77, 0x85, 0xcf, 0x20, 0xae, 0x7d, 0x97, 0xa0, 0x61, 0xed, 0x5d, 0x61, 0xa6, 0x3a, 0x23, 0xce, 0xfd, 0x4e, 0x48, 0xda, 0x1, 0x7c, 0xba, 0xa5, 0x98, 0x39, 0x80, 0xe3, 0x8d, 0xaa, 0xc3, 0x13, 0x83, 0x75, 0x80, 0x37, 0x1b, 0x66, 0x86, 0x71, 0xa9, 0xb0, 0x22, 0xe3, 0x34, 0x1d, 0x64, 0xfc, 0x10, 0x62, 0xfc, 0x2e, 0xc0, 0x54, 0x27, 0xd8, 0x31, 0xc, 0xef, 0xdb, 0x12, 0x37, 0x8c, 0x1b, 0x44, 0xb9, 0xae, 0x12, 0x3c, 0xc8, 0xd4, 0x53, 0x1f, 0xdb, 0xfe, 0xab, 0xd0, 0x91, 0x46, 0x9f, 0xba, 0x26, 0x6f, 0x17, 0xf8, 0xf, 0x79, 0xe0, 0x1f, 0xd, 0x80, 0x80, 0xb4, 0xad, 0xe9, 0x2a, 0x4d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char tool_button_pressed_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, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x1, 0xfe, 0x50, 0x4c, 0x54, 0x45, 0x29, 0x3a, 0x40, 0x2d, 0x3e, 0x44, 0x26, 0x34, 0x3b, 0x24, 0x34, 0x39, 0x23, 0x31, 0x38, 0x22, 0x31, 0x37, 0x22, 0x31, 0x37, 0x22, 0x30, 0x36, 0x22, 0x31, 0x36, 0x26, 0x34, 0x3c, 0x32, 0x44, 0x4c, 0x26, 0x34, 0x39, 0x23, 0x31, 0x36, 0x21, 0x2e, 0x34, 0x1f, 0x2c, 0x30, 0x1f, 0x2b, 0x2f, 0x1f, 0x2a, 0x2e, 0x1e, 0x2b, 0x2f, 0x1f, 0x2b, 0x2e, 0x36, 0x4b, 0x52, 0x25, 0x33, 0x38, 0x20, 0x2f, 0x32, 0x1c, 0x29, 0x2e, 0x1b, 0x26, 0x2a, 0x1a, 0x23, 0x26, 0x18, 0x22, 0x26, 0x19, 0x22, 0x26, 0x19, 0x23, 0x26, 0x19, 0x26, 0x29, 0x20, 0x2d, 0x32, 0x25, 0x31, 0x38, 0x3c, 0x51, 0x59, 0x23, 0x31, 0x37, 0x1f, 0x2b, 0x31, 0x1a, 0x25, 0x2b, 0x17, 0x20, 0x24, 0x15, 0x1c, 0x21, 0x14, 0x1b, 0x21, 0x14, 0x1c, 0x21, 0x13, 0x1b, 0x21, 0x15, 0x1d, 0x21, 0x1a, 0x25, 0x2a, 0x40, 0x57, 0x60, 0x23, 0x31, 0x36, 0x1f, 0x2b, 0x31, 0x1b, 0x25, 0x29, 0x16, 0x1e, 0x23, 0x14, 0x1b, 0x1d, 0x12, 0x19, 0x1d, 0x12, 0x1b, 0x1d, 0x14, 0x1a, 0x1d, 0x45, 0x5e, 0x67, 0x22, 0x32, 0x37, 0x20, 0x2d, 0x31, 0x1a, 0x26, 0x2a, 0x15, 0x1f, 0x25, 0x14, 0x1c, 0x1f, 0x12, 0x1b, 0x1f, 0x12, 0x1b, 0x20, 0x14, 0x1b, 0x1f, 0x15, 0x1e, 0x24, 0x1a, 0x25, 0x29, 0x4b, 0x64, 0x6d, 0x23, 0x32, 0x38, 0x20, 0x2e, 0x32, 0x1b, 0x27, 0x2b, 0x17, 0x22, 0x27, 0x16, 0x1e, 0x23, 0x14, 0x1e, 0x23, 0x16, 0x20, 0x24, 0x14, 0x1e, 0x22, 0x15, 0x1e, 0x22, 0x17, 0x21, 0x27, 0x1c, 0x27, 0x2c, 0x4f, 0x6a, 0x75, 0x21, 0x2f, 0x33, 0x1d, 0x29, 0x2d, 0x19, 0x23, 0x2a, 0x18, 0x22, 0x27, 0x16, 0x21, 0x27, 0x18, 0x23, 0x29, 0x17, 0x21, 0x26, 0x19, 0x23, 0x29, 0x1c, 0x28, 0x2d, 0x21, 0x2e, 0x33, 0x54, 0x70, 0x7c, 0x23, 0x33, 0x38, 0x22, 0x30, 0x34, 0x1e, 0x2a, 0x2f, 0x1a, 0x26, 0x2d, 0x1a, 0x25, 0x2b, 0x19, 0x25, 0x2b, 0x1a, 0x26, 0x2d, 0x1a, 0x26, 0x2c, 0x18, 0x25, 0x2a, 0x1a, 0x24, 0x2a, 0x1a, 0x25, 0x2c, 0x1d, 0x2a, 0x2f, 0x22, 0x2f, 0x34, 0x59, 0x77, 0x82, 0x23, 0x33, 0x39, 0x22, 0x30, 0x35, 0x1f, 0x2c, 0x31, 0x1c, 0x28, 0x30, 0x1c, 0x28, 0x2e, 0x1b, 0x29, 0x2f, 0x1c, 0x2a, 0x31, 0x1b, 0x28, 0x2f, 0x1c, 0x28, 0x2d, 0x1b, 0x27, 0x2f, 0x1f, 0x2b, 0x31, 0x5e, 0x7d, 0x8a, 0x24, 0x34, 0x39, 0x21, 0x2f, 0x37, 0x20, 0x2d, 0x34, 0x1d, 0x2b, 0x33, 0x1d, 0x2b, 0x32, 0x1d, 0x2d, 0x35, 0x1e, 0x2e, 0x36, 0x1f, 0x2e, 0x36, 0x1d, 0x2b, 0x34, 0x1d, 0x2b, 0x31, 0x1d, 0x2b, 0x32, 0x20, 0x2d, 0x32, 0x21, 0x2f, 0x36, 0x63, 0x83, 0x90, 0x25, 0x34, 0x39, 0x21, 0x31, 0x36, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x36, 0x20, 0x31, 0x39, 0x21, 0x33, 0x3b, 0x21, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1e, 0x2d, 0x33, 0x1f, 0x2d, 0x33, 0x21, 0x30, 0x36, 0x67, 0x8a, 0x97, 0x24, 0x33, 0x39, 0x20, 0x30, 0x36, 0x1f, 0x2f, 0x35, 0x21, 0x30, 0x37, 0x22, 0x32, 0x39, 0x21, 0x35, 0x3e, 0x24, 0x37, 0x41, 0x24, 0x36, 0x41, 0x21, 0x33, 0x3c, 0x21, 0x31, 0x38, 0x1e, 0x2f, 0x35, 0x1e, 0x2e, 0x35, 0x20, 0x2e, 0x35, 0x24, 0x31, 0x39, 0x6c, 0x90, 0x9e, 0x22, 0x30, 0x36, 0x1f, 0x2e, 0x36, 0x20, 0x30, 0x36, 0x20, 0x31, 0x39, 0x23, 0x34, 0x3d, 0x23, 0x37, 0x41, 0x26, 0x3c, 0x47, 0x26, 0x3b, 0x46, 0x22, 0x35, 0x3f, 0x22, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1f, 0x2d, 0x35, 0x21, 0x30, 0x36, 0x72, 0x96, 0xa5, 0x7e, 0x8c, 0xc3, 0xb0, 0x0, 0x0, 0x0, 0xaa, 0x74, 0x52, 0x4e, 0x53, 0xc3, 0xc3, 0xe6, 0xd7, 0xcb, 0xc3, 0xbf, 0xbe, 0xbd, 0xe5, 0xc3, 0xd7, 0xc0, 0xac, 0xa0, 0x9a, 0x98, 0x98, 0x98, 0xc3, 0xcb, 0xac, 0x92, 0x82, 0x7b, 0x78, 0x78, 0x7b, 0x82, 0xac, 0xcb, 0xc3, 0xc3, 0xa0, 0x82, 0x6f, 0x67, 0x64, 0x63, 0x64, 0x67, 0x82, 0xc3, 0xbf, 0x9a, 0x7a, 0x67, 0x5e, 0x5b, 0x5a, 0x5e, 0xc3, 0xbd, 0x98, 0x78, 0x64, 0x5b, 0x57, 0x57, 0x5b, 0x64, 0x78, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x77, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0xbb, 0x96, 0x76, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x76, 0x96, 0xc3, 0xb5, 0x92, 0x75, 0x62, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x59, 0x62, 0x74, 0x92, 0xc3, 0xa9, 0x8b, 0x71, 0x61, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x61, 0x71, 0x8b, 0xa9, 0xc3, 0x95, 0x7e, 0x6b, 0x5e, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x5e, 0x6b, 0x7e, 0x95, 0xc3, 0x4f, 0x78, 0x99, 0x30, 0x0, 0x0, 0x0, 0x67, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5c, 0x8b, 0x5, 0x2, 0xc3, 0x30, 0xc, 0xc4, 0x72, 0x5d, 0x39, 0xf4, 0xff, 0x67, 0x8e, 0x79, 0x1a, 0x37, 0xa0, 0xa0, 0x6d, 0x5d, 0x6b, 0x2a, 0x5a, 0xfd, 0x30, 0xe6, 0x1, 0xf4, 0xa7, 0x76, 0xfa, 0x37, 0x74, 0x7, 0x98, 0x52, 0x83, 0x46, 0x97, 0x41, 0xfb, 0xd6, 0x2d, 0x86, 0xae, 0xfe, 0x84, 0x6b, 0x6d, 0x32, 0x6e, 0x58, 0x28, 0x22, 0x3a, 0x41, 0x32, 0xde, 0xd7, 0x6a, 0x67, 0x5b, 0xb7, 0xb7, 0xc9, 0xb0, 0xd8, 0xd6, 0x3a, 0x65, 0x34, 0xb4, 0x21, 0x8f, 0x1c, 0x3, 0x6d, 0x21, 0x84, 0x5d, 0x32, 0x8a, 0x48, 0x22, 0x6e, 0xda, 0xa8, 0x92, 0x36, 0x3e, 0x87, 0xea, 0x7b, 0x7e, 0x0, 0x62, 0xa8, 0x25, 0xad, 0x68, 0x1d, 0x7d, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; diff --git a/scene/resources/default_theme/toggle_off_disabled.png b/scene/resources/default_theme/toggle_off_disabled.png Binary files differnew file mode 100644 index 0000000000..d65a9d8e64 --- /dev/null +++ b/scene/resources/default_theme/toggle_off_disabled.png diff --git a/scene/resources/default_theme/toggle_on_disabled.png b/scene/resources/default_theme/toggle_on_disabled.png Binary files differnew file mode 100644 index 0000000000..ca4dbe211f --- /dev/null +++ b/scene/resources/default_theme/toggle_on_disabled.png diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 619165dc2a..8ee9879055 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -281,18 +281,6 @@ const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFon return Pair<const Character *, DynamicFontAtSize *>(chr, const_cast<DynamicFontAtSize *>(this)); } -float DynamicFontAtSize::_get_kerning_advance(const DynamicFontAtSize *font, CharType p_char, CharType p_next) const { - float advance = 0.0; - - if (p_next) { - FT_Vector delta; - FT_Get_Kerning(font->face, p_char, p_next, FT_KERNING_DEFAULT, &delta); - advance = (delta.x / 64.0) / oversampling; - } - - return advance; -} - Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const { if (!valid) @@ -301,7 +289,6 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V Pair<const Character *, DynamicFontAtSize *> char_pair_with_font = _find_char_with_font(p_char, p_fallbacks); const Character *ch = char_pair_with_font.first; - DynamicFontAtSize *font = char_pair_with_font.second; ERR_FAIL_COND_V(!ch, Size2()); Size2 ret(0, get_height()); @@ -309,7 +296,6 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V if (ch->found) { ret.x = ch->advance; } - ret.x += _get_kerning_advance(font, p_char, p_next); return ret; } @@ -358,8 +344,6 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT advance = ch->advance; } - advance += _get_kerning_advance(font, p_char, p_next); - return advance; } @@ -1024,8 +1008,8 @@ void DynamicFont::_bind_methods() { ClassDB::bind_method(D_METHOD("get_fallback_count"), &DynamicFont::get_fallback_count); ADD_GROUP("Settings", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size"), "set_outline_size", "get_outline_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "size", PROPERTY_HINT_RANGE, "1,255,1"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,255,1"), "set_outline_size", "get_outline_size"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_color"), "set_outline_color", "get_outline_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_mipmaps"), "set_use_mipmaps", "get_use_mipmaps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_filter"), "set_use_filter", "get_use_filter"); diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h index 9c41c948bd..d0a709a2d3 100644 --- a/scene/resources/dynamic_font.h +++ b/scene/resources/dynamic_font.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -54,8 +54,9 @@ public: struct { uint32_t size : 16; uint32_t outline_size : 8; - bool mipmaps : 1; - bool filter : 1; + uint32_t mipmaps : 1; + uint32_t filter : 1; + uint32_t unused : 6; }; uint32_t key; }; @@ -109,7 +110,7 @@ VARIANT_ENUM_CAST(DynamicFontData::Hinting); class DynamicFontAtSize : public Reference { - GDCLASS(DynamicFontAtSize, Reference) + GDCLASS(DynamicFontAtSize, Reference); _THREAD_SAFE_CLASS_ @@ -164,7 +165,6 @@ class DynamicFontAtSize : public Reference { const Pair<const Character *, DynamicFontAtSize *> _find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const; Character _make_outline_char(CharType p_char); - float _get_kerning_advance(const DynamicFontAtSize *font, CharType p_char, CharType p_next) const; TexturePosition _find_texture_pos_for_glyph(int p_color_size, Image::Format p_image_format, int p_width, int p_height); Character _bitmap_to_character(FT_Bitmap bitmap, int yofs, int xofs, float advance); @@ -303,7 +303,6 @@ VARIANT_ENUM_CAST(DynamicFont::SpacingType); ///////////// class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader { - GDCLASS(ResourceFormatLoaderDynamicFont, 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; diff --git a/scene/resources/dynamic_font_stb.cpp b/scene/resources/dynamic_font_stb.cpp index 8cb2cc4983..3b44f05b94 100644 --- a/scene/resources/dynamic_font_stb.cpp +++ b/scene/resources/dynamic_font_stb.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/dynamic_font_stb.h b/scene/resources/dynamic_font_stb.h index c83cc1b01f..caee6e7e32 100644 --- a/scene/resources/dynamic_font_stb.h +++ b/scene/resources/dynamic_font_stb.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -180,7 +180,6 @@ public: ///////////// class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader { - GDCLASS(ResourceFormatLoaderDynamicFont, 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; diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 9754ba736e..7c3867beaa 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -111,6 +111,11 @@ void Environment::set_ambient_light_sky_contribution(float p_energy) { VS::get_singleton()->environment_set_ambient_light(environment, ambient_color, ambient_energy, ambient_sky_contribution); } +void Environment::set_camera_feed_id(int p_camera_feed_id) { + camera_feed_id = p_camera_feed_id; + VS::get_singleton()->environment_set_camera_feed_id(environment, camera_feed_id); +}; + Environment::BGMode Environment::get_background() const { return bg_mode; @@ -165,6 +170,10 @@ float Environment::get_ambient_light_sky_contribution() const { return ambient_sky_contribution; } +int Environment::get_camera_feed_id(void) const { + + return camera_feed_id; +} void Environment::set_tonemapper(ToneMapper p_tone_mapper) { @@ -303,7 +312,7 @@ Ref<Texture> Environment::get_adjustment_color_correction() const { void Environment::_validate_property(PropertyInfo &property) const { - if (property.name == "background_sky" || property.name == "background_sky_custom_fov" || property.name == "background_sky_orientation" || property.name == "ambient_light/sky_contribution") { + if (property.name == "background_sky" || property.name == "background_sky_custom_fov" || property.name == "background_sky_orientation" || property.name == "background_sky_rotation" || property.name == "background_sky_rotation_degrees" || property.name == "ambient_light/sky_contribution") { if (bg_mode != BG_SKY && bg_mode != BG_COLOR_SKY) { property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; } @@ -321,6 +330,12 @@ void Environment::_validate_property(PropertyInfo &property) const { } } + if (property.name == "background_camera_feed_id") { + if (bg_mode != BG_CAMERA_FEED) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } + } + static const char *hide_prefixes[] = { "fog_", "auto_exposure_", @@ -334,6 +349,19 @@ void Environment::_validate_property(PropertyInfo &property) const { }; + static const char *high_end_prefixes[] = { + "auto_exposure_", + "tonemap_", + "ss_reflections_", + "ssao_", + "dof_blur_far_", + "dof_blur_near_", + "glow_", + "adjustment_", + NULL + + }; + const char **prefixes = hide_prefixes; while (*prefixes) { String prefix = String(*prefixes); @@ -346,6 +374,20 @@ void Environment::_validate_property(PropertyInfo &property) const { prefixes++; } + + if (VisualServer::get_singleton()->is_low_end()) { + prefixes = high_end_prefixes; + while (*prefixes) { + String prefix = String(*prefixes); + + if (property.name.begins_with(prefix)) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + return; + } + + prefixes++; + } + } } void Environment::set_ssr_enabled(bool p_enable) { @@ -919,6 +961,7 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ambient_light_color", "color"), &Environment::set_ambient_light_color); ClassDB::bind_method(D_METHOD("set_ambient_light_energy", "energy"), &Environment::set_ambient_light_energy); ClassDB::bind_method(D_METHOD("set_ambient_light_sky_contribution", "energy"), &Environment::set_ambient_light_sky_contribution); + ClassDB::bind_method(D_METHOD("set_camera_feed_id", "camera_feed_id"), &Environment::set_camera_feed_id); ClassDB::bind_method(D_METHOD("get_background"), &Environment::get_background); ClassDB::bind_method(D_METHOD("get_sky"), &Environment::get_sky); @@ -932,9 +975,10 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_ambient_light_color"), &Environment::get_ambient_light_color); ClassDB::bind_method(D_METHOD("get_ambient_light_energy"), &Environment::get_ambient_light_energy); ClassDB::bind_method(D_METHOD("get_ambient_light_sky_contribution"), &Environment::get_ambient_light_sky_contribution); + ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &Environment::get_camera_feed_id); ADD_GROUP("Background", "background_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "background_mode", PROPERTY_HINT_ENUM, "Clear Color,Custom Color,Sky,Color+Sky,Canvas,Keep"), "set_background", "get_background"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "background_mode", PROPERTY_HINT_ENUM, "Clear Color,Custom Color,Sky,Color+Sky,Canvas,Keep,Camera Feed"), "set_background", "get_background"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "background_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "background_sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_sky_custom_fov", "get_sky_custom_fov"); ADD_PROPERTY(PropertyInfo(Variant::BASIS, "background_sky_orientation"), "set_sky_orientation", "get_sky_orientation"); @@ -943,6 +987,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_bg_color", "get_bg_color"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "background_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy", "get_bg_energy"); ADD_PROPERTY(PropertyInfo(Variant::INT, "background_canvas_max_layer", PROPERTY_HINT_RANGE, "-1000,1000,1"), "set_canvas_max_layer", "get_canvas_max_layer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "background_camera_feed_id", PROPERTY_HINT_RANGE, "1,10,1"), "set_camera_feed_id", "get_camera_feed_id"); ADD_GROUP("Ambient Light", "ambient_light_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ambient_light_color"), "set_ambient_light_color", "get_ambient_light_color"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ambient_light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_ambient_light_energy", "get_ambient_light_energy"); @@ -1238,6 +1283,7 @@ void Environment::_bind_methods() { BIND_ENUM_CONSTANT(BG_SKY); BIND_ENUM_CONSTANT(BG_COLOR_SKY); BIND_ENUM_CONSTANT(BG_CANVAS); + BIND_ENUM_CONSTANT(BG_CAMERA_FEED); BIND_ENUM_CONSTANT(BG_MAX); BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_ADDITIVE); @@ -1264,7 +1310,14 @@ void Environment::_bind_methods() { BIND_ENUM_CONSTANT(SSAO_QUALITY_HIGH); } -Environment::Environment() { +Environment::Environment() : + bg_mode(BG_CLEAR_COLOR), + tone_mapper(TONE_MAPPER_LINEAR), + ssao_blur(SSAO_BLUR_3x3), + ssao_quality(SSAO_QUALITY_MEDIUM), + glow_blend_mode(GLOW_BLEND_MODE_ADDITIVE), + dof_blur_far_quality(DOF_BLUR_QUALITY_LOW), + dof_blur_near_quality(DOF_BLUR_QUALITY_LOW) { environment = VS::get_singleton()->environment_create(); @@ -1276,6 +1329,7 @@ Environment::Environment() { ambient_energy = 1.0; //ambient_sky_contribution = 1.0; set_ambient_light_sky_contribution(1.0); + set_camera_feed_id(1); tone_mapper = TONE_MAPPER_LINEAR; tonemap_exposure = 1.0; @@ -1312,7 +1366,7 @@ Environment::Environment() { ssao_ao_channel_affect = 0.0; ssao_blur = SSAO_BLUR_3x3; set_ssao_edge_sharpness(4); - set_ssao_quality(SSAO_QUALITY_LOW); + set_ssao_quality(SSAO_QUALITY_MEDIUM); glow_enabled = false; glow_levels = (1 << 2) | (1 << 4); diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 8d6436487b..acce9c09a2 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,7 +32,7 @@ #define ENVIRONMENT_H #include "core/resource.h" -#include "scene/resources/sky_box.h" +#include "scene/resources/sky.h" #include "scene/resources/texture.h" #include "servers/visual_server.h" @@ -49,6 +49,7 @@ public: BG_COLOR_SKY, BG_CANVAS, BG_KEEP, + BG_CAMERA_FEED, BG_MAX }; @@ -98,6 +99,7 @@ private: Color ambient_color; float ambient_energy; float ambient_sky_contribution; + int camera_feed_id; ToneMapper tone_mapper; float tonemap_exposure; @@ -192,6 +194,7 @@ public: void set_ambient_light_color(const Color &p_color); void set_ambient_light_energy(float p_energy); void set_ambient_light_sky_contribution(float p_energy); + void set_camera_feed_id(int p_camera_feed_id); BGMode get_background() const; Ref<Sky> get_sky() const; @@ -205,6 +208,7 @@ public: Color get_ambient_light_color() const; float get_ambient_light_energy() const; float get_ambient_light_sky_contribution() const; + int get_camera_feed_id(void) const; void set_tonemapper(ToneMapper p_tone_mapper); ToneMapper get_tonemapper() const; diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index b78b3a6ffb..627397f0ab 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -96,6 +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("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); @@ -495,8 +496,47 @@ Size2 Font::get_string_size(const String &p_string) const { return Size2(w, get_height()); } + +Size2 Font::get_wordwrap_string_size(const String &p_string, float p_width) const { + + ERR_FAIL_COND_V(p_width <= 0, Vector2(0, get_height())); + + int l = p_string.length(); + if (l == 0) + return Size2(p_width, get_height()); + + float line_w = 0; + float h = 0; + float space_w = get_char_size(' ').width; + Vector<String> lines = p_string.split("\n"); + for (int i = 0; i < lines.size(); i++) { + h += get_height(); + String t = lines[i]; + line_w = 0; + Vector<String> words = t.split(" "); + for (int j = 0; j < words.size(); j++) { + line_w += get_string_size(words[j]).x; + if (line_w > p_width) { + h += get_height(); + line_w = get_string_size(words[j]).x; + } else { + line_w += space_w; + } + } + } + + return Size2(p_width, h); +} + void BitmapFont::set_fallback(const Ref<BitmapFont> &p_fallback) { + for (Ref<BitmapFont> fallback_child = p_fallback; fallback_child != NULL; fallback_child = fallback_child->get_fallback()) { + if (fallback_child == this) { + ERR_EXPLAIN("Can't set as fallback one of its parents to prevent crashes due to recursive loop."); + ERR_FAIL_COND(fallback_child == this); + } + } + fallback = p_fallback; } diff --git a/scene/resources/font.h b/scene/resources/font.h index 3c5e650758..436ed43c42 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -53,6 +53,7 @@ public: virtual Size2 get_char_size(CharType p_char, CharType p_next = 0) const = 0; Size2 get_string_size(const String &p_string) const; + Size2 get_wordwrap_string_size(const String &p_string, float p_width) const; virtual bool is_distance_field_hint() const = 0; @@ -201,7 +202,6 @@ public: }; class ResourceFormatLoaderBMFont : public ResourceFormatLoader { - GDCLASS(ResourceFormatLoaderBMFont, 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; diff --git a/scene/resources/color_ramp.cpp b/scene/resources/gradient.cpp index d5e8c17cbc..99ce8ef821 100644 --- a/scene/resources/color_ramp.cpp +++ b/scene/resources/gradient.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* color_ramp.cpp */ +/* gradient.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,7 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "color_ramp.h" +#include "gradient.h" + #include "core/core_string_names.h" //setter and getter names for property serialization diff --git a/scene/resources/color_ramp.h b/scene/resources/gradient.h index 88fa4beb7f..7e7fc99a5d 100644 --- a/scene/resources/color_ramp.h +++ b/scene/resources/gradient.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* color_ramp.h */ +/* gradient.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SCENE_RESOURCES_COLOR_RAMP_H_ -#define SCENE_RESOURCES_COLOR_RAMP_H_ +#ifndef GRADIENT_H +#define GRADIENT_H #include "core/resource.h" @@ -91,7 +91,7 @@ public: int high = points.size() - 1; int middle = 0; -#if DEBUG_ENABLED +#ifdef DEBUG_ENABLED if (low > high) ERR_PRINT("low > high, this may be a bug"); #endif @@ -126,4 +126,4 @@ public: int get_points_count() const; }; -#endif /* SCENE_RESOURCES_COLOR_RAMP_H_ */ +#endif // GRADIENT_H diff --git a/scene/resources/height_map_shape.cpp b/scene/resources/height_map_shape.cpp new file mode 100644 index 0000000000..f763700d52 --- /dev/null +++ b/scene/resources/height_map_shape.cpp @@ -0,0 +1,205 @@ +/*************************************************************************/ +/* height_map_shape.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 "height_map_shape.h" +#include "servers/physics_server.h" + +Vector<Vector3> HeightMapShape::_gen_debug_mesh_lines() { + Vector<Vector3> points; + + if ((map_width != 0) && (map_depth != 0)) { + + // This will be slow for large maps... + // also we'll have to figure out how well bullet centers this shape... + + Vector2 size(map_width - 1, map_depth - 1); + Vector2 start = size * -0.5; + + PoolRealArray::Read r = map_data.read(); + + // reserve some memory for our points.. + points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2)); + + // now set our points + int r_offset = 0; + int w_offset = 0; + for (int d = 0; d < map_depth; d++) { + Vector3 height(start.x, 0.0, start.y); + + for (int w = 0; w < map_width; w++) { + height.y = r[r_offset++]; + + if (w != map_width - 1) { + points.write[w_offset++] = height; + points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z); + } + + if (d != map_depth - 1) { + points.write[w_offset++] = height; + points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0); + } + + height.x += 1.0; + } + + start.y += 1.0; + } + } + + return points; +} + +void HeightMapShape::_update_shape() { + + Dictionary d; + d["width"] = map_width; + d["depth"] = map_depth; + d["heights"] = map_data; + d["min_height"] = min_height; + d["max_height"] = max_height; + PhysicsServer::get_singleton()->shape_set_data(get_shape(), d); + Shape::_update_shape(); +} + +void HeightMapShape::set_map_width(int p_new) { + if (p_new < 1) { + // ignore + } else if (map_width != p_new) { + int was_size = map_width * map_depth; + map_width = p_new; + + int new_size = map_width * map_depth; + map_data.resize(map_width * map_depth); + + PoolRealArray::Write w = map_data.write(); + while (was_size < new_size) { + w[was_size++] = 0.0; + } + + _update_shape(); + notify_change_to_owners(); + _change_notify("map_width"); + _change_notify("map_data"); + } +} + +int HeightMapShape::get_map_width() const { + return map_width; +} + +void HeightMapShape::set_map_depth(int p_new) { + if (p_new < 1) { + // ignore + } else if (map_depth != p_new) { + int was_size = map_width * map_depth; + map_depth = p_new; + + int new_size = map_width * map_depth; + map_data.resize(new_size); + + PoolRealArray::Write w = map_data.write(); + while (was_size < new_size) { + w[was_size++] = 0.0; + } + + _update_shape(); + notify_change_to_owners(); + _change_notify("map_depth"); + _change_notify("map_data"); + } +} + +int HeightMapShape::get_map_depth() const { + return map_depth; +} + +void HeightMapShape::set_map_data(PoolRealArray p_new) { + int size = (map_width * map_depth); + if (p_new.size() != size) { + // fail + return; + } + + // copy + PoolRealArray::Write w = map_data.write(); + PoolRealArray::Read r = p_new.read(); + for (int i = 0; i < size; i++) { + float val = r[i]; + w[i] = val; + if (i == 0) { + min_height = val; + max_height = val; + } else { + if (min_height > val) + min_height = val; + + if (max_height < val) + max_height = val; + } + } + + _update_shape(); + notify_change_to_owners(); + _change_notify("map_data"); +} + +PoolRealArray HeightMapShape::get_map_data() const { + return map_data; +} + +void HeightMapShape::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape::set_map_width); + ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape::get_map_width); + ClassDB::bind_method(D_METHOD("set_map_depth", "height"), &HeightMapShape::set_map_depth); + ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape::get_map_depth); + ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape::set_map_data); + ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape::get_map_data); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "1,4096,1"), "set_map_width", "get_map_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "1,4096,1"), "set_map_depth", "get_map_depth"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_REAL_ARRAY, "map_data"), "set_map_data", "get_map_data"); +} + +HeightMapShape::HeightMapShape() : + Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_HEIGHTMAP)) { + + map_width = 2; + map_depth = 2; + map_data.resize(map_width * map_depth); + PoolRealArray::Write w = map_data.write(); + w[0] = 0.0; + w[1] = 0.0; + w[2] = 0.0; + w[3] = 0.0; + min_height = 0.0; + max_height = 0.0; + + _update_shape(); +} diff --git a/scene/resources/bounds.h b/scene/resources/height_map_shape.h index c86e15ae40..b062f4e893 100644 --- a/scene/resources/bounds.h +++ b/scene/resources/height_map_shape.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* bounds.h */ +/* height_map_shape.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,25 +28,35 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BOUNDS_H -#define BOUNDS_H +#ifndef HEIGHT_MAP_SHAPE_H +#define HEIGHT_MAP_SHAPE_H -#include "core/math/bsp_tree.h" -#include "core/resource.h" +#include "scene/resources/shape.h" -class Bounds : public Resource { +class HeightMapShape : public Shape { + GDCLASS(HeightMapShape, Shape); - GDCLASS(Bounds, Resource); - BSP_Tree bsp_tree; + int map_width; + int map_depth; + PoolRealArray map_data; + float min_height; + float max_height; protected: static void _bind_methods(); + virtual void _update_shape(); -public: - void set_bsp_tree(const BSP_Tree &p_bsp_tree); - BSP_Tree get_bsp_tree() const; + virtual Vector<Vector3> _gen_debug_mesh_lines(); - Bounds(); +public: + void set_map_width(int p_new); + int get_map_width() const; + void set_map_depth(int p_new); + int get_map_depth() const; + void set_map_data(PoolRealArray p_new); + PoolRealArray get_map_data() const; + + HeightMapShape(); }; -#endif // BOUNDS_H +#endif /* !HEIGHT_MAP_SHAPE_H */ diff --git a/scene/resources/shape_line_2d.cpp b/scene/resources/line_shape_2d.cpp index 1a81eea6e5..f5d5fb561a 100644 --- a/scene/resources/shape_line_2d.cpp +++ b/scene/resources/line_shape_2d.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* shape_line_2d.cpp */ +/* line_shape_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,7 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "shape_line_2d.h" +#include "line_shape_2d.h" + #include "servers/physics_2d_server.h" #include "servers/visual_server.h" diff --git a/scene/resources/shape_line_2d.h b/scene/resources/line_shape_2d.h index 7d31941558..f684862025 100644 --- a/scene/resources/shape_line_2d.h +++ b/scene/resources/line_shape_2d.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* shape_line_2d.h */ +/* line_shape_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SHAPE_LINE_2D_H -#define SHAPE_LINE_2D_H +#ifndef LINE_SHAPE_2D_H +#define LINE_SHAPE_2D_H #include "scene/resources/shape_2d.h" @@ -59,4 +59,4 @@ public: LineShape2D(); }; -#endif // SHAPE_LINE_2D_H +#endif // LINE_SHAPE_2D_H diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index f6dc60900f..197ff14b38 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -30,11 +30,20 @@ #include "material.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif + #include "scene/scene_string_names.h" void Material::set_next_pass(const Ref<Material> &p_pass) { - ERR_FAIL_COND(p_pass == this); + for (Ref<Material> pass_child = p_pass; pass_child != NULL; pass_child = pass_child->get_next_pass()) { + if (pass_child == this) { + ERR_EXPLAIN("Can't set as next_pass one of its parents to prevent crashes due to recursive loop."); + ERR_FAIL_COND(pass_child == this); + } + } if (next_pass == p_pass) return; @@ -113,6 +122,9 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { if (n.find("param/") == 0) { //backwards compatibility pr = n.substr(6, n.length()); } + if (n.find("shader_param/") == 0) { //backwards compatibility + pr = n.replace_first("shader_param/", ""); + } } if (pr) { VisualServer::get_singleton()->material_set_param(_get_material(), pr, p_value); @@ -128,6 +140,16 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const { if (shader.is_valid()) { StringName pr = shader->remap_param(p_name); + if (!pr) { + String n = p_name; + if (n.find("param/") == 0) { //backwards compatibility + pr = n.substr(6, n.length()); + } + if (n.find("shader_param/") == 0) { //backwards compatibility + pr = n.replace_first("shader_param/", ""); + } + } + if (pr) { r_ret = VisualServer::get_singleton()->material_get_param(_get_material(), pr); return true; @@ -223,6 +245,12 @@ void ShaderMaterial::_bind_methods() { void ShaderMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { +#ifdef TOOLS_ENABLED + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\""; +#else + const String quote_style = "\""; +#endif + String f = p_function.operator String(); if ((f == "get_shader_param" || f == "set_shader_param") && p_idx == 0) { @@ -230,7 +258,7 @@ void ShaderMaterial::get_argument_options(const StringName &p_function, int p_id List<PropertyInfo> pl; shader->get_param_list(&pl); for (List<PropertyInfo>::Element *E = pl.front(); E; E = E->next()) { - r_options->push_back("\"" + E->get().name.replace_first("shader_param/", "") + "\""); + r_options->push_back(quote_style + E->get().name.replace_first("shader_param/", "") + quote_style); } } } @@ -445,6 +473,9 @@ void SpatialMaterial::_update_shader() { if (flags[FLAG_ENSURE_CORRECT_NORMALS]) { code += ",ensure_correct_normals"; } + if (flags[FLAG_USE_SHADOW_TO_OPACITY]) { + code += ",shadow_to_opacity"; + } code += ";\n"; code += "uniform vec4 albedo : hint_color;\n"; @@ -594,17 +625,17 @@ void SpatialMaterial::_update_shader() { code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);\n"; if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz),0,0,0),vec4(0,length(WORLD_MATRIX[1].xyz),0,0),vec4(0,0,length(WORLD_MATRIX[2].xyz),0),vec4(0,0,0,1));\n"; + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n"; } } break; case BILLBOARD_FIXED_Y: { - code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)),0.0),WORLD_MATRIX[3]);\n"; + code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)), 0.0),WORLD_MATRIX[3]);\n"; if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz),0,0,0),vec4(0,1,0,0),vec4(0,0,length(WORLD_MATRIX[2].xyz),0),vec4(0,0,0,1));\n"; + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, 1.0, 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } else { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1,0,0,0),vec4(0,1.0/length(WORLD_MATRIX[1].xyz),0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n"; + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1.0, 0.0, 0.0, 0.0),vec4(0.0, 1.0/length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0 ,1.0));\n"; } } break; case BILLBOARD_PARTICLES: { @@ -612,16 +643,22 @@ void SpatialMaterial::_update_shader() { //make billboard code += "\tmat4 mat_world = mat4(normalize(CAMERA_MATRIX[0])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[1])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[2])*length(WORLD_MATRIX[2]),WORLD_MATRIX[3]);\n"; //rotate by rotation - code += "\tmat_world = mat_world * mat4( vec4(cos(INSTANCE_CUSTOM.x),-sin(INSTANCE_CUSTOM.x),0.0,0.0), vec4(sin(INSTANCE_CUSTOM.x),cos(INSTANCE_CUSTOM.x),0.0,0.0),vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0));\n"; + code += "\tmat_world = mat_world * mat4( vec4(cos(INSTANCE_CUSTOM.x),-sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0),vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n"; //set modelview code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat_world;\n"; //handle animation + code += "\tfloat h_frames = float(particles_anim_h_frames);\n"; + code += "\tfloat v_frames = float(particles_anim_v_frames);\n"; code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n"; code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n"; - code += "\tif (!particles_anim_loop) particle_frame=clamp(particle_frame,0.0,particle_total_frames-1.0); else particle_frame=mod(particle_frame,float(particle_total_frames));\n"; - code += "\tUV /= vec2(float(particles_anim_h_frames),float(particles_anim_v_frames));\n"; - code += "\tUV += vec2(mod(particle_frame,float(particles_anim_h_frames)) / float(particles_anim_h_frames), floor(particle_frame / float(particles_anim_h_frames)) / float(particles_anim_v_frames));\n"; + code += "\tif (!particles_anim_loop) {\n"; + code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n"; + code += "\t} else {\n"; + code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n"; + code += "\t}"; + code += "\tUV /= vec2(h_frames, v_frames);\n"; + code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n"; } break; } @@ -702,7 +739,7 @@ void SpatialMaterial::_update_shader() { code += "\tvec2 base_uv2 = UV2;\n"; } - if (features[FEATURE_DEPTH_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //depthmap not supported with triplanar + if (!VisualServer::get_singleton()->is_low_end() && features[FEATURE_DEPTH_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //depthmap not supported with triplanar code += "\t{\n"; code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT*depth_flip.x,-BINORMAL*depth_flip.y,NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-) @@ -820,11 +857,11 @@ void SpatialMaterial::_update_shader() { code += "\tALBEDO *= 1.0 - ref_amount;\n"; code += "\tALPHA = 1.0;\n"; - } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { + } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { code += "\tALPHA = albedo.a * albedo_tex.a;\n"; } - if (!VisualServer::get_singleton()->is_low_end() && proximity_fade_enabled) { + if (proximity_fade_enabled) { code += "\tfloat depth_tex = textureLod(DEPTH_TEXTURE,SCREEN_UV,0.0).r;\n"; code += "\tvec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex*2.0-1.0,1.0);\n"; code += "\tworld_pos.xyz/=world_pos.w;\n"; @@ -1320,7 +1357,7 @@ void SpatialMaterial::set_flag(Flags p_flag, bool p_enabled) { return; flags[p_flag] = p_enabled; - if (p_flag == FLAG_USE_ALPHA_SCISSOR || p_flag == FLAG_UNSHADED) { + if ((p_flag == FLAG_USE_ALPHA_SCISSOR) || (p_flag == FLAG_UNSHADED) || (p_flag == FLAG_USE_SHADOW_TO_OPACITY)) { _change_notify(); } _queue_shader_change(); @@ -2031,6 +2068,7 @@ void SpatialMaterial::_bind_methods() { ADD_GROUP("Flags", "flags_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_transparent"), "set_feature", "get_feature", FEATURE_TRANSPARENT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_use_shadow_to_opacity"), "set_flag", "get_flag", FLAG_USE_SHADOW_TO_OPACITY); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_unshaded"), "set_flag", "get_flag", FLAG_UNSHADED); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_vertex_lighting"), "set_flag", "get_flag", FLAG_USE_VERTEX_LIGHTING); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST); @@ -2056,7 +2094,7 @@ void SpatialMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "params_billboard_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard,Particle Billboard"), "set_billboard_mode", "get_billboard_mode"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "params_billboard_keep_scale"), "set_flag", "get_flag", FLAG_BILLBOARD_KEEP_SCALE); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "params_grow"), "set_grow_enabled", "is_grow_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_grow_amount", PROPERTY_HINT_RANGE, "-16,10,0.01"), "set_grow", "get_grow"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_grow_amount", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_grow", "get_grow"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "params_use_alpha_scissor"), "set_flag", "get_flag", FLAG_USE_ALPHA_SCISSOR); ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold"); ADD_GROUP("Particles Anim", "particles_anim_"); @@ -2082,7 +2120,7 @@ void SpatialMaterial::_bind_methods() { ADD_GROUP("Emission", "emission_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_enabled"), "set_feature", "get_feature", FEATURE_EMISSION); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_emission_energy", "get_emission_energy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy", "get_emission_energy"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_operator", PROPERTY_HINT_ENUM, "Add,Multiply"), "set_emission_operator", "get_emission_operator"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_on_uv2"), "set_flag", "get_flag", FLAG_EMISSION_ON_UV2); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_EMISSION); @@ -2164,11 +2202,11 @@ void SpatialMaterial::_bind_methods() { ADD_GROUP("Proximity Fade", "proximity_fade_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_proximity_fade_distance", "get_proximity_fade_distance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_proximity_fade_distance", "get_proximity_fade_distance"); ADD_GROUP("Distance Fade", "distance_fade_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "distance_fade_mode", PROPERTY_HINT_ENUM, "Disabled,PixelAlpha,PixelDither,ObjectDither"), "set_distance_fade", "get_distance_fade"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_distance_fade_min_distance", "get_distance_fade_min_distance"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_distance_fade_max_distance", "get_distance_fade_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_distance_fade_min_distance", "get_distance_fade_min_distance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_distance_fade_max_distance", "get_distance_fade_max_distance"); BIND_ENUM_CONSTANT(TEXTURE_ALBEDO); BIND_ENUM_CONSTANT(TEXTURE_METALLIC); @@ -2237,6 +2275,7 @@ void SpatialMaterial::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_DONT_RECEIVE_SHADOWS); BIND_ENUM_CONSTANT(FLAG_DISABLE_AMBIENT_LIGHT); BIND_ENUM_CONSTANT(FLAG_ENSURE_CORRECT_NORMALS); + BIND_ENUM_CONSTANT(FLAG_USE_SHADOW_TO_OPACITY); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(DIFFUSE_BURLEY); @@ -2314,8 +2353,8 @@ SpatialMaterial::SpatialMaterial() : set_ao_light_affect(0.0); - set_metallic_texture_channel(TEXTURE_CHANNEL_RED); - set_roughness_texture_channel(TEXTURE_CHANNEL_RED); + set_metallic_texture_channel(TEXTURE_CHANNEL_BLUE); + set_roughness_texture_channel(TEXTURE_CHANNEL_GREEN); set_ao_texture_channel(TEXTURE_CHANNEL_RED); set_refraction_texture_channel(TEXTURE_CHANNEL_RED); diff --git a/scene/resources/material.h b/scene/resources/material.h index 921f3baeaa..17e52527b3 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -43,7 +43,7 @@ class Material : public Resource { - GDCLASS(Material, Resource) + GDCLASS(Material, Resource); RES_BASE_EXTENSION("material") OBJ_SAVE_TYPE(Material) @@ -111,7 +111,7 @@ public: class SpatialMaterial : public Material { - GDCLASS(SpatialMaterial, Material) + GDCLASS(SpatialMaterial, Material); public: enum TextureParam { @@ -196,6 +196,7 @@ public: FLAG_DONT_RECEIVE_SHADOWS, FLAG_ENSURE_CORRECT_NORMALS, FLAG_DISABLE_AMBIENT_LIGHT, + FLAG_USE_SHADOW_TO_OPACITY, FLAG_MAX }; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 80191367ce..6443b44bb6 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,6 +37,8 @@ #include <stdlib.h> +Mesh::ConvexDecompositionFunc Mesh::convex_composition_function = NULL; + Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) @@ -84,15 +86,15 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { PoolVector<int> indices = a[ARRAY_INDEX]; PoolVector<int>::Read ir = indices.read(); - for (int i = 0; i < ic; i++) { - int index = ir[i]; + for (int j = 0; j < ic; j++) { + int index = ir[j]; facesw[widx++] = vr[index]; } } else { - for (int i = 0; i < vc; i++) - facesw[widx++] = vr[i]; + for (int j = 0; j < vc; j++) + facesw[widx++] = vr[j]; } } @@ -487,6 +489,7 @@ void Mesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count); ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays); ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &Mesh::surface_get_blend_shape_arrays); + ClassDB::bind_method(D_METHOD("surface_set_material", "surf_idx", "material"), &Mesh::surface_set_material); ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &Mesh::surface_get_material); BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); @@ -543,6 +546,49 @@ void Mesh::clear_cache() const { debug_lines.clear(); } +Vector<Ref<Shape> > Mesh::convex_decompose() const { + + ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape> >()); + + PoolVector<Face3> faces = get_faces(); + Vector<Face3> f3; + f3.resize(faces.size()); + PoolVector<Face3>::Read f = faces.read(); + for (int i = 0; i < f3.size(); i++) { + f3.write[i] = f[i]; + } + + Vector<Vector<Face3> > decomposed = convex_composition_function(f3); + + Vector<Ref<Shape> > ret; + + for (int i = 0; i < decomposed.size(); i++) { + Set<Vector3> points; + for (int j = 0; j < decomposed[i].size(); j++) { + points.insert(decomposed[i][j].vertex[0]); + points.insert(decomposed[i][j].vertex[1]); + points.insert(decomposed[i][j].vertex[2]); + } + + PoolVector<Vector3> convex_points; + convex_points.resize(points.size()); + { + PoolVector<Vector3>::Write w = convex_points.write(); + int idx = 0; + for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) { + w[idx++] = E->get(); + } + } + + Ref<ConvexPolygonShape> shape; + shape.instance(); + shape->set_points(convex_points); + ret.push_back(shape); + } + + return ret; +} + Mesh::Mesh() { } @@ -787,7 +833,6 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & Surface s; VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_flags); - surfaces.push_back(s); /* make aABB? */ { @@ -808,8 +853,9 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & aabb.expand_to(vtx[i]); } - surfaces.write[surfaces.size() - 1].aabb = aabb; - surfaces.write[surfaces.size() - 1].is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; + s.aabb = aabb; + s.is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; + surfaces.push_back(s); _recompute_aabb(); } @@ -1028,34 +1074,6 @@ AABB ArrayMesh::get_custom_aabb() const { return custom_aabb; } -void ArrayMesh::center_geometry() { - - /* - Vector3 ofs = aabb.pos+aabb.size*0.5; - - for(int i=0;i<get_surface_count();i++) { - - PoolVector<Vector3> geom = surface_get_array(i,ARRAY_VERTEX); - int gc =geom.size(); - PoolVector<Vector3>::Write w = geom.write(); - surfaces[i].aabb.pos-=ofs; - - for(int i=0;i<gc;i++) { - - w[i]-=ofs; - } - - w = PoolVector<Vector3>::Write(); - - surface_set_array(i,ARRAY_VERTEX,geom); - - } - - aabb.pos-=ofs; - -*/ -} - void ArrayMesh::regen_normalmaps() { Vector<Ref<SurfaceTool> > surfs; @@ -1288,15 +1306,12 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("surface_get_array_index_len", "surf_idx"), &ArrayMesh::surface_get_array_index_len); ClassDB::bind_method(D_METHOD("surface_get_format", "surf_idx"), &ArrayMesh::surface_get_format); ClassDB::bind_method(D_METHOD("surface_get_primitive_type", "surf_idx"), &ArrayMesh::surface_get_primitive_type); - ClassDB::bind_method(D_METHOD("surface_set_material", "surf_idx", "material"), &ArrayMesh::surface_set_material); ClassDB::bind_method(D_METHOD("surface_find_by_name", "name"), &ArrayMesh::surface_find_by_name); ClassDB::bind_method(D_METHOD("surface_set_name", "surf_idx", "name"), &ArrayMesh::surface_set_name); ClassDB::bind_method(D_METHOD("surface_get_name", "surf_idx"), &ArrayMesh::surface_get_name); ClassDB::bind_method(D_METHOD("create_trimesh_shape"), &ArrayMesh::create_trimesh_shape); ClassDB::bind_method(D_METHOD("create_convex_shape"), &ArrayMesh::create_convex_shape); ClassDB::bind_method(D_METHOD("create_outline", "margin"), &ArrayMesh::create_outline); - ClassDB::bind_method(D_METHOD("center_geometry"), &ArrayMesh::center_geometry); - ClassDB::set_method_flags(get_class_static(), _scs_create("center_geometry"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("regen_normalmaps"), &ArrayMesh::regen_normalmaps); ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normalmaps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("lightmap_unwrap", "transform", "texel_size"), &ArrayMesh::lightmap_unwrap); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index aebba09ef8..b38791b9a6 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -31,6 +31,7 @@ #ifndef MESH_H #define MESH_H +#include "core/math/face3.h" #include "core/math/triangle_mesh.h" #include "core/resource.h" #include "scene/resources/material.h" @@ -127,6 +128,7 @@ public: virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0; virtual uint32_t surface_get_format(int p_idx) const = 0; virtual PrimitiveType surface_get_primitive_type(int p_idx) const = 0; + virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) = 0; virtual Ref<Material> surface_get_material(int p_idx) const = 0; virtual int get_blend_shape_count() const = 0; virtual StringName get_blend_shape_name(int p_index) const = 0; @@ -147,6 +149,12 @@ public: Size2 get_lightmap_size_hint() const; void clear_cache() const; + typedef Vector<Vector<Face3> > (*ConvexDecompositionFunc)(const Vector<Face3> &); + + static ConvexDecompositionFunc convex_composition_function; + + Vector<Ref<Shape> > convex_decompose() const; + Mesh(); }; @@ -208,8 +216,8 @@ public: PrimitiveType surface_get_primitive_type(int p_idx) const; bool surface_is_alpha_sorting_enabled(int p_idx) const; - void surface_set_material(int p_idx, const Ref<Material> &p_material); - Ref<Material> surface_get_material(int p_idx) const; + virtual void surface_set_material(int p_idx, const Ref<Material> &p_material); + virtual Ref<Material> surface_get_material(int p_idx) const; int surface_find_by_name(const String &p_name) const; void surface_set_name(int p_idx, const String &p_name); @@ -223,7 +231,6 @@ public: AABB get_aabb() const; virtual RID get_rid() const; - void center_geometry(); void regen_normalmaps(); Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index 7af9086ab7..7cd765fb5d 100644 --- a/scene/resources/mesh_data_tool.cpp +++ b/scene/resources/mesh_data_tool.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h index f614b80c3b..8f5def72c7 100644 --- a/scene/resources/mesh_data_tool.h +++ b/scene/resources/mesh_data_tool.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index a1d3e0ba1e..d40a5dee2e 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -56,6 +56,8 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) { set_item_preview(idx, p_value); else if (what == "navmesh") set_item_navmesh(idx, p_value); + else if (what == "navmesh_transform") + set_item_navmesh_transform(idx, p_value); else return false; @@ -80,6 +82,8 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const { r_ret = _get_item_shapes(idx); else if (what == "navmesh") r_ret = get_item_navmesh(idx); + else if (what == "navmesh_transform") + r_ret = get_item_navmesh_transform(idx); else if (what == "preview") r_ret = get_item_preview(idx); else @@ -95,8 +99,10 @@ void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const { String name = "item/" + itos(E->key()) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, name + "name")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM, name + "mesh_transform")); p_list->push_back(PropertyInfo(Variant::ARRAY, name + "shapes")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM, name + "navmesh_transform")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "preview", PROPERTY_HINT_RESOURCE_TYPE, "Texture", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_HELPER)); } } @@ -116,6 +122,7 @@ void MeshLibrary::set_item_name(int p_item, const String &p_name) { emit_changed(); _change_notify(); } + void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { ERR_FAIL_COND(!item_map.has(p_item)); @@ -145,6 +152,15 @@ void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navm _change_notify(); } +void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) { + + ERR_FAIL_COND(!item_map.has(p_item)); + item_map[p_item].navmesh_transform = p_transform; + notify_change_to_owners(); + emit_changed(); + _change_notify(); +} + void MeshLibrary::set_item_preview(int p_item, const Ref<Texture> &p_preview) { ERR_FAIL_COND(!item_map.has(p_item)); @@ -152,11 +168,13 @@ void MeshLibrary::set_item_preview(int p_item, const Ref<Texture> &p_preview) { emit_changed(); _change_notify(); } + String MeshLibrary::get_item_name(int p_item) const { ERR_FAIL_COND_V(!item_map.has(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>()); @@ -175,6 +193,12 @@ Ref<NavigationMesh> MeshLibrary::get_item_navmesh(int p_item) const { 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()); + 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>()); @@ -268,11 +292,13 @@ void MeshLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name); ClassDB::bind_method(D_METHOD("set_item_mesh", "id", "mesh"), &MeshLibrary::set_item_mesh); ClassDB::bind_method(D_METHOD("set_item_navmesh", "id", "navmesh"), &MeshLibrary::set_item_navmesh); + ClassDB::bind_method(D_METHOD("set_item_navmesh_transform", "id", "navmesh"), &MeshLibrary::set_item_navmesh_transform); ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes); ClassDB::bind_method(D_METHOD("set_item_preview", "id", "texture"), &MeshLibrary::set_item_preview); ClassDB::bind_method(D_METHOD("get_item_name", "id"), &MeshLibrary::get_item_name); ClassDB::bind_method(D_METHOD("get_item_mesh", "id"), &MeshLibrary::get_item_mesh); ClassDB::bind_method(D_METHOD("get_item_navmesh", "id"), &MeshLibrary::get_item_navmesh); + ClassDB::bind_method(D_METHOD("get_item_navmesh_transform", "id"), &MeshLibrary::get_item_navmesh_transform); ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes); ClassDB::bind_method(D_METHOD("get_item_preview", "id"), &MeshLibrary::get_item_preview); ClassDB::bind_method(D_METHOD("remove_item", "id"), &MeshLibrary::remove_item); diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index 3ce0cf9b66..4ae4fc6483 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -52,6 +52,7 @@ public: Ref<Mesh> mesh; Vector<ShapeData> shapes; Ref<Texture> preview; + Transform navmesh_transform; Ref<NavigationMesh> navmesh; }; @@ -72,11 +73,13 @@ public: void set_item_name(int p_item, const String &p_name); void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh); void set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh); + void set_item_navmesh_transform(int p_item, const Transform &p_transform); void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes); void set_item_preview(int p_item, const Ref<Texture> &p_preview); String get_item_name(int p_item) const; Ref<Mesh> get_item_mesh(int p_item) const; Ref<NavigationMesh> get_item_navmesh(int p_item) const; + Transform get_item_navmesh_transform(int p_item) const; Vector<ShapeData> get_item_shapes(int p_item) const; Ref<Texture> get_item_preview(int p_item) const; diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index e8e19fdb60..5d8adc0c8d 100644 --- a/scene/resources/multimesh.cpp +++ b/scene/resources/multimesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,6 +32,8 @@ #include "servers/visual_server.h" void MultiMesh::_set_transform_array(const PoolVector<Vector3> &p_array) { + if (transform_format != TRANSFORM_3D) + return; PoolVector<Vector3> xforms = p_array; int len = xforms.size(); @@ -55,6 +57,9 @@ void MultiMesh::_set_transform_array(const PoolVector<Vector3> &p_array) { PoolVector<Vector3> MultiMesh::_get_transform_array() const { + if (transform_format != TRANSFORM_3D) + return PoolVector<Vector3>(); + if (instance_count == 0) return PoolVector<Vector3>(); @@ -75,6 +80,54 @@ PoolVector<Vector3> MultiMesh::_get_transform_array() const { return xforms; } +void MultiMesh::_set_transform_2d_array(const PoolVector<Vector2> &p_array) { + + if (transform_format != TRANSFORM_2D) + return; + + PoolVector<Vector2> xforms = p_array; + int len = xforms.size(); + ERR_FAIL_COND((len / 3) != instance_count); + if (len == 0) + return; + + PoolVector<Vector2>::Read r = xforms.read(); + + for (int i = 0; i < len / 3; i++) { + + Transform2D t; + t.elements[0] = r[i * 3 + 0]; + t.elements[1] = r[i * 3 + 1]; + t.elements[2] = r[i * 3 + 2]; + + set_instance_transform_2d(i, t); + } +} + +PoolVector<Vector2> MultiMesh::_get_transform_2d_array() const { + + if (transform_format != TRANSFORM_2D) + return PoolVector<Vector2>(); + + if (instance_count == 0) + return PoolVector<Vector2>(); + + PoolVector<Vector2> xforms; + xforms.resize(instance_count * 3); + + PoolVector<Vector2>::Write w = xforms.write(); + + for (int i = 0; i < instance_count; i++) { + + Transform2D t = get_instance_transform_2d(i); + w[i * 3 + 0] = t.elements[0]; + w[i * 3 + 1] = t.elements[1]; + w[i * 3 + 2] = t.elements[2]; + } + + return xforms; +} + void MultiMesh::_set_color_array(const PoolVector<Color> &p_array) { PoolVector<Color> colors = p_array; @@ -162,15 +215,36 @@ int MultiMesh::get_instance_count() const { return instance_count; } +void MultiMesh::set_visible_instance_count(int p_count) { + ERR_FAIL_COND(p_count < -1); + VisualServer::get_singleton()->multimesh_set_visible_instances(multimesh, p_count); + visible_instance_count = p_count; +} +int MultiMesh::get_visible_instance_count() const { + + return visible_instance_count; +} + void MultiMesh::set_instance_transform(int p_instance, const Transform &p_transform) { VisualServer::get_singleton()->multimesh_instance_set_transform(multimesh, p_instance, p_transform); } + +void MultiMesh::set_instance_transform_2d(int p_instance, const Transform2D &p_transform) { + + VisualServer::get_singleton()->multimesh_instance_set_transform_2d(multimesh, p_instance, p_transform); +} + Transform MultiMesh::get_instance_transform(int p_instance) const { return VisualServer::get_singleton()->multimesh_instance_get_transform(multimesh, p_instance); } +Transform2D MultiMesh::get_instance_transform_2d(int p_instance) const { + + return VisualServer::get_singleton()->multimesh_instance_get_transform_2d(multimesh, p_instance); +} + void MultiMesh::set_instance_color(int p_instance, const Color &p_color) { VisualServer::get_singleton()->multimesh_instance_set_color(multimesh, p_instance, p_color); @@ -189,6 +263,11 @@ Color MultiMesh::get_instance_custom_data(int p_instance) const { return VisualServer::get_singleton()->multimesh_instance_get_custom_data(multimesh, p_instance); } +void MultiMesh::set_as_bulk_array(const PoolVector<float> &p_array) { + + VisualServer::get_singleton()->multimesh_set_as_bulk_array(multimesh, p_array); +} + AABB MultiMesh::get_aabb() const { return VisualServer::get_singleton()->multimesh_get_aabb(multimesh); @@ -244,16 +323,23 @@ void MultiMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_instance_count", "count"), &MultiMesh::set_instance_count); ClassDB::bind_method(D_METHOD("get_instance_count"), &MultiMesh::get_instance_count); + ClassDB::bind_method(D_METHOD("set_visible_instance_count", "count"), &MultiMesh::set_visible_instance_count); + ClassDB::bind_method(D_METHOD("get_visible_instance_count"), &MultiMesh::get_visible_instance_count); ClassDB::bind_method(D_METHOD("set_instance_transform", "instance", "transform"), &MultiMesh::set_instance_transform); + ClassDB::bind_method(D_METHOD("set_instance_transform_2d", "instance", "transform"), &MultiMesh::set_instance_transform_2d); ClassDB::bind_method(D_METHOD("get_instance_transform", "instance"), &MultiMesh::get_instance_transform); + ClassDB::bind_method(D_METHOD("get_instance_transform_2d", "instance"), &MultiMesh::get_instance_transform_2d); ClassDB::bind_method(D_METHOD("set_instance_color", "instance", "color"), &MultiMesh::set_instance_color); ClassDB::bind_method(D_METHOD("get_instance_color", "instance"), &MultiMesh::get_instance_color); ClassDB::bind_method(D_METHOD("set_instance_custom_data", "instance", "custom_data"), &MultiMesh::set_instance_custom_data); ClassDB::bind_method(D_METHOD("get_instance_custom_data", "instance"), &MultiMesh::get_instance_custom_data); + ClassDB::bind_method(D_METHOD("set_as_bulk_array", "array"), &MultiMesh::set_as_bulk_array); ClassDB::bind_method(D_METHOD("get_aabb"), &MultiMesh::get_aabb); ClassDB::bind_method(D_METHOD("_set_transform_array"), &MultiMesh::_set_transform_array); ClassDB::bind_method(D_METHOD("_get_transform_array"), &MultiMesh::_get_transform_array); + ClassDB::bind_method(D_METHOD("_set_transform_2d_array"), &MultiMesh::_set_transform_2d_array); + ClassDB::bind_method(D_METHOD("_get_transform_2d_array"), &MultiMesh::_get_transform_2d_array); ClassDB::bind_method(D_METHOD("_set_color_array"), &MultiMesh::_set_color_array); ClassDB::bind_method(D_METHOD("_get_color_array"), &MultiMesh::_get_color_array); ClassDB::bind_method(D_METHOD("_set_custom_data_array"), &MultiMesh::_set_custom_data_array); @@ -263,8 +349,10 @@ void MultiMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_format", PROPERTY_HINT_ENUM, "2D,3D"), "set_transform_format", "get_transform_format"); ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_data_format", PROPERTY_HINT_ENUM, "None,Byte,Float"), "set_custom_data_format", "get_custom_data_format"); ADD_PROPERTY(PropertyInfo(Variant::INT, "instance_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"), "set_instance_count", "get_instance_count"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_instance_count", PROPERTY_HINT_RANGE, "-1,16384,1,or_greater"), "set_visible_instance_count", "get_visible_instance_count"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "transform_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_transform_array", "_get_transform_array"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "transform_2d_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_transform_2d_array", "_get_transform_2d_array"); ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "color_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_color_array", "_get_color_array"); ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "custom_data_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_custom_data_array", "_get_custom_data_array"); @@ -286,6 +374,7 @@ MultiMesh::MultiMesh() { color_format = COLOR_NONE; custom_data_format = CUSTOM_DATA_NONE; transform_format = TRANSFORM_2D; + visible_instance_count = -1; instance_count = 0; } diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h index ec5a5ca4d5..6b17e9278d 100644 --- a/scene/resources/multimesh.h +++ b/scene/resources/multimesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -64,6 +64,7 @@ private: ColorFormat color_format; CustomDataFormat custom_data_format; int instance_count; + int visible_instance_count; protected: static void _bind_methods(); @@ -71,6 +72,9 @@ protected: void _set_transform_array(const PoolVector<Vector3> &p_array); PoolVector<Vector3> _get_transform_array() const; + void _set_transform_2d_array(const PoolVector<Vector2> &p_array); + PoolVector<Vector2> _get_transform_2d_array() const; + void _set_color_array(const PoolVector<Color> &p_array); PoolVector<Color> _get_color_array() const; @@ -93,8 +97,13 @@ public: void set_instance_count(int p_count); int get_instance_count() const; + void set_visible_instance_count(int p_count); + int get_visible_instance_count() const; + void set_instance_transform(int p_instance, const Transform &p_transform); + void set_instance_transform_2d(int p_instance, const Transform2D &p_transform); Transform get_instance_transform(int p_instance) const; + Transform2D get_instance_transform_2d(int p_instance) const; void set_instance_color(int p_instance, const Color &p_color); Color get_instance_color(int p_instance) const; @@ -102,6 +111,8 @@ public: void set_instance_custom_data(int p_instance, const Color &p_custom_data); Color get_instance_custom_data(int p_instance) const; + void set_as_bulk_array(const PoolVector<float> &p_array); + virtual AABB get_aabb() const; virtual RID get_rid() const; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 87483a7da4..99286668ce 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -55,7 +55,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { Node *p_name; \ if (p_id & FLAG_ID_IS_PATH) { \ NodePath np = node_paths[p_id & FLAG_MASK]; \ - p_name = ret_nodes[0]->_get_node(np); \ + p_name = ret_nodes[0]->get_node_or_null(np); \ } else { \ ERR_FAIL_INDEX_V(p_id &FLAG_MASK, nc, NULL); \ p_name = ret_nodes[p_id & FLAG_MASK]; \ @@ -92,6 +92,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const { if (i > 0) { + ERR_EXPLAIN(vformat("Invalid scene: node %s does not specify its parent node.", snames[n.name])); + ERR_FAIL_COND_V(n.parent == -1, NULL); NODE_FROM_ID(nparent, n.parent); #ifdef DEBUG_ENABLED if (!nparent && (n.parent & FLAG_ID_IS_PATH)) { @@ -175,8 +177,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const { node = Object::cast_to<Node>(obj); } else { - print_line("Class is disabled for: " + itos(n.type)); - print_line("name: " + String(snames[n.type])); + //print_line("Class is disabled for: " + itos(n.type)); + //print_line("name: " + String(snames[n.type])); } if (node) { @@ -236,8 +238,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const { } else { //for instances, a copy must be made - Node *base = i == 0 ? node : ret_nodes[0]; - Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, resources_local_to_scene); + Node *base2 = i == 0 ? node : ret_nodes[0]; + Ref<Resource> local_dupe = res->duplicate_for_local_scene(base2, resources_local_to_scene); resources_local_to_scene[res] = local_dupe; res = local_dupe; value = local_dupe; @@ -296,8 +298,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const { ret_nodes[i] = node; if (node && gen_node_path_cache && ret_nodes[0]) { - NodePath n = ret_nodes[0]->get_path_to(node); - node_path_cache[n] = i; + NodePath n2 = ret_nodes[0]->get_path_to(node); + node_path_cache[n2] = i; } } @@ -342,7 +344,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { } for (int i = 0; i < editable_instances.size(); i++) { - Node *ei = ret_nodes[0]->_get_node(editable_instances[i]); + Node *ei = ret_nodes[0]->get_node_or_null(editable_instances[i]); if (ei) { ret_nodes[0]->set_editable_instance(ei, true); } @@ -533,7 +535,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map float a = value; float b = original; - if (Math::abs(a - b) < CMP_EPSILON) + if (Math::is_equal_approx(a, b)) continue; } else if (bool(Variant::evaluate(Variant::OP_EQUAL, value, original))) { @@ -749,7 +751,7 @@ Error SceneState::_parse_connections(Node *p_owner, Node *p_node, Map<StringName { Node *nl = p_node; - bool exists = false; + bool exists2 = false; while (nl) { @@ -763,7 +765,7 @@ Error SceneState::_parse_connections(Node *p_owner, Node *p_node, Map<StringName if (from_node >= 0 && to_node >= 0) { //this one has state for this node, save if (state->is_connection(from_node, c.signal, to_node, c.method)) { - exists = true; + exists2 = true; break; } } @@ -781,7 +783,7 @@ Error SceneState::_parse_connections(Node *p_owner, Node *p_node, Map<StringName if (from_node >= 0 && to_node >= 0) { //this one has state for this node, save if (state->is_connection(from_node, c.signal, to_node, c.method)) { - exists = true; + exists2 = true; break; } } @@ -791,7 +793,7 @@ Error SceneState::_parse_connections(Node *p_owner, Node *p_node, Map<StringName } } - if (exists) { + if (exists2) { continue; } } diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index e5f22f5e3b..3c05929dea 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 92c185712a..758475b75e 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -311,8 +311,8 @@ void ParticlesMaterial::_update_shader() { //initiate velocity spread in 3D code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n"; - code += " vec3 direction_xz = vec3(sin(angle1_rad), 0, cos(angle1_rad));\n"; - code += " vec3 direction_yz = vec3(0, sin(angle2_rad), cos(angle2_rad));\n"; + code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n"; + code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n"; code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n"; code += " vec3 direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; code += " direction = normalize(direction);\n"; @@ -347,7 +347,7 @@ void ParticlesMaterial::_update_shader() { code += " VELOCITY.xy = rotm * VELOCITY.xy;\n"; } else { code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n"; - code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n"; + code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n"; code += " vec3 tangent = normalize(cross(v0, normal));\n"; code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; code += " VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n"; @@ -1186,6 +1186,7 @@ void ParticlesMaterial::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); + BIND_ENUM_CONSTANT(FLAG_DISABLE_Z); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index 20b505532e..42bf60ff48 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -36,7 +36,7 @@ class ParticlesMaterial : public Material { - GDCLASS(ParticlesMaterial, Material) + GDCLASS(ParticlesMaterial, Material); public: enum Parameter { diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp index 03b3589727..7d97c279ed 100644 --- a/scene/resources/physics_material.cpp +++ b/scene/resources/physics_material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h index bf11bf0ac1..30660e80ac 100644 --- a/scene/resources/physics_material.h +++ b/scene/resources/physics_material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/plane_shape.cpp b/scene/resources/plane_shape.cpp index 4d38ebe090..08f6ccd764 100644 --- a/scene/resources/plane_shape.cpp +++ b/scene/resources/plane_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -64,6 +64,7 @@ Vector<Vector3> PlaneShape::_gen_debug_mesh_lines() { void PlaneShape::_update_shape() { PhysicsServer::get_singleton()->shape_set_data(get_shape(), plane); + Shape::_update_shape(); } void PlaneShape::set_plane(Plane p_plane) { diff --git a/scene/resources/plane_shape.h b/scene/resources/plane_shape.h index c24c9474fb..87c367cfde 100644 --- a/scene/resources/plane_shape.h +++ b/scene/resources/plane_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index bd03930c9e..52fc21ac11 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -441,9 +441,9 @@ void PolygonPathFinder::_set_data(const Dictionary &p_data) { PoolVector<float> penalties = p_data["penalties"]; if (penalties.size() == pc) { - PoolVector<float>::Read pr = penalties.read(); + PoolVector<float>::Read pr2 = penalties.read(); for (int i = 0; i < pc; i++) { - points.write[i].penalty = pr[i]; + points.write[i].penalty = pr2[i]; } } } diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h index 66282458af..59387e9672 100644 --- a/scene/resources/polygon_path_finder.h +++ b/scene/resources/polygon_path_finder.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 6dedb74fad..04d13c8869 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -157,6 +157,12 @@ Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const { return primitive_type; } +void PrimitiveMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) { + ERR_FAIL_INDEX(p_idx, 1); + + set_material(p_material); +} + Ref<Material> PrimitiveMesh::surface_get_material(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, 1, NULL); @@ -376,17 +382,17 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const { z = radius * cos(0.5 * Math_PI * v); for (i = 0; i <= radial_segments; i++) { - float u = i; - u /= radial_segments; + float u2 = i; + u2 /= radial_segments; - x = sin(u * (Math_PI * 2.0)); - y = -cos(u * (Math_PI * 2.0)); + x = sin(u2 * (Math_PI * 2.0)); + y = -cos(u2 * (Math_PI * 2.0)); Vector3 p = Vector3(x * radius * w, y * radius * w, z); points.push_back(p + Vector3(0.0, 0.0, -0.5 * mid_height)); normals.push_back(p.normalized()); ADD_TANGENT(-y, x, 0.0, 1.0) - uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird))); + uvs.push_back(Vector2(u2, twothirds + ((v - 1.0) * onethird))); point++; if (i > 0 && j > 0) { diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index a91aa09ffe..312899c028 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -72,6 +72,7 @@ public: virtual Array surface_get_blend_shape_arrays(int p_surface) const; virtual uint32_t surface_get_format(int p_idx) const; virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const; + virtual void surface_set_material(int p_idx, const Ref<Material> &p_material); virtual Ref<Material> surface_get_material(int p_idx) const; virtual int get_blend_shape_count() const; virtual StringName get_blend_shape_name(int p_index) const; @@ -268,7 +269,7 @@ public: class QuadMesh : public PrimitiveMesh { - GDCLASS(QuadMesh, PrimitiveMesh) + GDCLASS(QuadMesh, PrimitiveMesh); private: Size2 size; diff --git a/scene/resources/ray_shape.cpp b/scene/resources/ray_shape.cpp index a9dec3e87c..0acfffdc06 100644 --- a/scene/resources/ray_shape.cpp +++ b/scene/resources/ray_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -47,7 +47,7 @@ void RayShape::_update_shape() { d["length"] = length; d["slips_on_slope"] = slips_on_slope; PhysicsServer::get_singleton()->shape_set_data(get_shape(), d); - emit_changed(); + Shape::_update_shape(); } void RayShape::set_length(float p_length) { diff --git a/scene/resources/ray_shape.h b/scene/resources/ray_shape.h index f11b2e7c3c..89fc34051c 100644 --- a/scene/resources/ray_shape.h +++ b/scene/resources/ray_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index aeb22f6d0a..ff0743a8dd 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h index 2d66d328fd..27305e5918 100644 --- a/scene/resources/rectangle_shape_2d.h +++ b/scene/resources/rectangle_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/resource_format_text.cpp index 5ae843f2bd..0921c0dae9 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* scene_format_text.cpp */ +/* resource_format_text.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,7 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "scene_format_text.h" +#include "resource_format_text.h" + #include "core/io/resource_format_binary.h" #include "core/os/dir_access.h" #include "core/project_settings.h" @@ -444,6 +445,10 @@ Error ResourceInteractiveLoaderText::poll() { } else { resource_cache.push_back(res); +#ifdef TOOLS_ENABLED + //remember ID for saving + res->set_id_for_path(local_path, index); +#endif } ExtResource er; @@ -1354,13 +1359,15 @@ String ResourceFormatSaverTextInstance::_write_resource(const RES &res) { if (external_resources.has(res)) { - return "ExtResource( " + itos(external_resources[res] + 1) + " )"; + return "ExtResource( " + itos(external_resources[res]) + " )"; } else { if (internal_resources.has(res)) { return "SubResource( " + itos(internal_resources[res]) + " )"; } else if (res->get_path().length() && res->get_path().find("::") == -1) { - + if (res->get_path() == local_path) { //circular reference attempt + return "null"; + } //external resource String path = relative_paths ? local_path.path_to_file(res->get_path()) : res->get_path(); return "Resource( \"" + path + "\" )"; @@ -1385,6 +1392,10 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, return; if (!p_main && (!bundle_resources) && res->get_path().length() && res->get_path().find("::") == -1) { + if (res->get_path() == local_path) { + ERR_PRINTS("Circular reference to resource being saved found: '" + local_path + "' will be null next time it's loaded."); + return; + } int index = external_resources.size(); external_resources[res] = index; return; @@ -1407,7 +1418,20 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, if (pi.usage & PROPERTY_USAGE_STORAGE) { Variant v = res->get(I->get().name); - _find_resources(v); + + if (pi.usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) { + RES sres = v; + if (sres.is_valid()) { + NonPersistentKey npk; + npk.base = res; + npk.property = pi.name; + non_persistent_map[npk] = sres; + resource_set.insert(sres); + saved_resources.push_back(sres); + } + } else { + _find_resources(v); + } } I = I->next(); @@ -1439,7 +1463,8 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, _find_resources(v); } } break; - default: {} + default: { + } } } @@ -1518,18 +1543,61 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r f->store_line("]\n"); //one empty line } - Vector<RES> sorted_er; - sorted_er.resize(external_resources.size()); + { + } +#ifdef TOOLS_ENABLED + //keep order from cached ids + Set<int> cached_ids_found; for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) { + int cached_id = E->key()->get_id_for_path(local_path); + if (cached_id < 0 || cached_ids_found.has(cached_id)) { + E->get() = -1; //reset + } else { + E->get() = cached_id; + cached_ids_found.insert(cached_id); + } + } + //create IDs for non cached resources + for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) { + if (cached_ids_found.has(E->get())) { //already cached, go on + continue; + } - sorted_er.write[E->get()] = E->key(); + int attempt = 1; //start from one, more readable format + while (cached_ids_found.has(attempt)) { + attempt++; + } + + cached_ids_found.insert(attempt); + E->get() = attempt; + //update also in resource + Ref<Resource> res = E->key(); + res->set_id_for_path(local_path, attempt); } +#else + //make sure to start from one, as it makes format more readable + for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) { + E->get() = E->get() + 1; + } +#endif + + Vector<ResourceSort> sorted_er; + + for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) { + + ResourceSort rs; + rs.resource = E->key(); + rs.index = E->get(); + sorted_er.push_back(rs); + } + + sorted_er.sort(); for (int i = 0; i < sorted_er.size(); i++) { - String p = sorted_er[i]->get_path(); + String p = sorted_er[i].resource->get_path(); - f->store_string("[ext_resource path=\"" + p + "\" type=\"" + sorted_er[i]->get_save_class() + "\" id=" + itos(i + 1) + "]\n"); //bundled + f->store_string("[ext_resource path=\"" + p + "\" type=\"" + sorted_er[i].resource->get_save_class() + "\" id=" + itos(sorted_er[i].index) + "]\n"); //bundled } if (external_resources.size()) @@ -1562,7 +1630,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r break; //save as a scene if (main) { - f->store_line("[resource]\n"); + f->store_line("[resource]"); } else { String line = "[sub_resource "; if (res->get_subindex() == 0) { @@ -1577,7 +1645,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r int idx = res->get_subindex(); line += "type=\"" + res->get_class() + "\" id=" + itos(idx); - f->store_line(line + "]\n"); + f->store_line(line + "]"); if (takeover_paths) { res->set_path(p_path + "::" + itos(idx), true); } @@ -1599,7 +1667,17 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r if (PE->get().usage & PROPERTY_USAGE_STORAGE) { String name = PE->get().name; - Variant value = res->get(name); + Variant value; + if (PE->get().usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) { + NonPersistentKey npk; + npk.base = res; + npk.property = name; + if (non_persistent_map.has(npk)) { + value = non_persistent_map[npk]; + } + } else { + value = res->get(name); + } Variant default_value = ClassDB::class_get_default_property_value(res->get_class(), name); if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) { @@ -1615,7 +1693,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } } - f->store_string("\n"); + if (E->next()) + f->store_line(String()); } if (packed_scene.is_valid()) { @@ -1633,15 +1712,15 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r Vector<StringName> groups = state->get_node_groups(i); String header = "[node"; - header += " name=\"" + String(name) + "\""; + header += " name=\"" + String(name).c_escape() + "\""; if (type != StringName()) { header += " type=\"" + String(type) + "\""; } if (path != NodePath()) { - header += " parent=\"" + String(path.simplified()) + "\""; + header += " parent=\"" + String(path.simplified()).c_escape() + "\""; } if (owner != NodePath() && owner != NodePath(".")) { - header += " owner=\"" + String(owner.simplified()) + "\""; + header += " owner=\"" + String(owner.simplified()).c_escape() + "\""; } if (index >= 0) { header += " index=\"" + itos(index) + "\""; @@ -1684,7 +1763,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r f->store_string(_valprop(String(state->get_node_property_name(i, j))) + " = " + vars + "\n"); } - f->store_line(String()); + if (i < state->get_node_count() - 1) + f->store_line(String()); } for (int i = 0; i < state->get_connection_count(); i++) { diff --git a/scene/resources/scene_format_text.h b/scene/resources/resource_format_text.h index e5ee6ae760..0041989f09 100644 --- a/scene/resources/scene_format_text.h +++ b/scene/resources/resource_format_text.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* scene_format_text.h */ +/* resource_format_text.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SCENE_FORMAT_TEXT_H -#define SCENE_FORMAT_TEXT_H +#ifndef RESOURCE_FORMAT_TEXT_H +#define RESOURCE_FORMAT_TEXT_H #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" @@ -128,7 +128,6 @@ public: }; class ResourceFormatLoaderText : public ResourceFormatLoader { - GDCLASS(ResourceFormatLoaderText, ResourceFormatLoader) public: static ResourceFormatLoaderText *singleton; virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); @@ -155,11 +154,28 @@ class ResourceFormatSaverTextInstance { bool bundle_resources; bool skip_editor; FileAccess *f; + + struct NonPersistentKey { //for resource properties generated on the fly + RES base; + StringName property; + bool operator<(const NonPersistentKey &p_key) const { return base == p_key.base ? property < p_key.property : base < p_key.base; } + }; + + Map<NonPersistentKey, RES> non_persistent_map; + Set<RES> resource_set; List<RES> saved_resources; Map<RES, int> external_resources; Map<RES, int> internal_resources; + struct ResourceSort { + RES resource; + int index; + bool operator<(const ResourceSort &p_right) const { + return index < p_right.index; + } + }; + void _find_resources(const Variant &p_variant, bool p_main = false); static String _write_resources(void *ud, const RES &p_resource); @@ -170,7 +186,6 @@ public: }; class ResourceFormatSaverText : public ResourceFormatSaver { - GDCLASS(ResourceFormatSaverText, ResourceFormatSaver) public: static ResourceFormatSaverText *singleton; virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); @@ -180,4 +195,4 @@ public: ResourceFormatSaverText(); }; -#endif // SCENE_FORMAT_TEXT_H +#endif // RESOURCE_FORMAT_TEXT_H diff --git a/scene/resources/room.cpp b/scene/resources/room.cpp index 9493f8fbe6..103a7ede74 100644 --- a/scene/resources/room.cpp +++ b/scene/resources/room.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/room.h b/scene/resources/room.h index d5ad847516..8990056f46 100644 --- a/scene/resources/room.h +++ b/scene/resources/room.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp index 58027c127d..62c5f9bab3 100644 --- a/scene/resources/segment_shape_2d.cpp +++ b/scene/resources/segment_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h index 700982ac0a..f35707b990 100644 --- a/scene/resources/segment_shape_2d.h +++ b/scene/resources/segment_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 66bf3b4991..89570beb5f 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 6804832fb9..6e7447839f 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -100,7 +100,6 @@ public: VARIANT_ENUM_CAST(Shader::Mode); class ResourceFormatLoaderShader : public ResourceFormatLoader { - GDCLASS(ResourceFormatLoaderShader, 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; @@ -109,7 +108,6 @@ public: }; class ResourceFormatSaverShader : public ResourceFormatSaver { - GDCLASS(ResourceFormatSaverShader, ResourceFormatSaver) public: virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp index 214e2e8edc..6ba46f066c 100644 --- a/scene/resources/shape.cpp +++ b/scene/resources/shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -96,6 +96,11 @@ Ref<ArrayMesh> Shape::get_debug_mesh() { return debug_mesh_cache; } +void Shape::_update_shape() { + emit_changed(); + debug_mesh_cache.unref(); +} + void Shape::_bind_methods() { ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape::set_margin); diff --git a/scene/resources/shape.h b/scene/resources/shape.h index 6643f4ee44..ba763eaab1 100644 --- a/scene/resources/shape.h +++ b/scene/resources/shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -51,6 +51,8 @@ protected: Shape(RID p_shape); virtual Vector<Vector3> _gen_debug_mesh_lines() = 0; // { return Vector<Vector3>(); } + virtual void _update_shape(); + public: virtual RID get_rid() const { return shape; } diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index 0ca518e5bb..e2407e4423 100644 --- a/scene/resources/shape_2d.cpp +++ b/scene/resources/shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -59,37 +59,37 @@ bool Shape2D::collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_sh return Physics2DServer::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), NULL, 0, r); } -Variant Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) { +Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) { - ERR_FAIL_COND_V(p_shape.is_null(), Variant()); + ERR_FAIL_COND_V(p_shape.is_null(), Array()); const int max_contacts = 16; Vector2 result[max_contacts * 2]; int contacts = 0; if (!Physics2DServer::get_singleton()->shape_collide(get_rid(), p_local_xform, p_local_motion, p_shape->get_rid(), p_shape_xform, p_shape_motion, result, max_contacts, contacts)) - return Variant(); + return Array(); Array results; results.resize(contacts * 2); - for (int i = 0; i < contacts; i++) { + for (int i = 0; i < contacts * 2; i++) { results[i] = result[i]; } return results; } -Variant Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) { +Array Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) { - ERR_FAIL_COND_V(p_shape.is_null(), Variant()); + ERR_FAIL_COND_V(p_shape.is_null(), Array()); const int max_contacts = 16; Vector2 result[max_contacts * 2]; int contacts = 0; if (!Physics2DServer::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), result, max_contacts, contacts)) - return Variant(); + return Array(); Array results; results.resize(contacts * 2); - for (int i = 0; i < contacts; i++) { + for (int i = 0; i < contacts * 2; i++) { results[i] = result[i]; } diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index fa39daa565..da9b80477c 100644 --- a/scene/resources/shape_2d.h +++ b/scene/resources/shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -53,8 +53,8 @@ public: bool collide_with_motion(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion); bool collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform); - Variant collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion); - Variant collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform); + Array collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion); + Array collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform); virtual void draw(const RID &p_to_rid, const Color &p_color) {} virtual Rect2 get_rect() const { return Rect2(); } diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky.cpp index 347bca4400..292fdcdbd2 100644 --- a/scene/resources/sky_box.cpp +++ b/scene/resources/sky.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* sky_box.cpp */ +/* sky.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,7 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "sky_box.h" +#include "sky.h" + #include "core/io/image_loader.h" void Sky::set_radiance_size(RadianceSize p_size) { @@ -61,7 +62,7 @@ void Sky::_bind_methods() { } Sky::Sky() { - radiance_size = RADIANCE_SIZE_512; + radiance_size = RADIANCE_SIZE_128; } ///////////////////////////////////////// @@ -155,7 +156,10 @@ Ref<Image> ProceduralSky::_generate_sky() { Color ground_bottom_linear = ground_bottom_color.to_linear(); Color ground_horizon_linear = ground_horizon_color.to_linear(); - //Color sun_linear = sun_color.to_linear(); + Color sun_linear; + sun_linear.r = sun_color.r * sun_energy; + sun_linear.g = sun_color.g * sun_energy; + sun_linear.b = sun_color.b * sun_energy; Vector3 sun(0, 0, -1); @@ -203,13 +207,13 @@ Ref<Image> ProceduralSky::_generate_sky() { float sun_angle = Math::rad2deg(Math::acos(CLAMP(sun.dot(normal), -1.0, 1.0))); if (sun_angle < sun_angle_min) { - color = color.blend(sun_color); + color = color.blend(sun_linear); } else if (sun_angle < sun_angle_max) { float c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min); c2 = Math::ease(c2, sun_curve); - color = color.blend(sun_color).linear_interpolate(color, c2); + color = color.blend(sun_linear).linear_interpolate(color, c2); } } @@ -532,7 +536,7 @@ void ProceduralSky::_bind_methods() { BIND_ENUM_CONSTANT(TEXTURE_SIZE_MAX); } -ProceduralSky::ProceduralSky() { +ProceduralSky::ProceduralSky(bool p_desaturate) { sky = VS::get_singleton()->sky_create(); texture = VS::get_singleton()->texture_create(); @@ -548,13 +552,19 @@ ProceduralSky::ProceduralSky() { ground_curve = 0.02; ground_energy = 1; + if (p_desaturate) { + sky_top_color.set_hsv(sky_top_color.get_h(), 0, sky_top_color.get_v()); + sky_horizon_color.set_hsv(sky_horizon_color.get_h(), 0, sky_horizon_color.get_v()); + ground_bottom_color.set_hsv(ground_bottom_color.get_h(), 0, ground_bottom_color.get_v()); + ground_horizon_color.set_hsv(ground_horizon_color.get_h(), 0, ground_horizon_color.get_v()); + } sun_color = Color(1, 1, 1); sun_latitude = 35; sun_longitude = 0; sun_angle_min = 1; sun_angle_max = 100; sun_curve = 0.05; - sun_energy = 16; + sun_energy = 1; texture_size = TEXTURE_SIZE_1024; sky_thread = NULL; diff --git a/scene/resources/sky_box.h b/scene/resources/sky.h index bbb852822d..3a6f44e11b 100644 --- a/scene/resources/sky_box.h +++ b/scene/resources/sky.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* sky_box.h */ +/* sky.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -28,11 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SKY_BOX_H -#define SKY_BOX_H +#ifndef SKY_H +#define SKY_H #include "core/os/thread.h" #include "scene/resources/texture.h" + class Sky : public Resource { GDCLASS(Sky, Resource); @@ -190,10 +191,10 @@ public: virtual RID get_rid() const; - ProceduralSky(); + ProceduralSky(bool p_desaturate = false); ~ProceduralSky(); }; VARIANT_ENUM_CAST(ProceduralSky::TextureSize) -#endif // SKY_BOX_H +#endif // SKY_H diff --git a/scene/resources/space_2d.cpp b/scene/resources/space_2d.cpp index 062f4099db..e6d366c501 100644 --- a/scene/resources/space_2d.cpp +++ b/scene/resources/space_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/space_2d.h b/scene/resources/space_2d.h index 1143ad2bd5..ced7c87406 100644 --- a/scene/resources/space_2d.h +++ b/scene/resources/space_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/sphere_shape.cpp b/scene/resources/sphere_shape.cpp index d8ca1cf3f1..af89413ced 100644 --- a/scene/resources/sphere_shape.cpp +++ b/scene/resources/sphere_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -58,6 +58,7 @@ Vector<Vector3> SphereShape::_gen_debug_mesh_lines() { void SphereShape::_update_shape() { PhysicsServer::get_singleton()->shape_set_data(get_shape(), radius); + Shape::_update_shape(); } void SphereShape::set_radius(float p_radius) { diff --git a/scene/resources/sphere_shape.h b/scene/resources/sphere_shape.h index 5dd7daabc5..682928e885 100644 --- a/scene/resources/sphere_shape.h +++ b/scene/resources/sphere_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 087990c308..5dd429fa75 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,6 +29,8 @@ /*************************************************************************/ #include "style_box.h" +#include "scene/2d/canvas_item.h" + #include <limits.h> bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const { @@ -54,6 +56,10 @@ float StyleBox::get_margin(Margin p_margin) const { return margin[p_margin]; } +CanvasItem *StyleBox::get_current_item_drawn() const { + return CanvasItem::get_current_item_drawn(); +} + Size2 StyleBox::get_minimum_size() const { return Size2(get_margin(MARGIN_LEFT) + get_margin(MARGIN_RIGHT), get_margin(MARGIN_TOP) + get_margin(MARGIN_BOTTOM)); @@ -83,6 +89,7 @@ void StyleBox::_bind_methods() { ClassDB::bind_method(D_METHOD("get_minimum_size"), &StyleBox::get_minimum_size); ClassDB::bind_method(D_METHOD("get_center_size"), &StyleBox::get_center_size); ClassDB::bind_method(D_METHOD("get_offset"), &StyleBox::get_offset); + ClassDB::bind_method(D_METHOD("get_current_item_drawn"), &StyleBox::get_current_item_drawn); ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw); @@ -361,25 +368,14 @@ Color StyleBoxFlat::get_bg_color() const { return bg_color; } -void StyleBoxFlat::set_border_color_all(const Color &p_color) { - for (int i = 0; i < 4; i++) { - - border_color.write()[i] = p_color; - } - emit_changed(); -} -Color StyleBoxFlat::get_border_color_all() const { - - return border_color[MARGIN_TOP]; -} -void StyleBoxFlat::set_border_color(Margin p_border, const Color &p_color) { +void StyleBoxFlat::set_border_color(const Color &p_color) { - border_color.write()[p_border] = p_color; + border_color = p_color; emit_changed(); } -Color StyleBoxFlat::get_border_color(Margin p_border) const { +Color StyleBoxFlat::get_border_color() const { - return border_color[p_border]; + return border_color; } void StyleBoxFlat::set_border_width_all(int p_size) { @@ -504,6 +500,16 @@ int StyleBoxFlat::get_shadow_size() const { return shadow_size; } +void StyleBoxFlat::set_shadow_offset(const Point2 &p_offset) { + + shadow_offset = p_offset; + emit_changed(); +} +Point2 StyleBoxFlat::get_shadow_offset() const { + + return shadow_offset; +} + void StyleBoxFlat::set_anti_aliased(const bool &p_anti_aliased) { anti_aliased = p_anti_aliased; emit_changed(); @@ -545,7 +551,7 @@ inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_re inner_corner_radius[0] = MAX(corner_radius[0] - rad, 0); //tr - rad = MIN(border_top, border_bottom); + rad = MIN(border_top, border_right); inner_corner_radius[1] = MAX(corner_radius[1] - rad, 0); //br @@ -558,12 +564,13 @@ inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_re } inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 style_rect, const int corner_radius[4], - const Rect2 ring_rect, const int border_width[4], const Color inner_color[4], const Color outer_color[4], const int corner_detail) { + const Rect2 ring_rect, const int border_width[4], const Color &inner_color, const Color &outer_color, const int corner_detail, const bool fill_center = false) { int vert_offset = verts.size(); if (!vert_offset) { vert_offset = 0; } + int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail; int ring_corner_radius[4]; @@ -578,10 +585,11 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color Rect2 inner_rect; inner_rect = ring_rect.grow_individual(-border_width[MARGIN_LEFT], -border_width[MARGIN_TOP], -border_width[MARGIN_RIGHT], -border_width[MARGIN_BOTTOM]); + int inner_corner_radius[4]; + set_inner_corner_radius(style_rect, inner_rect, corner_radius, inner_corner_radius); Vector<Point2> inner_points; - set_inner_corner_radius(style_rect, inner_rect, corner_radius, inner_corner_radius); inner_points.push_back(inner_rect.position + Vector2(inner_corner_radius[0], inner_corner_radius[0])); //tl inner_points.push_back(Point2(inner_rect.position.x + inner_rect.size.x - inner_corner_radius[1], inner_rect.position.y + inner_corner_radius[1])); //tr inner_points.push_back(inner_rect.position + inner_rect.size - Vector2(inner_corner_radius[2], inner_corner_radius[2])); //br @@ -596,11 +604,11 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color Point2 corner_point; if (inner_outer == 0) { radius = inner_corner_radius[corner_index]; - color = *inner_color; + color = inner_color; corner_point = inner_points[corner_index]; } else { radius = ring_corner_radius[corner_index]; - color = *outer_color; + color = outer_color; corner_point = outer_points[corner_index]; } float x = radius * (float)cos((double)corner_index * Math_PI / 2.0 + (double)detail / (double)adapted_corner_detail * Math_PI / 2.0 + Math_PI) + corner_point.x; @@ -611,17 +619,28 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color } } - int vert_count = (adapted_corner_detail + 1) * 4 * 2; + int ring_vert_count = verts.size() - vert_offset; + //fill the indices and the colors for the border - for (int i = 0; i < vert_count; i++) { - //poly 1 - indices.push_back(vert_offset + ((i + 0) % vert_count)); - indices.push_back(vert_offset + ((i + 2) % vert_count)); - indices.push_back(vert_offset + ((i + 1) % vert_count)); - //poly 2 - indices.push_back(vert_offset + ((i + 1) % vert_count)); - indices.push_back(vert_offset + ((i + 2) % vert_count)); - indices.push_back(vert_offset + ((i + 3) % vert_count)); + for (int i = 0; i < ring_vert_count; i++) { + indices.push_back(vert_offset + ((i + 0) % ring_vert_count)); + indices.push_back(vert_offset + ((i + 2) % ring_vert_count)); + indices.push_back(vert_offset + ((i + 1) % ring_vert_count)); + } + + if (fill_center) { + //fill the indices and the colors for the center + for (int index = 0; index < ring_vert_count / 2; index += 2) { + int i = index; + //poly 1 + indices.push_back(vert_offset + i); + indices.push_back(vert_offset + ring_vert_count - 4 - i); + indices.push_back(vert_offset + i + 2); + //poly 2 + indices.push_back(vert_offset + i); + indices.push_back(vert_offset + ring_vert_count - 2 - i); + indices.push_back(vert_offset + ring_vert_count - 4 - i); + } } } @@ -650,13 +669,29 @@ inline void adapt_values(int p_index_a, int p_index_b, int *adapted_values, cons void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { //PREPARATIONS + bool draw_border = (border_width[0] > 0) || (border_width[1] > 0) || (border_width[2] > 0) || (border_width[3] > 0); + bool draw_shadow = (shadow_size > 0); + if (!draw_border && !draw_center && !draw_shadow) { + return; + } bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0); bool aa_on = rounded_corners && anti_aliased; + Color border_color_alpha = Color(border_color.r, border_color.g, border_color.b, 0); + + bool blend_on = blend_border && draw_border; + Rect2 style_rect = p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); - if (aa_on) { - style_rect = style_rect.grow(-((aa_size + 1) / 2)); + Rect2 border_style_rect = style_rect; + if (aa_on && !blend_on) { + float aa_size_grow = 0.5 * ((aa_size + 1) / 2); + style_rect = style_rect.grow(-aa_size_grow); + for (int i = 0; i < 4; i++) { + if (border_width[i] > 0) { + border_style_rect = border_style_rect.grow_margin((Margin)i, -aa_size_grow); + } + } } //adapt borders (prevent weird overlapping/glitchy drawings) @@ -679,79 +714,93 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { Vector<int> indices; Vector<Color> colors; - //DRAWING - VisualServer *vs = VisualServer::get_singleton(); - //DRAW SHADOW - if (shadow_size > 0) { + if (draw_shadow) { int shadow_width[4] = { shadow_size, shadow_size, shadow_size, shadow_size }; - Color shadow_colors[4] = { shadow_color, shadow_color, shadow_color, shadow_color }; - Color shadow_colors_transparent[4]; - for (int i = 0; i < 4; i++) { - shadow_colors_transparent[i] = Color(shadow_color.r, shadow_color.g, shadow_color.b, 0); + + Rect2 shadow_inner_rect = style_rect; + shadow_inner_rect.position += shadow_offset; + + Rect2 shadow_rect = style_rect.grow(shadow_size); + shadow_rect.position += shadow_offset; + + Color shadow_color_transparent = Color(shadow_color.r, shadow_color.g, shadow_color.b, 0); + + draw_ring(verts, indices, colors, shadow_inner_rect, adapted_corner, + shadow_rect, shadow_width, shadow_color, shadow_color_transparent, corner_detail); + + if (draw_center) { + int no_border[4] = { 0, 0, 0, 0 }; + draw_ring(verts, indices, colors, shadow_inner_rect, adapted_corner, + shadow_inner_rect, no_border, shadow_color, shadow_color, corner_detail, true); } - draw_ring(verts, indices, colors, style_rect, adapted_corner, - style_rect.grow(shadow_size), shadow_width, shadow_colors, shadow_colors_transparent, corner_detail); } //DRAW border - Color bg_color_array[4] = { bg_color, bg_color, bg_color, bg_color }; - const Color *inner_color = ((blend_border) ? bg_color_array : border_color.read().ptr()); - draw_ring(verts, indices, colors, style_rect, adapted_corner, - style_rect, adapted_border, inner_color, border_color.read().ptr(), corner_detail); + if (draw_border) { + draw_ring(verts, indices, colors, border_style_rect, adapted_corner, + border_style_rect, adapted_border, blend_on ? (draw_center ? bg_color : border_color_alpha) : border_color, border_color, corner_detail); + } //DRAW INFILL if (draw_center) { - int temp_vert_offset = verts.size(); int no_border[4] = { 0, 0, 0, 0 }; draw_ring(verts, indices, colors, style_rect, adapted_corner, - infill_rect, no_border, &bg_color, &bg_color, corner_detail); - int added_vert_count = verts.size() - temp_vert_offset; - //fill the indices and the colors for the center - for (int index = 0; index <= added_vert_count / 2; index += 2) { - int i = index; - //poly 1 - indices.push_back(temp_vert_offset + i); - indices.push_back(temp_vert_offset + added_vert_count - 4 - i); - indices.push_back(temp_vert_offset + i + 2); - //poly 1 - indices.push_back(temp_vert_offset + i); - indices.push_back(temp_vert_offset + added_vert_count - 2 - i); - indices.push_back(temp_vert_offset + added_vert_count - 4 - i); - } + infill_rect, no_border, bg_color, bg_color, corner_detail, true); } if (aa_on) { - - //HELPER ARRAYS - Color border_color_alpha[4]; - for (int i = 0; i < 4; i++) { - Color c = border_color.read().ptr()[i]; - border_color_alpha[i] = Color(c.r, c.g, c.b, 0); + Rect2 border_inner_rect = infill_rect; + int aa_border_width[4]; + int aa_fill_width[4]; + if (draw_border) { + border_inner_rect = border_style_rect.grow_individual(-adapted_border[MARGIN_LEFT], -adapted_border[MARGIN_TOP], -adapted_border[MARGIN_RIGHT], -adapted_border[MARGIN_BOTTOM]); + for (int i = 0; i < 4; i++) { + if (border_width[i] > 0) { + aa_border_width[i] = aa_size; + aa_fill_width[i] = 0; + } else { + aa_border_width[i] = 0; + aa_fill_width[i] = aa_size; + } + } + } else { + for (int i = 0; i < 4; i++) { + aa_fill_width[i] = aa_size; + } } - Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0); - Color bg_color_array_alpha[4] = { alpha_bg, alpha_bg, alpha_bg, alpha_bg }; - - int aa_border_width[4] = { aa_size, aa_size, aa_size, aa_size }; if (draw_center) { - if (!blend_border) { + if (!draw_border || !blend_on) { + Rect2 aa_rect = infill_rect.grow_individual(aa_fill_width[MARGIN_LEFT], aa_fill_width[MARGIN_TOP], + aa_fill_width[MARGIN_RIGHT], aa_fill_width[MARGIN_BOTTOM]); + + Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0); + //INFILL AA draw_ring(verts, indices, colors, style_rect, adapted_corner, - infill_rect.grow(aa_size), aa_border_width, bg_color_array, bg_color_array_alpha, corner_detail); + aa_rect, aa_fill_width, bg_color, alpha_bg, corner_detail); } - } else if (!(border_width[0] == 0 && border_width[1] == 0 && border_width[2] == 0 && border_width[3] == 0)) { - //DRAW INNER BORDER AA - draw_ring(verts, indices, colors, style_rect, adapted_corner, - infill_rect, aa_border_width, border_color_alpha, border_color.read().ptr(), corner_detail); } - //DRAW OUTER BORDER AA - if (!(border_width[0] == 0 && border_width[1] == 0 && border_width[2] == 0 && border_width[3] == 0)) { - draw_ring(verts, indices, colors, style_rect, adapted_corner, - style_rect.grow(aa_size), aa_border_width, border_color.read().ptr(), border_color_alpha, corner_detail); + + if (draw_border) { + if (!blend_on) { + //DRAW INNER BORDER AA + draw_ring(verts, indices, colors, border_style_rect, adapted_corner, + border_inner_rect, aa_border_width, border_color_alpha, border_color, corner_detail); + } + + Rect2 aa_rect = border_style_rect.grow_individual(aa_border_width[MARGIN_LEFT], aa_border_width[MARGIN_TOP], + aa_border_width[MARGIN_RIGHT], aa_border_width[MARGIN_BOTTOM]); + + //DRAW OUTER BORDER AA + draw_ring(verts, indices, colors, border_style_rect, adapted_corner, + aa_rect, aa_border_width, border_color, border_color_alpha, corner_detail); } } + //DRAWING + VisualServer *vs = VisualServer::get_singleton(); vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors); } @@ -763,8 +812,8 @@ void StyleBoxFlat::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &StyleBoxFlat::set_bg_color); ClassDB::bind_method(D_METHOD("get_bg_color"), &StyleBoxFlat::get_bg_color); - ClassDB::bind_method(D_METHOD("set_border_color", "color"), &StyleBoxFlat::set_border_color_all); - ClassDB::bind_method(D_METHOD("get_border_color"), &StyleBoxFlat::get_border_color_all); + ClassDB::bind_method(D_METHOD("set_border_color", "color"), &StyleBoxFlat::set_border_color); + ClassDB::bind_method(D_METHOD("get_border_color"), &StyleBoxFlat::get_border_color); ClassDB::bind_method(D_METHOD("set_border_width_all", "width"), &StyleBoxFlat::set_border_width_all); ClassDB::bind_method(D_METHOD("get_border_width_min"), &StyleBoxFlat::get_border_width_min); @@ -795,6 +844,9 @@ void StyleBoxFlat::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_size", "size"), &StyleBoxFlat::set_shadow_size); ClassDB::bind_method(D_METHOD("get_shadow_size"), &StyleBoxFlat::get_shadow_size); + ClassDB::bind_method(D_METHOD("set_shadow_offset", "offset"), &StyleBoxFlat::set_shadow_offset); + ClassDB::bind_method(D_METHOD("get_shadow_offset"), &StyleBoxFlat::get_shadow_offset); + ClassDB::bind_method(D_METHOD("set_anti_aliased", "anti_aliased"), &StyleBoxFlat::set_anti_aliased); ClassDB::bind_method(D_METHOD("is_anti_aliased"), &StyleBoxFlat::is_anti_aliased); @@ -836,6 +888,7 @@ void StyleBoxFlat::_bind_methods() { ADD_GROUP("Shadow", "shadow_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size"), "set_shadow_size", "get_shadow_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset"), "set_shadow_offset", "get_shadow_offset"); ADD_GROUP("Anti Aliasing", "anti_aliasing_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "anti_aliasing"), "set_anti_aliased", "is_anti_aliased"); @@ -846,17 +899,14 @@ StyleBoxFlat::StyleBoxFlat() { bg_color = Color(0.6, 0.6, 0.6); shadow_color = Color(0, 0, 0, 0.6); - - border_color.append(Color(0.8, 0.8, 0.8)); - border_color.append(Color(0.8, 0.8, 0.8)); - border_color.append(Color(0.8, 0.8, 0.8)); - border_color.append(Color(0.8, 0.8, 0.8)); + border_color = Color(0.8, 0.8, 0.8); blend_border = false; draw_center = true; anti_aliased = true; shadow_size = 0; + shadow_offset = Point2(0, 0); corner_detail = 8; aa_size = 1; @@ -896,6 +946,7 @@ int StyleBoxLine::get_thickness() const { void StyleBoxLine::set_vertical(bool p_vertical) { vertical = p_vertical; + emit_changed(); } bool StyleBoxLine::is_vertical() const { return vertical; diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index df3ebe1c36..c3965fe076 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,6 +37,8 @@ /** @author Juan Linietsky <reduzio@gmail.com> */ +class CanvasItem; + class StyleBox : public Resource { GDCLASS(StyleBox, Resource); @@ -58,6 +60,8 @@ public: virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const = 0; + CanvasItem *get_current_item_drawn() const; + Size2 get_minimum_size() const; Point2 get_offset() const; @@ -145,7 +149,7 @@ class StyleBoxFlat : public StyleBox { Color bg_color; Color shadow_color; - PoolVector<Color> border_color; + Color border_color; int border_width[4]; int expand_margin[4]; @@ -157,6 +161,7 @@ class StyleBoxFlat : public StyleBox { int corner_detail; int shadow_size; + Point2 shadow_offset; int aa_size; protected: @@ -169,10 +174,8 @@ public: Color get_bg_color() const; //Border Color - void set_border_color_all(const Color &p_color); - Color get_border_color_all() const; - void set_border_color(Margin p_border, const Color &p_color); - Color get_border_color(Margin p_border) const; + void set_border_color(const Color &p_color); + Color get_border_color() const; //BORDER //width @@ -214,6 +217,9 @@ public: void set_shadow_size(const int &p_size); int get_shadow_size() const; + void set_shadow_offset(const Point2 &p_offset); + Point2 get_shadow_offset() const; + //ANTI_ALIASING void set_anti_aliased(const bool &p_anti_aliased); bool is_anti_aliased() const; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 842252d5d9..496b1b2bdc 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -108,8 +108,55 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) { vtx.bones = last_bones; vtx.tangent = last_tangent.normal; vtx.binormal = last_normal.cross(last_tangent.normal).normalized() * last_tangent.d; + + const int expected_vertices = 4; + + if ((format & Mesh::ARRAY_FORMAT_WEIGHTS || format & Mesh::ARRAY_FORMAT_BONES) && (vtx.weights.size() != expected_vertices || vtx.bones.size() != expected_vertices)) { + //ensure vertices are the expected amount + ERR_FAIL_COND(vtx.weights.size() != vtx.bones.size()); + if (vtx.weights.size() < expected_vertices) { + //less than required, fill + for (int i = vtx.weights.size(); i < expected_vertices; i++) { + vtx.weights.push_back(0); + vtx.bones.push_back(0); + } + } else if (vtx.weights.size() > expected_vertices) { + //more than required, sort, cap and normalize. + Vector<WeightSort> weights; + for (int i = 0; i < vtx.weights.size(); i++) { + WeightSort ws; + ws.index = vtx.bones[i]; + ws.weight = vtx.weights[i]; + weights.push_back(ws); + } + + //sort + weights.sort(); + //cap + weights.resize(expected_vertices); + //renormalize + float total = 0; + for (int i = 0; i < expected_vertices; i++) { + total += weights[i].weight; + } + + vtx.weights.resize(expected_vertices); + vtx.bones.resize(expected_vertices); + + for (int i = 0; i < expected_vertices; i++) { + if (total > 0) { + vtx.weights.write[i] = weights[i].weight / total; + } else { + vtx.weights.write[i] = 0; + } + vtx.bones.write[i] = weights[i].index; + } + } + } + vertex_array.push_back(vtx); first = false; + format |= Mesh::ARRAY_FORMAT_VERTEX; } void SurfaceTool::add_color(Color p_color) { @@ -161,7 +208,6 @@ void SurfaceTool::add_uv2(const Vector2 &p_uv2) { void SurfaceTool::add_bones(const Vector<int> &p_bones) { ERR_FAIL_COND(!begun); - ERR_FAIL_COND(p_bones.size() != 4); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_BONES)); format |= Mesh::ARRAY_FORMAT_BONES; @@ -171,8 +217,6 @@ void SurfaceTool::add_bones(const Vector<int> &p_bones) { void SurfaceTool::add_weights(const Vector<float> &p_weights) { ERR_FAIL_COND(!begun); - - ERR_FAIL_COND(p_weights.size() != 4); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_WEIGHTS)); format |= Mesh::ARRAY_FORMAT_WEIGHTS; @@ -190,10 +234,10 @@ void SurfaceTool::add_smooth_group(bool p_smooth) { } } -void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertexes, const Vector<Vector2> &p_uvs, const Vector<Color> &p_colors, const Vector<Vector2> &p_uv2s, const Vector<Vector3> &p_normals, const Vector<Plane> &p_tangents) { +void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<Color> &p_colors, const Vector<Vector2> &p_uv2s, const Vector<Vector3> &p_normals, const Vector<Plane> &p_tangents) { ERR_FAIL_COND(!begun); ERR_FAIL_COND(primitive != Mesh::PRIMITIVE_TRIANGLES); - ERR_FAIL_COND(p_vertexes.size() < 3); + ERR_FAIL_COND(p_vertices.size() < 3); #define ADD_POINT(n) \ { \ @@ -207,10 +251,10 @@ void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertexes, const Vect add_normal(p_normals[n]); \ if (p_tangents.size() > n) \ add_tangent(p_tangents[n]); \ - add_vertex(p_vertexes[n]); \ + add_vertex(p_vertices[n]); \ } - for (int i = 0; i < p_vertexes.size() - 2; i++) { + for (int i = 0; i < p_vertices.size() - 2; i++) { ADD_POINT(0); ADD_POINT(i + 1); ADD_POINT(i + 2); @@ -397,7 +441,8 @@ Array SurfaceTool::commit_to_arrays() { a[i] = array; } break; - default: {} + default: { + } } } @@ -724,6 +769,26 @@ void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) { material = p_existing->surface_get_material(p_surface); } +void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String p_blend_shape_name) { + clear(); + primitive = p_existing->surface_get_primitive_type(p_surface); + Array arr = p_existing->surface_get_blend_shape_arrays(p_surface); + Array blend_shape_names; + int32_t shape_idx = -1; + for (int32_t i = 0; i < p_existing->get_blend_shape_count(); i++) { + String name = p_existing->get_blend_shape_name(i); + if (name == p_blend_shape_name) { + shape_idx = i; + break; + } + } + ERR_FAIL_COND(shape_idx == -1); + ERR_FAIL_COND(shape_idx >= arr.size()); + Array mesh = arr[shape_idx]; + ERR_FAIL_COND(mesh.size() != VS::ARRAY_MAX); + _create_list_from_arrays(arr[shape_idx], &vertex_array, &index_array, format); +} + void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform) { if (vertex_array.size() == 0) { @@ -1012,7 +1077,7 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("add_weights", "weights"), &SurfaceTool::add_weights); ClassDB::bind_method(D_METHOD("add_smooth_group", "smooth"), &SurfaceTool::add_smooth_group); - ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertexes", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>())); + ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>())); ClassDB::bind_method(D_METHOD("add_index", "index"), &SurfaceTool::add_index); @@ -1021,15 +1086,15 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("generate_normals", "flip"), &SurfaceTool::generate_normals, DEFVAL(false)); ClassDB::bind_method(D_METHOD("generate_tangents"), &SurfaceTool::generate_tangents); - ClassDB::bind_method(D_METHOD("add_to_format", "flags"), &SurfaceTool::add_to_format); - ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material); ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear); ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from); + ClassDB::bind_method(D_METHOD("create_from_blend_shape", "existing", "surface", "blend_shape"), &SurfaceTool::create_from_blend_shape); ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from); ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT)); + ClassDB::bind_method(D_METHOD("commit_to_arrays"), &SurfaceTool::commit_to_arrays); } SurfaceTool::SurfaceTool() { diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index cc8599e90a..c4c71dca13 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -62,6 +62,14 @@ private: static _FORCE_INLINE_ uint32_t hash(const Vertex &p_vtx); }; + struct WeightSort { + int index; + float weight; + bool operator<(const WeightSort &p_right) const { + return weight < p_right.weight; + } + }; + bool begun; bool first; Mesh::PrimitiveType primitive; @@ -109,7 +117,7 @@ public: void add_weights(const Vector<float> &p_weights); void add_smooth_group(bool p_smooth); - void add_triangle_fan(const Vector<Vector3> &p_vertexes, const Vector<Vector2> &p_uvs = Vector<Vector2>(), const Vector<Color> &p_colors = Vector<Color>(), const Vector<Vector2> &p_uv2s = Vector<Vector2>(), const Vector<Vector3> &p_normals = Vector<Vector3>(), const Vector<Plane> &p_tangents = Vector<Plane>()); + void add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs = Vector<Vector2>(), const Vector<Color> &p_colors = Vector<Color>(), const Vector<Vector2> &p_uv2s = Vector<Vector2>(), const Vector<Vector3> &p_normals = Vector<Vector3>(), const Vector<Plane> &p_tangents = Vector<Plane>()); void add_index(int p_index); @@ -118,8 +126,6 @@ public: void generate_normals(bool p_flip = false); void generate_tangents(); - void add_to_format(int p_flags) { format |= p_flags; } - void set_material(const Ref<Material> &p_material); void clear(); @@ -130,6 +136,7 @@ public: static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays); Array commit_to_arrays(); void create_from(const Ref<Mesh> &p_existing, int p_surface); + void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String p_blend_shape_name); void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform); Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT); diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp index 2af24ad2d5..37bdd691b4 100644 --- a/scene/resources/text_file.cpp +++ b/scene/resources/text_file.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/text_file.h b/scene/resources/text_file.h index 3abc769dc6..7127eaeb93 100644 --- a/scene/resources/text_file.h +++ b/scene/resources/text_file.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -36,7 +36,7 @@ class TextFile : public Resource { - GDCLASS(TextFile, Resource) + GDCLASS(TextFile, Resource); private: String text; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 4f4d375481..6e0bc43296 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -34,7 +34,9 @@ #include "core/io/image_loader.h" #include "core/method_bind_ext.gen.inc" #include "core/os/os.h" -#include "scene/resources/bit_mask.h" +#include "mesh.h" +#include "scene/resources/bit_map.h" +#include "servers/camera/camera_feed.h" Size2 Texture::get_size() const { @@ -110,10 +112,12 @@ void ImageTexture::reload_from_file() { Ref<Image> img; img.instance(); - Error err = ImageLoader::load_image(path, img); - ERR_FAIL_COND(err != OK); - - create_from_image(img, flags); + if (ImageLoader::load_image(path, img) == OK) { + create_from_image(img, flags); + } else { + Resource::reload_from_file(); + _change_notify(); + } } bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) { @@ -157,7 +161,7 @@ bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const { void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat")); - p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT)); p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "")); } @@ -185,6 +189,7 @@ void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uin format = p_format; w = p_width; h = p_height; + _change_notify(); } void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags) { @@ -197,6 +202,8 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags); VisualServer::get_singleton()->texture_set_data(texture, p_image); _change_notify(); + + image_stored = true; } void ImageTexture::set_flags(uint32_t p_flags) { @@ -211,6 +218,7 @@ void ImageTexture::set_flags(uint32_t p_flags) { return; //uninitialized, do not set to texture } VisualServer::get_singleton()->texture_set_flags(texture, p_flags); + _change_notify("flags"); } uint32_t ImageTexture::get_flags() const { @@ -225,7 +233,7 @@ Image::Format ImageTexture::get_format() const { #ifndef DISABLE_DEPRECATED Error ImageTexture::load(const String &p_path) { - WARN_DEPRECATED + WARN_DEPRECATED; Ref<Image> img; img.instance(); Error err = img->load(p_path); @@ -243,6 +251,7 @@ void ImageTexture::set_data(const Ref<Image> &p_image) { _change_notify(); alpha_cache.unref(); + image_stored = true; } void ImageTexture::_resource_path_changed() { @@ -252,7 +261,11 @@ void ImageTexture::_resource_path_changed() { Ref<Image> ImageTexture::get_data() const { - return VisualServer::get_singleton()->texture_get_data(texture); + if (image_stored) { + return VisualServer::get_singleton()->texture_get_data(texture); + } else { + return Ref<Image>(); + } } int ImageTexture::get_width() const { @@ -324,7 +337,7 @@ bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const { int y = p_y * ah / h; x = CLAMP(x, 0, aw); - y = CLAMP(y, 0, aw); + y = CLAMP(y, 0, ah); return alpha_cache->get_bit(Point2(x, y)); } @@ -417,6 +430,8 @@ ImageTexture::ImageTexture() { texture = VisualServer::get_singleton()->texture_create(); storage = STORAGE_RAW; lossy_storage_quality = 0.7; + image_stored = false; + format = Image::FORMAT_L8; } ImageTexture::~ImageTexture() { @@ -472,7 +487,7 @@ Image::Format StreamTexture::get_format() const { return format; } -Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit) { +Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, int &flags, Ref<Image> &image, int p_size_limit) { alpha_cache.unref(); @@ -488,8 +503,11 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'D' || header[2] != 'S' || header[3] != 'T', ERR_FILE_CORRUPT); } - tw = f->get_32(); - th = f->get_32(); + tw = f->get_16(); + tw_custom = f->get_16(); + th = f->get_16(); + th_custom = f->get_16(); + flags = f->get_32(); //texture flags! uint32_t df = f->get_32(); //data format @@ -623,7 +641,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla bool mipmaps = df & FORMAT_BIT_HAS_MIPMAPS; if (!mipmaps) { - int size = Image::get_image_data_size(tw, th, format, 0); + int size = Image::get_image_data_size(tw, th, format, false); PoolVector<uint8_t> img_data; img_data.resize(size); @@ -642,22 +660,19 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla int sw = tw; int sh = th; - int mipmaps = Image::get_image_required_mipmaps(tw, th, format); + int mipmaps2 = Image::get_image_required_mipmaps(tw, th, format); int total_size = Image::get_image_data_size(tw, th, format, true); int idx = 0; - int ofs = 0; - while (mipmaps > 1 && p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) { + while (mipmaps2 > 1 && p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) { sw = MAX(sw >> 1, 1); sh = MAX(sh >> 1, 1); - mipmaps--; + mipmaps2--; idx++; } - if (idx > 0) { - ofs = Image::get_image_data_size(tw, th, format, idx - 1); - } + int ofs = Image::get_image_mipmap_offset(tw, th, format, idx); if (total_size - ofs <= 0) { memdelete(f); @@ -678,7 +693,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla int expected = total_size - ofs; if (bytes < expected) { - //this is a compatibility workaround for older format, which saved less mipmaps. It is still recommended the image is reimported. + //this is a compatibility workaround for older format, which saved less mipmaps2. It is still recommended the image is reimported. zeromem(w.ptr() + bytes, (expected - bytes)); } else if (bytes != expected) { ERR_FAIL_V(ERR_FILE_CORRUPT); @@ -696,22 +711,31 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla Error StreamTexture::load(const String &p_path) { - int lw, lh, lflags; + int lw, lh, lwc, lhc, lflags; Ref<Image> image; image.instance(); - Error err = _load_data(p_path, lw, lh, lflags, image); + Error err = _load_data(p_path, lw, lh, lwc, lhc, lflags, image); if (err) return err; + if (get_path() == String()) { + //temporarily set path if no path set for resource, helps find errors + VisualServer::get_singleton()->texture_set_path(texture, p_path); + } VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, image->get_format(), VS::TEXTURE_TYPE_2D, lflags); VS::get_singleton()->texture_set_data(texture, image); + if (lwc || lhc) { + VS::get_singleton()->texture_set_size_override(texture, lwc, lhc, 0); + } else { + } - w = lw; - h = lh; + w = lwc ? lwc : lw; + h = lhc ? lhc : lh; flags = lflags; path_to_file = p_path; format = image->get_format(); + _change_notify(); return OK; } String StreamTexture::get_load_path() const { @@ -774,6 +798,7 @@ bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const { decom->decompress(); img = decom; } + alpha_cache.instance(); alpha_cache->create_from_image_alpha(img); } @@ -791,7 +816,7 @@ bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const { int y = p_y * ah / h; x = CLAMP(x, 0, aw); - y = CLAMP(y, 0, aw); + y = CLAMP(y, 0, ah); return alpha_cache->get_bit(Point2(x, y)); } @@ -801,6 +826,7 @@ bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const { void StreamTexture::set_flags(uint32_t p_flags) { flags = p_flags; VS::get_singleton()->texture_set_flags(texture, flags); + _change_notify("flags"); } void StreamTexture::reload_from_file() { @@ -817,6 +843,12 @@ void StreamTexture::reload_from_file() { load(path); } +void StreamTexture::_validate_property(PropertyInfo &property) const { + if (property.name == "flags") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void StreamTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture::load); @@ -921,6 +953,7 @@ uint32_t AtlasTexture::get_flags() const { void AtlasTexture::set_atlas(const Ref<Texture> &p_atlas) { + ERR_FAIL_COND(p_atlas == this); if (atlas == p_atlas) return; atlas = p_atlas; @@ -1087,8 +1120,12 @@ bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const { if (!atlas.is_valid()) return true; - int x = p_x + region.position.x + margin.position.x; - int y = p_y + region.position.y + margin.position.y; + int x = p_x + region.position.x - margin.position.x; + int y = p_y + region.position.y - margin.position.y; + + // margin edge may outside of atlas + if (x < 0 || x >= atlas->get_width()) return false; + if (y < 0 || y >= atlas->get_height()) return false; return atlas->is_pixel_opaque(x, y); } @@ -1097,6 +1134,138 @@ AtlasTexture::AtlasTexture() { filter_clip = false; } +///////////////////////////////////////// + +int MeshTexture::get_width() const { + return size.width; +} +int MeshTexture::get_height() const { + return size.height; +} +RID MeshTexture::get_rid() const { + return RID(); +} + +bool MeshTexture::has_alpha() const { + return false; +} + +void MeshTexture::set_flags(uint32_t p_flags) { +} + +uint32_t MeshTexture::get_flags() const { + return 0; +} + +void MeshTexture::set_mesh(const Ref<Mesh> &p_mesh) { + mesh = p_mesh; +} +Ref<Mesh> MeshTexture::get_mesh() const { + return mesh; +} + +void MeshTexture::set_image_size(const Size2 &p_size) { + size = p_size; +} + +Size2 MeshTexture::get_image_size() const { + + return size; +} + +void MeshTexture::set_base_texture(const Ref<Texture> &p_texture) { + base_texture = p_texture; +} + +Ref<Texture> MeshTexture::get_base_texture() const { + return base_texture; +} + +void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const { + + if (mesh.is_null() || base_texture.is_null()) { + return; + } + Transform2D xform; + xform.set_origin(p_pos); + if (p_transpose) { + SWAP(xform.elements[0][1], xform.elements[1][0]); + SWAP(xform.elements[0][0], xform.elements[1][1]); + } + RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); + VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid); +} +void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const { + if (mesh.is_null() || base_texture.is_null()) { + return; + } + Transform2D xform; + Vector2 origin = p_rect.position; + if (p_rect.size.x < 0) { + origin.x += size.x; + } + if (p_rect.size.y < 0) { + origin.y += size.y; + } + xform.set_origin(origin); + xform.set_scale(p_rect.size / size); + + if (p_transpose) { + SWAP(xform.elements[0][1], xform.elements[1][0]); + SWAP(xform.elements[0][0], xform.elements[1][1]); + } + RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); + VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid); +} +void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const { + + if (mesh.is_null() || base_texture.is_null()) { + return; + } + Transform2D xform; + Vector2 origin = p_rect.position; + if (p_rect.size.x < 0) { + origin.x += size.x; + } + if (p_rect.size.y < 0) { + origin.y += size.y; + } + xform.set_origin(origin); + xform.set_scale(p_rect.size / size); + + if (p_transpose) { + SWAP(xform.elements[0][1], xform.elements[1][0]); + SWAP(xform.elements[0][0], xform.elements[1][1]); + } + RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); + VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid); +} +bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { + r_rect = p_rect; + r_src_rect = p_src_rect; + return true; +} + +bool MeshTexture::is_pixel_opaque(int p_x, int p_y) const { + return true; +} + +void MeshTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshTexture::set_mesh); + ClassDB::bind_method(D_METHOD("get_mesh"), &MeshTexture::get_mesh); + ClassDB::bind_method(D_METHOD("set_image_size", "size"), &MeshTexture::set_image_size); + ClassDB::bind_method(D_METHOD("get_image_size"), &MeshTexture::get_image_size); + ClassDB::bind_method(D_METHOD("set_base_texture", "texture"), &MeshTexture::set_base_texture); + ClassDB::bind_method(D_METHOD("get_base_texture"), &MeshTexture::get_base_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_base_texture", "get_base_texture"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1"), "set_image_size", "get_image_size"); +} + +MeshTexture::MeshTexture() { +} + ////////////////////////////////////////// int LargeTexture::get_width() const { @@ -1156,6 +1325,7 @@ void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) { void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture> &p_texture) { + ERR_FAIL_COND(p_texture == this); ERR_FAIL_INDEX(p_idx, pieces.size()); pieces.write[p_idx].texture = p_texture; }; @@ -1205,6 +1375,17 @@ Ref<Texture> LargeTexture::get_piece_texture(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, pieces.size(), Ref<Texture>()); return pieces[p_idx].texture; } +Ref<Image> LargeTexture::to_image() const { + + Ref<Image> img = memnew(Image(this->get_width(), this->get_height(), false, Image::FORMAT_RGBA8)); + for (int i = 0; i < pieces.size(); i++) { + + Ref<Image> src_img = pieces[i].texture->get_data(); + img->blit_rect(src_img, Rect2(0, 0, src_img->get_width(), src_img->get_height()), pieces[i].offset); + } + + return img; +} void LargeTexture::_bind_methods() { @@ -1474,6 +1655,7 @@ CubeMap::CubeMap() { cubemap = VisualServer::get_singleton()->texture_create(); storage = STORAGE_RAW; lossy_storage_quality = 0.7; + format = Image::FORMAT_BPTC_RGBA; } CubeMap::~CubeMap() { @@ -1710,6 +1892,7 @@ void ProxyTexture::_bind_methods() { void ProxyTexture::set_base(const Ref<Texture> &p_texture) { + ERR_FAIL_COND(p_texture == this); base = p_texture; if (base.is_valid()) { VS::get_singleton()->texture_set_proxy(proxy, base->get_rid()); @@ -1825,6 +2008,8 @@ int AnimatedTexture::get_frames() const { } void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture> &p_texture) { + + ERR_FAIL_COND(p_texture == this); ERR_FAIL_INDEX(p_frame, MAX_FRAMES); RWLockWrite w(rw_lock); @@ -1960,9 +2145,11 @@ void AnimatedTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps"); for (int i = 0; i < MAX_FRAMES; i++) { - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i); } + + BIND_CONSTANT(MAX_FRAMES); } AnimatedTexture::AnimatedTexture() { @@ -2067,7 +2254,7 @@ void TextureLayered::create(uint32_t p_width, uint32_t p_height, uint32_t p_dept width = p_width; height = p_height; depth = p_depth; - + format = p_format; flags = p_flags; } @@ -2312,3 +2499,107 @@ String ResourceFormatLoaderTextureLayered::get_resource_type(const String &p_pat return "TextureArray"; return ""; } + +void CameraTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_camera_feed_id", "feed_id"), &CameraTexture::set_camera_feed_id); + ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &CameraTexture::get_camera_feed_id); + + ClassDB::bind_method(D_METHOD("set_which_feed", "which_feed"), &CameraTexture::set_which_feed); + ClassDB::bind_method(D_METHOD("get_which_feed"), &CameraTexture::get_which_feed); + + ClassDB::bind_method(D_METHOD("set_camera_active", "active"), &CameraTexture::set_camera_active); + ClassDB::bind_method(D_METHOD("get_camera_active"), &CameraTexture::get_camera_active); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "camera_feed_id"), "set_camera_feed_id", "get_camera_feed_id"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "which_feed"), "set_which_feed", "get_which_feed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "camera_is_active"), "set_camera_active", "get_camera_active"); +} + +int CameraTexture::get_width() const { + Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); + if (feed.is_valid()) { + return feed->get_base_width(); + } else { + return 0; + } +} + +int CameraTexture::get_height() const { + Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); + if (feed.is_valid()) { + return feed->get_base_height(); + } else { + return 0; + } +} + +bool CameraTexture::has_alpha() const { + return false; +} + +RID CameraTexture::get_rid() const { + Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); + if (feed.is_valid()) { + return feed->get_texture(which_feed); + } else { + return RID(); + } +} + +void CameraTexture::set_flags(uint32_t p_flags) { + // not supported +} + +uint32_t CameraTexture::get_flags() const { + // not supported + return 0; +} + +Ref<Image> CameraTexture::get_data() const { + // not (yet) supported + return Ref<Image>(); +} + +void CameraTexture::set_camera_feed_id(int p_new_id) { + camera_feed_id = p_new_id; + _change_notify(); +} + +int CameraTexture::get_camera_feed_id() const { + return camera_feed_id; +} + +void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) { + which_feed = p_which; + _change_notify(); +} + +CameraServer::FeedImage CameraTexture::get_which_feed() const { + return which_feed; +} + +void CameraTexture::set_camera_active(bool p_active) { + Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); + if (feed.is_valid()) { + feed->set_active(p_active); + _change_notify(); + } +} + +bool CameraTexture::get_camera_active() const { + Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); + if (feed.is_valid()) { + return feed->is_active(); + } else { + return false; + } +} + +CameraTexture::CameraTexture() { + camera_feed_id = 0; + which_feed = CameraServer::FEED_RGBA_IMAGE; +} + +CameraTexture::~CameraTexture() { + // nothing to do here yet +} diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 845a075015..eb7a9ff25c 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -37,8 +37,9 @@ #include "core/os/rw_lock.h" #include "core/os/thread_safe.h" #include "core/resource.h" -#include "scene/resources/color_ramp.h" #include "scene/resources/curve.h" +#include "scene/resources/gradient.h" +#include "servers/camera_server.h" #include "servers/visual_server.h" /** @@ -111,6 +112,7 @@ private: Size2 size_override; float lossy_storage_quality; mutable Ref<BitMap> alpha_cache; + bool image_stored; protected: virtual void reload_from_file(); @@ -186,7 +188,7 @@ public: }; private: - Error _load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit = 0); + Error _load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, int &flags, Ref<Image> &image, int p_size_limit = 0); String path_to_file; RID texture; Image::Format format; @@ -202,6 +204,7 @@ private: protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; public: typedef void (*TextureFormatRequestCallback)(const Ref<StreamTexture> &); @@ -236,7 +239,6 @@ public: }; class ResourceFormatLoaderStreamTexture : public ResourceFormatLoader { - GDCLASS(ResourceFormatLoaderStreamTexture, 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; @@ -291,6 +293,49 @@ public: AtlasTexture(); }; +class Mesh; + +class MeshTexture : public Texture { + + GDCLASS(MeshTexture, Texture); + RES_BASE_EXTENSION("meshtex"); + + Ref<Texture> base_texture; + Ref<Mesh> mesh; + Size2i size; + +protected: + static void _bind_methods(); + +public: + virtual int get_width() const; + virtual int get_height() const; + virtual RID get_rid() const; + + virtual bool has_alpha() const; + + virtual void set_flags(uint32_t p_flags); + virtual uint32_t get_flags() const; + + void set_mesh(const Ref<Mesh> &p_mesh); + Ref<Mesh> get_mesh() const; + + void set_image_size(const Size2 &p_size); + Size2 get_image_size() const; + + void set_base_texture(const Ref<Texture> &p_texture); + Ref<Texture> get_base_texture() const; + + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; + virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const; + virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const; + + bool is_pixel_opaque(int p_x, int p_y) const; + + MeshTexture(); +}; + class LargeTexture : public Texture { GDCLASS(LargeTexture, Texture); @@ -330,6 +375,7 @@ public: int get_piece_count() const; Vector2 get_piece_offset(int p_idx) const; Ref<Texture> get_piece_texture(int p_idx) const; + Ref<Image> to_image() const; virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; @@ -423,7 +469,7 @@ VARIANT_ENUM_CAST(CubeMap::Storage) class TextureLayered : public Resource { - GDCLASS(TextureLayered, Resource) + GDCLASS(TextureLayered, Resource); public: enum Flags { @@ -475,7 +521,8 @@ VARIANT_ENUM_CAST(TextureLayered::Flags) class Texture3D : public TextureLayered { - GDCLASS(Texture3D, TextureLayered) + GDCLASS(Texture3D, TextureLayered); + public: Texture3D() : TextureLayered(true) {} @@ -483,14 +530,14 @@ public: class TextureArray : public TextureLayered { - GDCLASS(TextureArray, TextureLayered) + GDCLASS(TextureArray, TextureLayered); + public: TextureArray() : TextureLayered(false) {} }; class ResourceFormatLoaderTextureLayered : public ResourceFormatLoader { - GDCLASS(ResourceFormatLoaderTextureLayered, ResourceFormatLoader) public: enum Compression { COMPRESSION_LOSSLESS, @@ -506,7 +553,7 @@ public: class CurveTexture : public Texture { - GDCLASS(CurveTexture, Texture) + GDCLASS(CurveTexture, Texture); RES_BASE_EXTENSION("curvetex") private: @@ -554,7 +601,7 @@ public: //VARIANT_ENUM_CAST( Texture::CubeMapSide ); class GradientTexture : public Texture { - GDCLASS(GradientTexture, Texture) + GDCLASS(GradientTexture, Texture); public: struct Point { @@ -599,7 +646,7 @@ public: }; class ProxyTexture : public Texture { - GDCLASS(ProxyTexture, Texture) + GDCLASS(ProxyTexture, Texture); private: RID proxy; @@ -626,7 +673,7 @@ public: }; class AnimatedTexture : public Texture { - GDCLASS(AnimatedTexture, Texture) + GDCLASS(AnimatedTexture, Texture); //use readers writers lock for this, since its far more times read than written to RWLock *rw_lock; @@ -694,4 +741,38 @@ public: ~AnimatedTexture(); }; +class CameraTexture : public Texture { + GDCLASS(CameraTexture, Texture); + +private: + int camera_feed_id; + CameraServer::FeedImage which_feed; + +protected: + static void _bind_methods(); + +public: + virtual int get_width() const; + virtual int get_height() const; + virtual RID get_rid() const; + virtual bool has_alpha() const; + + virtual void set_flags(uint32_t p_flags); + virtual uint32_t get_flags() const; + + virtual Ref<Image> get_data() const; + + void set_camera_feed_id(int p_new_id); + int get_camera_feed_id() const; + + void set_which_feed(CameraServer::FeedImage p_which); + CameraServer::FeedImage get_which_feed() const; + + void set_camera_active(bool p_active); + bool get_camera_active() const; + + CameraTexture(); + ~CameraTexture(); +}; + #endif diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 3eb652ecd9..69258bc834 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -621,44 +621,48 @@ void Theme::clear() { void Theme::copy_default_theme() { - Ref<Theme> default_theme = get_default(); + Ref<Theme> default_theme2 = get_default(); + copy_theme(default_theme2); +} + +void Theme::copy_theme(const Ref<Theme> &p_other) { //these need reconnecting, so add normally { const StringName *K = NULL; - while ((K = default_theme->icon_map.next(K))) { + while ((K = p_other->icon_map.next(K))) { const StringName *L = NULL; - while ((L = default_theme->icon_map[*K].next(L))) { - set_icon(*K, *L, default_theme->icon_map[*K][*L]); + while ((L = p_other->icon_map[*K].next(L))) { + set_icon(*L, *K, p_other->icon_map[*K][*L]); } } } { const StringName *K = NULL; - while ((K = default_theme->style_map.next(K))) { + while ((K = p_other->style_map.next(K))) { const StringName *L = NULL; - while ((L = default_theme->style_map[*K].next(L))) { - set_stylebox(*K, *L, default_theme->style_map[*K][*L]); + while ((L = p_other->style_map[*K].next(L))) { + set_stylebox(*L, *K, p_other->style_map[*K][*L]); } } } { const StringName *K = NULL; - while ((K = default_theme->font_map.next(K))) { + while ((K = p_other->font_map.next(K))) { const StringName *L = NULL; - while ((L = default_theme->font_map[*K].next(L))) { - set_font(*K, *L, default_theme->font_map[*K][*L]); + while ((L = p_other->font_map[*K].next(L))) { + set_font(*L, *K, p_other->font_map[*K][*L]); } } } //these are ok to just copy - color_map = default_theme->color_map; - constant_map = default_theme->constant_map; - shader_map = default_theme->shader_map; + color_map = p_other->color_map; + constant_map = p_other->constant_map; + shader_map = p_other->shader_map; _change_notify(); emit_changed(); @@ -752,6 +756,7 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("_emit_theme_changed"), &Theme::_emit_theme_changed); ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme); + ClassDB::bind_method(D_METHOD("copy_theme", "other"), &Theme::copy_theme); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font"); } diff --git a/scene/resources/theme.h b/scene/resources/theme.h index ba47c5fb3c..fb59073cbe 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -184,6 +184,7 @@ public: void get_type_list(List<StringName> *p_list) const; void copy_default_theme(); + void copy_theme(const Ref<Theme> &p_other); void clear(); Theme(); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 8a24d4bab1..d09fac47f0 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -30,6 +30,7 @@ #include "tile_set.h" #include "core/array.h" +#include "core/engine.h" bool TileSet::_set(const StringName &p_name, const Variant &p_value) { @@ -154,6 +155,8 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { tile_set_shape_transform(id, 0, p_value); else if (what == "shape_one_way") tile_set_shape_one_way(id, 0, p_value); + else if (what == "shape_one_way_margin") + tile_set_shape_one_way_margin(id, 0, p_value); else if (what == "shapes") _tile_set_shapes(id, p_value); else if (what == "occluder") @@ -212,7 +215,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = autotile_get_spacing(id); else if (what == "bitmask_flags") { Array p; - for (Map<Vector2, uint16_t>::Element *E = tile_map[id].autotile_data.flags.front(); E; E = E->next()) { + for (Map<Vector2, uint32_t>::Element *E = tile_map[id].autotile_data.flags.front(); E; E = E->next()) { p.push_back(E->key()); p.push_back(E->value()); } @@ -266,6 +269,8 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = tile_get_shape_transform(id, 0); else if (what == "shape_one_way") r_ret = tile_get_shape_one_way(id, 0); + else if (what == "shape_one_way_margin") + r_ret = tile_get_shape_one_way_margin(id, 0); else if (what == "shapes") r_ret = _tile_get_shapes(id); else if (what == "occluder") @@ -314,6 +319,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/z_index_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); } p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "occluder_offset")); @@ -324,6 +330,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, pre + "shape_one_way", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::REAL, pre + "shape_one_way_margin", PROPERTY_HINT_RANGE, "0,128,0.01", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "shapes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::INT, pre + "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1")); } @@ -507,6 +514,13 @@ int TileSet::autotile_get_subtile_priority(int p_id, const Vector2 &p_coord) { return 1; } +const Map<Vector2, int> &TileSet::autotile_get_priority_map(int p_id) const { + + static Map<Vector2, int> dummy; + ERR_FAIL_COND_V(!tile_map.has(p_id), dummy); + return tile_map[p_id].autotile_data.priority_map; +} + void TileSet::autotile_set_z_index(int p_id, const Vector2 &p_coord, int p_z_index) { ERR_FAIL_COND(!tile_map.has(p_id)); @@ -524,14 +538,14 @@ int TileSet::autotile_get_z_index(int p_id, const Vector2 &p_coord) { return 0; } -const Map<Vector2, int> &TileSet::autotile_get_priority_map(int p_id) const { +const Map<Vector2, int> &TileSet::autotile_get_z_index_map(int p_id) const { static Map<Vector2, int> dummy; ERR_FAIL_COND_V(!tile_map.has(p_id), dummy); - return tile_map[p_id].autotile_data.priority_map; + return tile_map[p_id].autotile_data.z_index_map; } -void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag) { +void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag) { ERR_FAIL_COND(!tile_map.has(p_id)); if (p_flag == 0) { @@ -542,7 +556,7 @@ void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag) { } } -uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) { +uint32_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) { ERR_FAIL_COND_V(!tile_map.has(p_id), 0); if (!tile_map[p_id].autotile_data.flags.has(p_coord)) { @@ -551,13 +565,13 @@ uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) { return tile_map[p_id].autotile_data.flags[p_coord]; } -const Map<Vector2, uint16_t> &TileSet::autotile_get_bitmask_map(int p_id) { +const Map<Vector2, uint32_t> &TileSet::autotile_get_bitmask_map(int p_id) { - static Map<Vector2, uint16_t> dummy; - static Map<Vector2, uint16_t> dummy_atlas; + static Map<Vector2, uint32_t> dummy; + static Map<Vector2, uint32_t> dummy_atlas; ERR_FAIL_COND_V(!tile_map.has(p_id), dummy); if (tile_get_tile_mode(p_id) == ATLAS_TILE) { - dummy_atlas = Map<Vector2, uint16_t>(); + dummy_atlas = Map<Vector2, uint32_t>(); Rect2 region = tile_get_region(p_id); Size2 size = autotile_get_size(p_id); float spacing = autotile_get_spacing(p_id); @@ -587,15 +601,72 @@ Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, } List<Vector2> coords; - uint16_t mask; - for (Map<Vector2, uint16_t>::Element *E = tile_map[p_id].autotile_data.flags.front(); E; E = E->next()) { + List<uint32_t> priorities; + uint32_t priority_sum = 0; + uint32_t mask; + uint16_t mask_; + uint16_t mask_ignore; + for (Map<Vector2, uint32_t>::Element *E = tile_map[p_id].autotile_data.flags.front(); E; E = E->next()) { mask = E->get(); if (tile_map[p_id].autotile_data.bitmask_mode == BITMASK_2X2) { - mask &= (BIND_BOTTOMLEFT | BIND_BOTTOMRIGHT | BIND_TOPLEFT | BIND_TOPRIGHT); + mask |= (BIND_IGNORE_TOP | BIND_IGNORE_LEFT | BIND_IGNORE_CENTER | BIND_IGNORE_RIGHT | BIND_IGNORE_BOTTOM); + } + + mask_ = mask & 0xFFFF; + mask_ignore = mask >> 16; + + if (((mask_ & (~mask_ignore)) == (p_bitmask & (~mask_ignore))) && (((~mask_) | mask_ignore) == ((~p_bitmask) | mask_ignore))) { + uint32_t priority = autotile_get_subtile_priority(p_id, E->key()); + priority_sum += priority; + priorities.push_back(priority); + coords.push_back(E->key()); + } + } + + if (coords.size() == 0) { + return autotile_get_icon_coordinate(p_id); + } else { + uint32_t picked_value = Math::rand() % priority_sum; + uint32_t upper_bound; + uint32_t lower_bound = 0; + Vector2 result = coords.front()->get(); + List<Vector2>::Element *coords_E = coords.front(); + List<uint32_t>::Element *priorities_E = priorities.front(); + while (priorities_E) { + upper_bound = lower_bound + priorities_E->get(); + if (lower_bound <= picked_value && picked_value < upper_bound) { + result = coords_E->get(); + break; + } + lower_bound = upper_bound; + priorities_E = priorities_E->next(); + coords_E = coords_E->next(); + } + + return result; + } +} + +Vector2 TileSet::atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node, const Vector2 &p_tile_location) { + + ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2()); + //First try to forward selection to script + if (get_script_instance() != NULL) { + if (get_script_instance()->has_method("_forward_atlas_subtile_selection")) { + Variant ret = get_script_instance()->call("_forward_atlas_subtile_selection", p_id, p_tilemap_node, p_tile_location); + if (ret.get_type() == Variant::VECTOR2) { + return ret; + } } - if (mask == p_bitmask) { - for (int i = 0; i < autotile_get_subtile_priority(p_id, E->key()); i++) { - coords.push_back(E->key()); + } + + Vector2 coord = tile_get_region(p_id).size / autotile_get_size(p_id); + + List<Vector2> coords; + for (int x = 0; x < coord.x; x++) { + for (int y = 0; y < coord.y; y++) { + for (int i = 0; i < autotile_get_subtile_priority(p_id, Vector2(x, y)); i++) { + coords.push_back(Vector2(x, y)); } } } @@ -650,6 +721,7 @@ void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_sha if (tile_map[p_id].shapes_data.size() <= p_shape_id) tile_map[p_id].shapes_data.resize(p_shape_id + 1); tile_map[p_id].shapes_data.write[p_shape_id].shape = p_shape; + _decompose_convex_shape(p_shape); emit_changed(); } @@ -708,6 +780,22 @@ bool TileSet::tile_get_shape_one_way(int p_id, int p_shape_id) const { return false; } +void TileSet::tile_set_shape_one_way_margin(int p_id, int p_shape_id, float p_margin) { + ERR_FAIL_COND(!tile_map.has(p_id)); + if (tile_map[p_id].shapes_data.size() <= p_shape_id) + tile_map[p_id].shapes_data.resize(p_shape_id + 1); + tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision_margin = p_margin; + emit_changed(); +} + +float TileSet::tile_get_shape_one_way_margin(int p_id, int p_shape_id) const { + ERR_FAIL_COND_V(!tile_map.has(p_id), 0); + if (tile_map[p_id].shapes_data.size() > p_shape_id) + return tile_map[p_id].shapes_data[p_shape_id].one_way_collision_margin; + + return 0; +} + void TileSet::tile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> &p_light_occluder) { ERR_FAIL_COND(!tile_map.has(p_id)); @@ -816,6 +904,9 @@ void TileSet::tile_set_shapes(int p_id, const Vector<ShapeData> &p_shapes) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].shapes_data = p_shapes; + for (int i = 0; i < p_shapes.size(); i++) { + _decompose_convex_shape(p_shapes[i].shape); + } emit_changed(); } @@ -860,9 +951,10 @@ void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) { } else if (p_shapes[i].get_type() == Variant::DICTIONARY) { Dictionary d = p_shapes[i]; - if (d.has("shape") && d["shape"].get_type() == Variant::OBJECT) + if (d.has("shape") && d["shape"].get_type() == Variant::OBJECT) { s.shape = d["shape"]; - else + _decompose_convex_shape(s.shape); + } else continue; if (d.has("shape_transform") && d["shape_transform"].get_type() == Variant::TRANSFORM2D) @@ -877,6 +969,11 @@ void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) { else s.one_way_collision = default_one_way; + if (d.has("one_way_margin") && d["one_way_margin"].is_num()) + s.one_way_collision_margin = d["one_way_margin"]; + else + s.one_way_collision_margin = 1.0; + if (d.has("autotile_coord") && d["autotile_coord"].get_type() == Variant::VECTOR2) s.autotile_coord = d["autotile_coord"]; else @@ -904,6 +1001,7 @@ Array TileSet::_tile_get_shapes(int p_id) const { shape_data["shape"] = data[i].shape; shape_data["shape_transform"] = data[i].shape_transform; shape_data["one_way"] = data[i].one_way_collision; + shape_data["one_way_margin"] = data[i].one_way_collision_margin; shape_data["autotile_coord"] = data[i].autotile_coord; arr.push_back(shape_data); } @@ -922,6 +1020,26 @@ Array TileSet::_get_tiles_ids() const { return arr; } +void TileSet::_decompose_convex_shape(Ref<Shape2D> p_shape) { + if (Engine::get_singleton()->is_editor_hint()) + return; + Ref<ConvexPolygonShape2D> convex = p_shape; + if (!convex.is_valid()) + return; + Vector<Vector<Vector2> > decomp = Geometry::decompose_polygon_in_convex(convex->get_points()); + if (decomp.size() > 1) { + Array sub_shapes; + for (int i = 0; i < decomp.size(); i++) { + Ref<ConvexPolygonShape2D> _convex = memnew(ConvexPolygonShape2D); + _convex->set_points(decomp[i]); + sub_shapes.append(_convex); + } + convex->set_meta("decomposed", sub_shapes); + } else { + convex->set_meta("decomposed", Variant()); + } +} + void TileSet::get_tile_list(List<int> *p_tiles) const { for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) { @@ -986,8 +1104,23 @@ void TileSet::clear() { void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("create_tile", "id"), &TileSet::create_tile); + ClassDB::bind_method(D_METHOD("autotile_clear_bitmask_map", "id"), &TileSet::autotile_clear_bitmask_map); + ClassDB::bind_method(D_METHOD("autotile_set_icon_coordinate", "id", "coord"), &TileSet::autotile_set_icon_coordinate); + ClassDB::bind_method(D_METHOD("autotile_get_icon_coordinate", "id"), &TileSet::autotile_get_icon_coordinate); + ClassDB::bind_method(D_METHOD("autotile_set_subtile_priority", "id", "coord", "priority"), &TileSet::autotile_set_subtile_priority); + ClassDB::bind_method(D_METHOD("autotile_get_subtile_priority", "id", "coord"), &TileSet::autotile_get_subtile_priority); + ClassDB::bind_method(D_METHOD("autotile_set_z_index", "id", "coord", "z_index"), &TileSet::autotile_set_z_index); + ClassDB::bind_method(D_METHOD("autotile_get_z_index", "id", "coord"), &TileSet::autotile_get_z_index); + ClassDB::bind_method(D_METHOD("autotile_set_light_occluder", "id", "light_occluder", "coord"), &TileSet::autotile_set_light_occluder); + ClassDB::bind_method(D_METHOD("autotile_get_light_occluder", "id", "coord"), &TileSet::autotile_get_light_occluder); + ClassDB::bind_method(D_METHOD("autotile_set_navigation_polygon", "id", "navigation_polygon", "coord"), &TileSet::autotile_set_navigation_polygon); + ClassDB::bind_method(D_METHOD("autotile_get_navigation_polygon", "id", "coord"), &TileSet::autotile_get_navigation_polygon); + ClassDB::bind_method(D_METHOD("autotile_set_bitmask", "id", "bitmask", "flag"), &TileSet::autotile_set_bitmask); + ClassDB::bind_method(D_METHOD("autotile_get_bitmask", "id", "coord"), &TileSet::autotile_get_bitmask); ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "id", "mode"), &TileSet::autotile_set_bitmask_mode); ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode", "id"), &TileSet::autotile_get_bitmask_mode); + ClassDB::bind_method(D_METHOD("autotile_set_spacing", "id", "spacing"), &TileSet::autotile_set_spacing); + ClassDB::bind_method(D_METHOD("autotile_get_spacing", "id"), &TileSet::autotile_get_spacing); ClassDB::bind_method(D_METHOD("autotile_set_size", "id", "size"), &TileSet::autotile_set_size); ClassDB::bind_method(D_METHOD("autotile_get_size", "id"), &TileSet::autotile_get_size); ClassDB::bind_method(D_METHOD("tile_set_name", "id", "name"), &TileSet::tile_set_name); @@ -1012,6 +1145,8 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("tile_get_shape_transform", "id", "shape_id"), &TileSet::tile_get_shape_transform); ClassDB::bind_method(D_METHOD("tile_set_shape_one_way", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way); ClassDB::bind_method(D_METHOD("tile_get_shape_one_way", "id", "shape_id"), &TileSet::tile_get_shape_one_way); + ClassDB::bind_method(D_METHOD("tile_set_shape_one_way_margin", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way_margin); + ClassDB::bind_method(D_METHOD("tile_get_shape_one_way_margin", "id", "shape_id"), &TileSet::tile_get_shape_one_way_margin); ClassDB::bind_method(D_METHOD("tile_add_shape", "id", "shape", "shape_transform", "one_way", "autotile_coord"), &TileSet::tile_add_shape, DEFVAL(false), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("tile_get_shape_count", "id"), &TileSet::tile_get_shape_count); ClassDB::bind_method(D_METHOD("tile_set_shapes", "id", "shapes"), &TileSet::_tile_set_shapes); @@ -1037,6 +1172,7 @@ void TileSet::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_tile_bound", PropertyInfo(Variant::INT, "drawn_id"), PropertyInfo(Variant::INT, "neighbor_id"))); BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location"))); + BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_atlas_subtile_selection", PropertyInfo(Variant::INT, "atlastile_id"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location"))); BIND_ENUM_CONSTANT(BITMASK_2X2); BIND_ENUM_CONSTANT(BITMASK_3X3_MINIMAL); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 2ab771b1b0..5fc22b9fc6 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -35,6 +35,7 @@ #include "core/resource.h" #include "scene/2d/light_occluder_2d.h" #include "scene/2d/navigation_polygon.h" +#include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/shape_2d.h" #include "scene/resources/texture.h" @@ -48,9 +49,11 @@ public: Transform2D shape_transform; Vector2 autotile_coord; bool one_way_collision; + float one_way_collision_margin; ShapeData() { one_way_collision = false; + one_way_collision_margin = 1.0; } }; @@ -69,7 +72,17 @@ public: BIND_RIGHT = 32, BIND_BOTTOMLEFT = 64, BIND_BOTTOM = 128, - BIND_BOTTOMRIGHT = 256 + BIND_BOTTOMRIGHT = 256, + + BIND_IGNORE_TOPLEFT = 1 << 16, + BIND_IGNORE_TOP = 1 << 17, + BIND_IGNORE_TOPRIGHT = 1 << 18, + BIND_IGNORE_LEFT = 1 << 19, + BIND_IGNORE_CENTER = 1 << 20, + BIND_IGNORE_RIGHT = 1 << 21, + BIND_IGNORE_BOTTOMLEFT = 1 << 22, + BIND_IGNORE_BOTTOM = 1 << 23, + BIND_IGNORE_BOTTOMRIGHT = 1 << 24 }; enum TileMode { @@ -83,7 +96,7 @@ public: Size2 size; int spacing; Vector2 icon_coord; - Map<Vector2, uint16_t> flags; + Map<Vector2, uint32_t> flags; Map<Vector2, Ref<OccluderPolygon2D> > occluder_map; Map<Vector2, Ref<NavigationPolygon> > navpoly_map; Map<Vector2, int> priority_map; @@ -132,6 +145,7 @@ protected: void _tile_set_shapes(int p_id, const Array &p_shapes); Array _tile_get_shapes(int p_id) const; Array _get_tiles_ids() const; + void _decompose_convex_shape(Ref<Shape2D> p_shape); static void _bind_methods(); @@ -175,11 +189,13 @@ public: void autotile_set_z_index(int p_id, const Vector2 &p_coord, int p_z_index); int autotile_get_z_index(int p_id, const Vector2 &p_coord); + const Map<Vector2, int> &autotile_get_z_index_map(int p_id) const; - void autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag); - uint16_t autotile_get_bitmask(int p_id, Vector2 p_coord); - const Map<Vector2, uint16_t> &autotile_get_bitmask_map(int p_id); + void autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag); + uint32_t autotile_get_bitmask(int p_id, Vector2 p_coord); + const Map<Vector2, uint32_t> &autotile_get_bitmask_map(int p_id); Vector2 autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node = NULL, const Vector2 &p_tile_location = Vector2()); + Vector2 atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node = NULL, const Vector2 &p_tile_location = Vector2()); void tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape); Ref<Shape2D> tile_get_shape(int p_id, int p_shape_id) const; @@ -193,6 +209,9 @@ public: void tile_set_shape_one_way(int p_id, int p_shape_id, bool p_one_way); bool tile_get_shape_one_way(int p_id, int p_shape_id) const; + void tile_set_shape_one_way_margin(int p_id, int p_shape_id, float p_margin); + float tile_get_shape_one_way_margin(int p_id, int p_shape_id) const; + void tile_clear_shapes(int p_id); void tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Transform2D &p_transform, bool p_one_way = false, const Vector2 &p_autotile_coord = Vector2()); int tile_get_shape_count(int p_id) const; diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp index 3cd8cbae77..a85db0c592 100644 --- a/scene/resources/video_stream.cpp +++ b/scene/resources/video_stream.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h index 0d25d9d687..eb3bf6770f 100644 --- a/scene/resources/video_stream.h +++ b/scene/resources/video_stream.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 3d247ab7ad..dd595d9ff8 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "visual_shader.h" + #include "core/vmap.h" #include "servers/visual/shader_types.h" @@ -159,6 +160,7 @@ Vector2 VisualShader::get_node_position(Type p_type, int p_id) const { ERR_FAIL_COND_V(!g->nodes.has(p_id), Vector2()); return g->nodes[p_id].position; } + Ref<VisualShaderNode> VisualShader::get_node(Type p_type, int p_id) const { ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Ref<VisualShaderNode>()); const Graph *g = &graph[p_type]; @@ -240,6 +242,9 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po if (!g->nodes.has(p_from_node)) return false; + if (p_from_node == p_to_node) + return false; + if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_output_port_count()) return false; @@ -252,7 +257,7 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port); VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port); - if (MAX(0, from_port_type - 1) != (MAX(0, to_port_type - 1))) { + if (MAX(0, from_port_type - 2) != (MAX(0, to_port_type - 2))) { return false; } @@ -266,6 +271,18 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po return true; } +void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { + ERR_FAIL_INDEX(p_type, TYPE_MAX); + Graph *g = &graph[p_type]; + Connection c; + c.from_node = p_from_node; + c.from_port = p_from_port; + c.to_node = p_to_node; + c.to_port = p_to_port; + g->connections.push_back(c); + _queue_update(); +} + Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { ERR_FAIL_INDEX_V(p_type, TYPE_MAX, ERR_CANT_CONNECT); Graph *g = &graph[p_type]; @@ -278,9 +295,9 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port); VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port); - if (MAX(0, from_port_type - 1) != (MAX(0, to_port_type - 1))) { - ERR_EXPLAIN("Incompatible port types (scalar/vec with transform"); - ERR_FAIL_V(ERR_INVALID_PARAMETER) + if (MAX(0, from_port_type - 2) != (MAX(0, to_port_type - 2))) { + ERR_EXPLAIN("Incompatible port types (scalar/vec/bool with transform"); + ERR_FAIL_V(ERR_INVALID_PARAMETER); return ERR_INVALID_PARAMETER; } @@ -301,6 +318,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, _queue_update(); return OK; } + void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { ERR_FAIL_INDEX(p_type, TYPE_MAX); Graph *g = &graph[p_type]; @@ -331,6 +349,7 @@ Array VisualShader::_get_node_connections(Type p_type) const { return ret; } + void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connections) const { ERR_FAIL_INDEX(p_type, TYPE_MAX); const Graph *g = &graph[p_type]; @@ -456,6 +475,8 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR) { code += "\tCOLOR.rgb = vec3( n_out" + itos(p_node) + "p" + itos(p_port) + " );\n"; + } else if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_BOOLEAN) { + code += "\tCOLOR.rgb = vec3( n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0 );\n"; } else { code += "\tCOLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n"; } @@ -472,6 +493,54 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port #define IS_SYMBOL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z') || ((m_d) >= '0' && (m_d) <= '9') || (m_d) == '_') +String VisualShader::validate_port_name(const String &p_name, const List<String> &p_input_ports, const List<String> &p_output_ports) const { + String name = p_name; + + while (name.length() && !IS_INITIAL_CHAR(name[0])) { + name = name.substr(1, name.length() - 1); + } + + if (name != String()) { + + String valid_name; + + for (int i = 0; i < name.length(); i++) { + if (IS_SYMBOL_CHAR(name[i])) { + valid_name += String::chr(name[i]); + } else if (name[i] == ' ') { + valid_name += "_"; + } + } + + name = valid_name; + } + + String valid_name = name; + bool is_equal = false; + + for (int i = 0; i < p_input_ports.size(); i++) { + if (name == p_input_ports[i]) { + is_equal = true; + break; + } + } + + if (!is_equal) { + for (int i = 0; i < p_output_ports.size(); i++) { + if (name == p_output_ports[i]) { + is_equal = true; + break; + } + } + } + + if (is_equal) { + name = ""; + } + + return name; +} + String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const { String name = p_name; //validate name first @@ -569,7 +638,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { String mode = name.get_slicec('/', 1); int value = p_value; if (value == 0) { - modes.erase(mode); //means its default anyway, so dont store it + modes.erase(mode); //means it's default anyway, so don't store it } else { modes[mode] = value; } @@ -591,7 +660,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { Vector<int> conns = p_value; if (conns.size() % 4 == 0) { for (int i = 0; i < conns.size(); i += 4) { - connect_nodes(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]); + connect_nodes_forced(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]); } } return true; @@ -606,6 +675,18 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { } else if (what == "position") { set_node_position(type, id, p_value); return true; + } else if (what == "size") { + ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_size(p_value); + return true; + } else if (what == "input_ports") { + ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_inputs(p_value); + return true; + } else if (what == "output_ports") { + ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_outputs(p_value); + return true; + } else if (what == "expression") { + ((VisualShaderNodeExpression *)get_node(type, id).ptr())->set_expression(p_value); + return true; } } return false; @@ -663,6 +744,18 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const { } else if (what == "position") { r_ret = get_node_position(type, id); return true; + } else if (what == "size") { + r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_size(); + return true; + } else if (what == "input_ports") { + r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_inputs(); + return true; + } else if (what == "output_ports") { + r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_outputs(); + return true; + } else if (what == "expression") { + r_ret = ((VisualShaderNodeExpression *)get_node(type, id).ptr())->get_expression(); + return true; } } return false; @@ -722,6 +815,15 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); } p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + + if (Object::cast_to<VisualShaderNodeGroupBase>(E->get().node.ptr()) != NULL) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/input_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + } + if (Object::cast_to<VisualShaderNodeExpression>(E->get().node.ptr()) != NULL) { + p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + } } p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "nodes/" + String(type_string[i]) + "/connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); } @@ -779,6 +881,14 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui inputs[i] = "dot(" + src_var + ",vec3(0.333333,0.333333,0.333333))"; } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_SCALAR) { inputs[i] = "vec3(" + src_var + ")"; + } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_VECTOR) { + inputs[i] = "all(bvec3(" + src_var + "))"; + } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_SCALAR) { + inputs[i] = src_var + ">0.0?true:false"; + } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { + inputs[i] = src_var + "?1.0:0.0"; + } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { + inputs[i] = "vec3(" + src_var + "?1.0:0.0)"; } } else { @@ -787,6 +897,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui float val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n"; + } else if (defval.get_type() == Variant::BOOL) { + bool val = defval; + inputs[i] = "n_in" + itos(node) + "p" + itos(i); + code += "\nbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n"; } else if (defval.get_type() == Variant::VECTOR3) { Vector3 val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); @@ -823,8 +937,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui switch (vsnode->get_output_port_type(i)) { case VisualShaderNode::PORT_TYPE_SCALAR: code += String() + "\tfloat " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_VECTOR: code += String() + "\tvec3 " + outputs[i] + ";\n"; break; + case VisualShaderNode::PORT_TYPE_BOOLEAN: code += String() + "\tbool " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_TRANSFORM: code += String() + "\tmat4 " + outputs[i] + ";\n"; break; - default: {} + default: { + } } } @@ -834,15 +950,15 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } Ref<VisualShaderNodeInput> input = vsnode; + bool skip_global = input.is_valid() && for_preview; - if (input.is_valid() && for_preview) { - //handle for preview - code += input->generate_code_for_preview(type, node, inputs, outputs); - } else { - //handle normally + if (!skip_global) { global_code += vsnode->generate_global(get_mode(), type, node); - code += vsnode->generate_code(get_mode(), type, node, inputs, outputs); } + + //handle normally + code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); + code += "\n"; // processed.insert(node); @@ -974,26 +1090,33 @@ void VisualShader::_input_type_changed(Type p_type, int p_id) { } } +void VisualShader::rebuild() { + dirty = true; + _update_shader(); +} + void VisualShader::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShader::set_mode); ClassDB::bind_method(D_METHOD("add_node", "type", "node", "position", "id"), &VisualShader::add_node); - ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position); - ClassDB::bind_method(D_METHOD("get_node", "type", "id"), &VisualShader::get_node); + + ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position); ClassDB::bind_method(D_METHOD("get_node_position", "type", "id"), &VisualShader::get_node_position); ClassDB::bind_method(D_METHOD("get_node_list", "type"), &VisualShader::get_node_list); ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id); ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node); + ClassDB::bind_method(D_METHOD("rebuild"), &VisualShader::rebuild); ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection); ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection); ClassDB::bind_method(D_METHOD("connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes); ClassDB::bind_method(D_METHOD("disconnect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::disconnect_nodes); + ClassDB::bind_method(D_METHOD("connect_nodes_forced", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes_forced); ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections); @@ -1046,32 +1169,40 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "modelview", "MODELVIEW_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0)" }, // Spatial, Fragment + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "view", "VIEW" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV2,0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec3(POINT_COORD,0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "float(FRONT_FACING ? 1.0 : 0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0.0)" }, // Spatial, Light + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "view", "VIEW" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT" }, @@ -1079,19 +1210,24 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "attenuation", "ATTENUATION" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "transmission", "TRANSMISSION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "diffuse", "DIFFUSE_LIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0.0)" }, // Canvas Item, Vertex { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "texture_pixel_size", "vec3(TEXTURE_PIXEL_SIZE, 1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" }, @@ -1099,14 +1235,18 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "light_pass", "float(AT_LIGHT_PASS ? 1.0 : 0.0)" }, // Canvas Item, Fragment + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "texture_pixel_size", "vec3(TEXTURE_PIXEL_SIZE, 1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_pixel_size", "vec3(SCREEN_PIXEL_SIZE, 1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec3(POINT_COORD,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light_pass", "float(AT_LIGHT_PASS ? 1.0 : 0.0)" }, // Canvas Item, Light + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, @@ -1117,10 +1257,11 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_alpha", "LIGHT_COLOR.a" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_uv", "vec3(LIGHT_UV,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "shadow_color", "SHADOW_COLOR.rgb" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "texture_pixel_size", "vec3(TEXTURE_PIXEL_SIZE, 1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec3(POINT_COORD,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Particles, Vertex { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, @@ -1151,16 +1292,16 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "1.0" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(1.0,1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0,1.0, 0.0)" }, // Spatial, Light { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0,0.0,1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, // Canvas Item, Vertex { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, @@ -1171,7 +1312,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Canvas Item, Light { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, @@ -1179,7 +1320,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Particles, Vertex { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, @@ -1218,56 +1359,61 @@ String VisualShaderNodeInput::get_caption() const { return TTR("Input"); } -String VisualShaderNodeInput::generate_code_for_preview(VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeInput::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) const { - int idx = 0; + if (p_for_preview) { + int idx = 0; - String code; + String code; - while (preview_ports[idx].mode != Shader::MODE_MAX) { - if (preview_ports[idx].mode == shader_mode && preview_ports[idx].shader_type == shader_type && preview_ports[idx].name == input_name) { - code = "\t" + p_output_vars[0] + " = " + preview_ports[idx].string + ";\n"; - break; + while (preview_ports[idx].mode != Shader::MODE_MAX) { + if (preview_ports[idx].mode == shader_mode && preview_ports[idx].shader_type == shader_type && preview_ports[idx].name == input_name) { + code = "\t" + p_output_vars[0] + " = " + preview_ports[idx].string + ";\n"; + break; + } + idx++; } - idx++; - } - if (code == String()) { - switch (get_output_port_type(0)) { - case PORT_TYPE_SCALAR: { - code = "\t" + p_output_vars[0] + " = 0.0;\n"; - } break; //default (none found) is scalar - case PORT_TYPE_VECTOR: { - code = "\t" + p_output_vars[0] + " = vec3(0.0);\n"; - } break; //default (none found) is scalar - case PORT_TYPE_TRANSFORM: { - code = "\t" + p_output_vars[0] + " = mat4( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), vec4(0.0,0.0,1.0,0.0), vec4(0.0,0.0,0.0,1.0) );\n"; - } break; //default (none found) is scalar + if (code == String()) { + switch (get_output_port_type(0)) { + case PORT_TYPE_SCALAR: { + code = "\t" + p_output_vars[0] + " = 0.0;\n"; + } break; //default (none found) is scalar + case PORT_TYPE_VECTOR: { + code = "\t" + p_output_vars[0] + " = vec3(0.0);\n"; + } break; //default (none found) is scalar + case PORT_TYPE_TRANSFORM: { + code = "\t" + p_output_vars[0] + " = mat4( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), vec4(0.0,0.0,1.0,0.0), vec4(0.0,0.0,0.0,1.0) );\n"; + } break; //default (none found) is scalar + case PORT_TYPE_BOOLEAN: { + code = "\t" + p_output_vars[0] + " = false;\n"; + } break; + default: + break; + } } - } - return code; -} + return code; -String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { + } else { + int idx = 0; - int idx = 0; + String code; - String code; + while (ports[idx].mode != Shader::MODE_MAX) { + if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == input_name) { + code = "\t" + p_output_vars[0] + " = " + ports[idx].string + ";\n"; + break; + } + idx++; + } - while (ports[idx].mode != Shader::MODE_MAX) { - if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == input_name) { - code = "\t" + p_output_vars[0] + " = " + ports[idx].string + ";\n"; - break; + if (code == String()) { + code = "\t" + p_output_vars[0] + " = 0.0;\n"; //default (none found) is scalar } - idx++; - } - if (code == String()) { - code = "\t" + p_output_vars[0] + " = 0.0;\n"; //default (none found) is scalar + return code; } - - return code; } void VisualShaderNodeInput::set_input_name(String p_name) { @@ -1535,7 +1681,7 @@ String VisualShaderNodeOutput::get_caption() const { return TTR("Output"); } -String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeOutput::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) const { int idx = 0; int count = 0; @@ -1585,3 +1731,555 @@ void VisualShaderNodeUniform::_bind_methods() { VisualShaderNodeUniform::VisualShaderNodeUniform() { } + +////////////// GroupBase + +String VisualShaderNodeGroupBase::get_caption() const { + return "Group"; +} + +void VisualShaderNodeGroupBase::set_size(const Vector2 &p_size) { + size = p_size; +} + +Vector2 VisualShaderNodeGroupBase::get_size() const { + return size; +} + +void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) { + + if (inputs == p_inputs) + return; + + clear_input_ports(); + + inputs = p_inputs; + + Vector<String> input_strings = inputs.split(";", false); + + int input_port_count = input_strings.size(); + + for (int i = 0; i < input_port_count; i++) { + + Vector<String> arr = input_strings[i].split(","); + + int port_idx = arr[0].to_int(); + int port_type = arr[1].to_int(); + String port_name = arr[2]; + + Port port; + port.type = (PortType)port_type; + port.name = port_name; + input_ports[port_idx] = port; + } +} + +String VisualShaderNodeGroupBase::get_inputs() const { + return inputs; +} + +void VisualShaderNodeGroupBase::set_outputs(const String &p_outputs) { + + if (outputs == p_outputs) + return; + + clear_output_ports(); + + outputs = p_outputs; + + Vector<String> output_strings = outputs.split(";", false); + + int output_port_count = output_strings.size(); + + for (int i = 0; i < output_port_count; i++) { + + Vector<String> arr = output_strings[i].split(","); + + int port_idx = arr[0].to_int(); + int port_type = arr[1].to_int(); + String port_name = arr[2]; + + Port port; + port.type = (PortType)port_type; + port.name = port_name; + output_ports[port_idx] = port; + } +} + +String VisualShaderNodeGroupBase::get_outputs() const { + return outputs; +} + +void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const String &p_name) { + + String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";"; + Vector<String> inputs_strings = inputs.split(";", false); + int index = 0; + if (p_id < inputs_strings.size()) { + for (int i = 0; i < inputs_strings.size(); i++) { + if (i == p_id) { + inputs = inputs.insert(index, str); + break; + } + index += inputs_strings[i].size(); + } + } else { + inputs += str; + } + + inputs_strings = inputs.split(";", false); + index = 0; + + for (int i = 0; i < inputs_strings.size(); i++) { + int count = 0; + for (int j = 0; j < inputs_strings[i].size(); j++) { + if (inputs_strings[i][j] == ',') { + break; + } + count++; + } + + inputs.erase(index, count); + inputs = inputs.insert(index, itos(i)); + index += inputs_strings[i].size(); + } + + _apply_port_changes(); +} + +void VisualShaderNodeGroupBase::remove_input_port(int p_id) { + + Vector<String> inputs_strings = inputs.split(";", false); + int count = 0; + int index = 0; + for (int i = 0; i < inputs_strings.size(); i++) { + Vector<String> arr = inputs_strings[i].split(","); + if (arr[0].to_int() == p_id) { + count = inputs_strings[i].size(); + break; + } + index += inputs_strings[i].size(); + } + inputs.erase(index, count); + + inputs_strings = inputs.split(";", false); + for (int i = p_id; i < inputs_strings.size(); i++) { + inputs = inputs.replace_first(inputs_strings[i].split(",")[0], itos(i)); + } + + _apply_port_changes(); +} + +int VisualShaderNodeGroupBase::get_input_port_count() const { + return input_ports.size(); +} + +bool VisualShaderNodeGroupBase::has_input_port(int p_id) const { + return input_ports.has(p_id); +} + +void VisualShaderNodeGroupBase::add_output_port(int p_id, int p_type, const String &p_name) { + + String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";"; + Vector<String> outputs_strings = outputs.split(";", false); + int index = 0; + if (p_id < outputs_strings.size()) { + for (int i = 0; i < outputs_strings.size(); i++) { + if (i == p_id) { + outputs = outputs.insert(index, str); + break; + } + index += outputs_strings[i].size(); + } + } else { + outputs += str; + } + + outputs_strings = outputs.split(";", false); + index = 0; + + for (int i = 0; i < outputs_strings.size(); i++) { + int count = 0; + for (int j = 0; j < outputs_strings[i].size(); j++) { + if (outputs_strings[i][j] == ',') { + break; + } + count++; + } + + outputs.erase(index, count); + outputs = outputs.insert(index, itos(i)); + index += outputs_strings[i].size(); + } + + _apply_port_changes(); +} + +void VisualShaderNodeGroupBase::remove_output_port(int p_id) { + + Vector<String> outputs_strings = outputs.split(";", false); + int count = 0; + int index = 0; + for (int i = 0; i < outputs_strings.size(); i++) { + Vector<String> arr = outputs_strings[i].split(","); + if (arr[0].to_int() == p_id) { + count = outputs_strings[i].size(); + break; + } + index += outputs_strings[i].size(); + } + outputs.erase(index, count); + + outputs_strings = outputs.split(";", false); + for (int i = p_id; i < outputs_strings.size(); i++) { + outputs = outputs.replace_first(outputs_strings[i].split(",")[0], itos(i)); + } + + _apply_port_changes(); +} + +int VisualShaderNodeGroupBase::get_output_port_count() const { + return output_ports.size(); +} + +bool VisualShaderNodeGroupBase::has_output_port(int p_id) const { + return output_ports.has(p_id); +} + +void VisualShaderNodeGroupBase::clear_input_ports() { + input_ports.clear(); +} + +void VisualShaderNodeGroupBase::clear_output_ports() { + output_ports.clear(); +} + +void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) { + + if (input_ports[p_id].type == p_type) + return; + + Vector<String> inputs_strings = inputs.split(";", false); + int count = 0; + int index = 0; + for (int i = 0; i < inputs_strings.size(); i++) { + Vector<String> arr = inputs_strings[i].split(","); + if (arr[0].to_int() == p_id) { + index += arr[0].size(); + count = arr[1].size() - 1; + break; + } + index += inputs_strings[i].size(); + } + + inputs.erase(index, count); + + inputs = inputs.insert(index, itos(p_type)); + + _apply_port_changes(); +} + +VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_input_port_type(int p_id) const { + ERR_FAIL_COND_V(!input_ports.has(p_id), (PortType)0); + return input_ports[p_id].type; +} + +void VisualShaderNodeGroupBase::set_input_port_name(int p_id, const String &p_name) { + + if (input_ports[p_id].name == p_name) + return; + + Vector<String> inputs_strings = inputs.split(";", false); + int count = 0; + int index = 0; + for (int i = 0; i < inputs_strings.size(); i++) { + Vector<String> arr = inputs_strings[i].split(","); + if (arr[0].to_int() == p_id) { + index += arr[0].size() + arr[1].size(); + count = arr[2].size() - 1; + break; + } + index += inputs_strings[i].size(); + } + + inputs.erase(index, count); + + inputs = inputs.insert(index, p_name); + + _apply_port_changes(); +} + +String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const { + ERR_FAIL_COND_V(!input_ports.has(p_id), ""); + return input_ports[p_id].name; +} + +void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) { + + if (output_ports[p_id].type == p_type) + return; + + Vector<String> output_strings = outputs.split(";", false); + int count = 0; + int index = 0; + for (int i = 0; i < output_strings.size(); i++) { + Vector<String> arr = output_strings[i].split(","); + if (arr[0].to_int() == p_id) { + index += arr[0].size(); + count = arr[1].size() - 1; + break; + } + index += output_strings[i].size(); + } + + outputs.erase(index, count); + + outputs = outputs.insert(index, itos(p_type)); + + _apply_port_changes(); +} + +VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_output_port_type(int p_id) const { + ERR_FAIL_COND_V(!output_ports.has(p_id), (PortType)0); + return output_ports[p_id].type; +} + +void VisualShaderNodeGroupBase::set_output_port_name(int p_id, const String &p_name) { + if (output_ports[p_id].name == p_name) + return; + + Vector<String> output_strings = outputs.split(";", false); + int count = 0; + int index = 0; + for (int i = 0; i < output_strings.size(); i++) { + Vector<String> arr = output_strings[i].split(","); + if (arr[0].to_int() == p_id) { + index += arr[0].size() + arr[1].size(); + count = arr[2].size() - 1; + break; + } + index += output_strings[i].size(); + } + + outputs.erase(index, count); + + outputs = outputs.insert(index, p_name); + + _apply_port_changes(); +} + +String VisualShaderNodeGroupBase::get_output_port_name(int p_id) const { + ERR_FAIL_COND_V(!output_ports.has(p_id), ""); + return output_ports[p_id].name; +} + +int VisualShaderNodeGroupBase::get_free_input_port_id() const { + return input_ports.size(); +} + +int VisualShaderNodeGroupBase::get_free_output_port_id() const { + return output_ports.size(); +} + +void VisualShaderNodeGroupBase::set_control(Control *p_control, int p_index) { + controls[p_index] = p_control; +} + +Control *VisualShaderNodeGroupBase::get_control(int p_index) { + ERR_FAIL_COND_V(!controls.has(p_index), NULL); + return controls[p_index]; +} + +void VisualShaderNodeGroupBase::_apply_port_changes() { + + Vector<String> inputs_strings = inputs.split(";", false); + Vector<String> outputs_strings = outputs.split(";", false); + + clear_input_ports(); + clear_output_ports(); + + for (int i = 0; i < inputs_strings.size(); i++) { + Vector<String> arr = inputs_strings[i].split(","); + Port port; + port.type = (PortType)arr[1].to_int(); + port.name = arr[2]; + input_ports[i] = port; + } + for (int i = 0; i < outputs_strings.size(); i++) { + Vector<String> arr = outputs_strings[i].split(","); + Port port; + port.type = (PortType)arr[1].to_int(); + port.name = arr[2]; + output_ports[i] = port; + } +} + +void VisualShaderNodeGroupBase::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeGroupBase::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeGroupBase::get_size); + + ClassDB::bind_method(D_METHOD("set_inputs", "inputs"), &VisualShaderNodeGroupBase::set_inputs); + ClassDB::bind_method(D_METHOD("get_inputs"), &VisualShaderNodeGroupBase::get_inputs); + + ClassDB::bind_method(D_METHOD("set_outputs", "outputs"), &VisualShaderNodeGroupBase::set_outputs); + ClassDB::bind_method(D_METHOD("get_outputs"), &VisualShaderNodeGroupBase::get_outputs); + + ClassDB::bind_method(D_METHOD("add_input_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_input_port); + ClassDB::bind_method(D_METHOD("remove_input_port", "id"), &VisualShaderNodeGroupBase::remove_input_port); + ClassDB::bind_method(D_METHOD("get_input_port_count"), &VisualShaderNodeGroupBase::get_input_port_count); + ClassDB::bind_method(D_METHOD("has_input_port", "id"), &VisualShaderNodeGroupBase::has_input_port); + ClassDB::bind_method(D_METHOD("clear_input_ports"), &VisualShaderNodeGroupBase::clear_input_ports); + + ClassDB::bind_method(D_METHOD("add_output_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_output_port); + ClassDB::bind_method(D_METHOD("remove_output_port", "id"), &VisualShaderNodeGroupBase::remove_output_port); + ClassDB::bind_method(D_METHOD("get_output_port_count"), &VisualShaderNodeGroupBase::get_output_port_count); + 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("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); + + ClassDB::bind_method(D_METHOD("set_control", "control", "index"), &VisualShaderNodeGroupBase::set_control); + ClassDB::bind_method(D_METHOD("get_control", "index"), &VisualShaderNodeGroupBase::get_control); +} + +String VisualShaderNodeGroupBase::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) const { + return ""; +} + +VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() { + size = Size2(0, 0); + inputs = ""; + outputs = ""; +} + +////////////// Expression + +String VisualShaderNodeExpression::get_caption() const { + return "Expression"; +} + +void VisualShaderNodeExpression::set_expression(const String &p_expression) { + expression = p_expression; +} + +void VisualShaderNodeExpression::build() { + emit_changed(); +} + +String VisualShaderNodeExpression::get_expression() const { + return expression; +} + +String VisualShaderNodeExpression::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) const { + + String _expression = expression; + + _expression = _expression.insert(0, "\n"); + _expression = _expression.replace("\n", "\n\t\t"); + + static Vector<String> pre_symbols; + if (pre_symbols.empty()) { + pre_symbols.push_back("\t"); + pre_symbols.push_back("{"); + pre_symbols.push_back("["); + pre_symbols.push_back("("); + pre_symbols.push_back(" "); + pre_symbols.push_back("-"); + pre_symbols.push_back("*"); + pre_symbols.push_back("/"); + pre_symbols.push_back("+"); + pre_symbols.push_back("="); + pre_symbols.push_back("&"); + pre_symbols.push_back("|"); + pre_symbols.push_back("!"); + } + + static Vector<String> post_symbols; + if (post_symbols.empty()) { + post_symbols.push_back("\0"); + post_symbols.push_back("\t"); + post_symbols.push_back("\n"); + post_symbols.push_back(";"); + post_symbols.push_back("}"); + post_symbols.push_back("]"); + post_symbols.push_back(")"); + post_symbols.push_back(" "); + post_symbols.push_back("."); + post_symbols.push_back("-"); + post_symbols.push_back("*"); + post_symbols.push_back("/"); + post_symbols.push_back("+"); + post_symbols.push_back("="); + post_symbols.push_back("&"); + post_symbols.push_back("|"); + post_symbols.push_back("!"); + } + + for (int i = 0; i < get_input_port_count(); i++) { + for (int j = 0; j < pre_symbols.size(); j++) { + for (int k = 0; k < post_symbols.size(); k++) { + _expression = _expression.replace(pre_symbols[j] + get_input_port_name(i) + post_symbols[k], pre_symbols[j] + p_input_vars[i] + post_symbols[k]); + } + } + } + for (int i = 0; i < get_output_port_count(); i++) { + for (int j = 0; j < pre_symbols.size(); j++) { + for (int k = 0; k < post_symbols.size(); k++) { + _expression = _expression.replace(pre_symbols[j] + get_output_port_name(i) + post_symbols[k], pre_symbols[j] + p_output_vars[i] + post_symbols[k]); + } + } + } + + String output_initializer; + + for (int i = 0; i < get_output_port_count(); i++) { + int port_type = get_output_port_type(i); + String tk = ""; + switch (port_type) { + case PORT_TYPE_SCALAR: + tk = "0.0"; + break; + case PORT_TYPE_VECTOR: + tk = "vec3(0.0, 0.0, 0.0)"; + break; + case PORT_TYPE_BOOLEAN: + tk = "false"; + break; + case PORT_TYPE_TRANSFORM: + tk = "mat4(1.0)"; + break; + default: + continue; + } + output_initializer += "\t" + p_output_vars[i] + "=" + tk + ";\n"; + } + + String code; + code += output_initializer; + code += "\t{"; + code += _expression; + code += "\n\t}"; + + return code; +} + +void VisualShaderNodeExpression::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_expression", "expression"), &VisualShaderNodeExpression::set_expression); + ClassDB::bind_method(D_METHOD("get_expression"), &VisualShaderNodeExpression::get_expression); + + ClassDB::bind_method(D_METHOD("build"), &VisualShaderNodeExpression::build); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "expression"), "set_expression", "get_expression"); +} + +VisualShaderNodeExpression::VisualShaderNodeExpression() { + expression = ""; +} diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 2867daac3a..1ab3c0c9cc 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,13 +32,15 @@ #define VISUAL_SHADER_H #include "core/string_builder.h" +#include "scene/gui/control.h" #include "scene/resources/shader.h" class VisualShaderNodeUniform; class VisualShaderNode; class VisualShader : public Shader { - GDCLASS(VisualShader, Shader) + GDCLASS(VisualShader, Shader); + public: enum Type { TYPE_VERTEX, @@ -135,7 +137,9 @@ public: bool can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const; Error connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port); void disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port); + void connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port); + void rebuild(); void get_node_connections(Type p_type, List<Connection> *r_connections) const; void set_mode(Mode p_mode); @@ -148,6 +152,7 @@ public: String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const; + String validate_port_name(const String &p_name, const List<String> &p_input_ports, const List<String> &p_output_ports) const; String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const; VisualShader(); @@ -159,7 +164,7 @@ VARIANT_ENUM_CAST(VisualShader::Type) /// class VisualShaderNode : public Resource { - GDCLASS(VisualShaderNode, Resource) + GDCLASS(VisualShaderNode, Resource); int port_preview; @@ -175,7 +180,9 @@ public: enum PortType { PORT_TYPE_SCALAR, PORT_TYPE_VECTOR, + PORT_TYPE_BOOLEAN, PORT_TYPE_TRANSFORM, + PORT_TYPE_COLOR // just a hint for node tree icons, do not use it as actual port type ! }; virtual String get_caption() const = 0; @@ -200,7 +207,7 @@ public: 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) const = 0; //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 + 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 = 0; //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 virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const; @@ -209,7 +216,7 @@ public: ///// class VisualShaderNodeInput : public VisualShaderNode { - GDCLASS(VisualShaderNodeInput, VisualShaderNode) + GDCLASS(VisualShaderNodeInput, VisualShaderNode); friend class VisualShader; VisualShader::Type shader_type; @@ -243,8 +250,7 @@ public: virtual String get_caption() const; - virtual String generate_code_for_preview(VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) 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) 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; void set_input_name(String p_name); String get_input_name() const; @@ -263,7 +269,8 @@ public: /// class VisualShaderNodeOutput : public VisualShaderNode { - GDCLASS(VisualShaderNodeOutput, VisualShaderNode) + GDCLASS(VisualShaderNodeOutput, VisualShaderNode); + public: friend class VisualShader; VisualShader::Type shader_type; @@ -293,13 +300,13 @@ public: virtual String get_caption() 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) 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; VisualShaderNodeOutput(); }; class VisualShaderNodeUniform : public VisualShaderNode { - GDCLASS(VisualShaderNodeUniform, VisualShaderNode) + GDCLASS(VisualShaderNodeUniform, VisualShaderNode); String uniform_name; @@ -313,4 +320,94 @@ public: VisualShaderNodeUniform(); }; +class VisualShaderNodeGroupBase : public VisualShaderNode { + GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode); + +private: + void _apply_port_changes(); + +protected: + Vector2 size; + String inputs; + String outputs; + + struct Port { + PortType type; + String name; + }; + + Map<int, Port> input_ports; + Map<int, Port> output_ports; + Map<int, Control *> controls; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + void set_size(const Vector2 &p_size); + Vector2 get_size() const; + + void set_inputs(const String &p_inputs); + String get_inputs() const; + + void set_outputs(const String &p_outputs); + String get_outputs() const; + + void add_input_port(int p_id, int p_type, const String &p_name); + void remove_input_port(int p_id); + virtual int get_input_port_count() const; + bool has_input_port(int p_id) const; + void clear_input_ports(); + + void add_output_port(int p_id, int p_type, const String &p_name); + void remove_output_port(int p_id); + virtual int get_output_port_count() const; + bool has_output_port(int p_id) const; + void clear_output_ports(); + + void set_input_port_type(int p_id, int p_type); + virtual PortType get_input_port_type(int p_id) const; + void set_input_port_name(int p_id, const String &p_name); + virtual String get_input_port_name(int p_id) const; + + void set_output_port_type(int p_id, int p_type); + virtual PortType get_output_port_type(int p_id) const; + void set_output_port_name(int p_id, const String &p_name); + virtual String get_output_port_name(int p_id) const; + + int get_free_input_port_id() const; + int get_free_output_port_id() const; + + void set_control(Control *p_control, int p_index); + Control *get_control(int p_index); + + 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; + + VisualShaderNodeGroupBase(); +}; + +class VisualShaderNodeExpression : public VisualShaderNodeGroupBase { + GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase); + +private: + String expression; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + void set_expression(const String &p_expression); + String get_expression() const; + + void build(); + + 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; + + VisualShaderNodeExpression(); +}; + #endif // VISUAL_SHADER_H diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index d011b102a2..a44471a365 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -55,7 +55,7 @@ String VisualShaderNodeScalarConstant::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -String VisualShaderNodeScalarConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeScalarConstant::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) const { return "\t" + p_output_vars[0] + " = " + vformat("%.6f", constant) + ";\n"; } @@ -88,6 +88,67 @@ VisualShaderNodeScalarConstant::VisualShaderNodeScalarConstant() { constant = 0; } +////////////// Boolean + +String VisualShaderNodeBooleanConstant::get_caption() const { + return "Boolean"; +} + +int VisualShaderNodeBooleanConstant::get_input_port_count() const { + return 0; +} + +VisualShaderNodeBooleanConstant::PortType VisualShaderNodeBooleanConstant::get_input_port_type(int p_port) const { + return PORT_TYPE_BOOLEAN; +} + +String VisualShaderNodeBooleanConstant::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeBooleanConstant::get_output_port_count() const { + return 1; +} + +VisualShaderNodeBooleanConstant::PortType VisualShaderNodeBooleanConstant::get_output_port_type(int p_port) const { + return PORT_TYPE_BOOLEAN; +} + +String VisualShaderNodeBooleanConstant::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeBooleanConstant::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) const { + return "\t" + p_output_vars[0] + " = " + (constant ? "true" : "false") + ";\n"; +} + +void VisualShaderNodeBooleanConstant::set_constant(bool p_value) { + constant = p_value; + emit_changed(); +} + +bool VisualShaderNodeBooleanConstant::get_constant() const { + return constant; +} + +Vector<StringName> VisualShaderNodeBooleanConstant::get_editable_properties() const { + Vector<StringName> props; + props.push_back("constant"); + return props; +} + +void VisualShaderNodeBooleanConstant::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeBooleanConstant::set_constant); + ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeBooleanConstant::get_constant); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "constant"), "set_constant", "get_constant"); +} + +VisualShaderNodeBooleanConstant::VisualShaderNodeBooleanConstant() { + constant = false; +} + ////////////// Color String VisualShaderNodeColorConstant::get_caption() const { @@ -114,7 +175,7 @@ String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const { return p_port == 0 ? "" : "alpha"; //no output port means the editor will be used as port } -String VisualShaderNodeColorConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeColorConstant::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) const { String code; code += "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f,%.6f,%.6f)", constant.r, constant.g, constant.b) + ";\n"; @@ -178,7 +239,7 @@ String VisualShaderNodeVec3Constant::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -String VisualShaderNodeVec3Constant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeVec3Constant::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) const { return "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f,%.6f,%.6f)", constant.x, constant.y, constant.z) + ";\n"; } @@ -236,7 +297,7 @@ String VisualShaderNodeTransformConstant::get_output_port_name(int p_port) const return ""; //no output port means the editor will be used as port } -String VisualShaderNodeTransformConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeTransformConstant::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) const { Transform t = constant; t.basis.transpose(); @@ -324,7 +385,7 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade String u = "uniform sampler2D " + make_unique_id(p_type, p_id, "tex"); switch (texture_type) { case TYPE_DATA: break; - case TYPE_COLOR: u += " : hint_color"; break; + case TYPE_COLOR: u += " : hint_albedo"; break; case TYPE_NORMALMAP: u += " : hint_normal"; break; } return u + ";"; @@ -333,7 +394,7 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade return String(); } -String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeTexture::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) const { if (source == SOURCE_TEXTURE) { String id = make_unique_id(p_type, p_id, "tex"); @@ -357,7 +418,7 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: 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()) { //none bound, do nothing + if (p_input_vars[0] == String() || p_for_preview) { //none bound, do nothing code += "\t\tvec4 _tex_read = vec4(0.0);\n"; @@ -554,13 +615,13 @@ String VisualShaderNodeCubeMap::generate_global(Shader::Mode p_mode, VisualShade String u = "uniform sampler2DCube " + make_unique_id(p_type, p_id, "cube"); switch (texture_type) { case TYPE_DATA: break; - case TYPE_COLOR: u += " : hint_color"; break; + case TYPE_COLOR: u += " : hint_albedo"; break; case TYPE_NORMALMAP: u += " : hint_normal"; break; } return u + ";"; } -String VisualShaderNodeCubeMap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeCubeMap::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) const { String id = make_unique_id(p_type, p_id, "cube"); String code; @@ -652,7 +713,7 @@ String VisualShaderNodeScalarOp::get_output_port_name(int p_port) const { return "op"; //no output port means the editor will be used as port } -String VisualShaderNodeScalarOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeScalarOp::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) const { String code = "\t" + p_output_vars[0] + " = "; switch (op) { @@ -666,6 +727,7 @@ String VisualShaderNodeScalarOp::generate_code(Shader::Mode p_mode, VisualShader case OP_MAX: code += "max( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; case OP_MIN: code += "min( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; case OP_ATAN2: code += "atan( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_STEP: code += "step( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; } return code; @@ -693,7 +755,7 @@ void VisualShaderNodeScalarOp::_bind_methods() { ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeScalarOp::set_operator); ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeScalarOp::get_operator); - ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Atan2"), "set_operator", "get_operator"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Atan2,Step"), "set_operator", "get_operator"); BIND_ENUM_CONSTANT(OP_ADD); BIND_ENUM_CONSTANT(OP_SUB); @@ -704,6 +766,7 @@ void VisualShaderNodeScalarOp::_bind_methods() { BIND_ENUM_CONSTANT(OP_MAX); BIND_ENUM_CONSTANT(OP_MIN); BIND_ENUM_CONSTANT(OP_ATAN2); + BIND_ENUM_CONSTANT(OP_STEP); } VisualShaderNodeScalarOp::VisualShaderNodeScalarOp() { @@ -738,7 +801,7 @@ String VisualShaderNodeVectorOp::get_output_port_name(int p_port) const { return "op"; //no output port means the editor will be used as port } -String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeVectorOp::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) const { String code = "\t" + p_output_vars[0] + " = "; switch (op) { @@ -752,6 +815,9 @@ String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader case OP_MAX: code += "max( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; case OP_MIN: code += "min( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; case OP_CROSS: code += "cross( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_ATAN2: code += "atan( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_REFLECT: code += "reflect( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; + case OP_STEP: code += "step( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break; } return code; @@ -779,7 +845,7 @@ void VisualShaderNodeVectorOp::_bind_methods() { ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeVectorOp::set_operator); ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeVectorOp::get_operator); - ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Cross"), "set_operator", "get_operator"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Cross,Atan2,Reflect,Step"), "set_operator", "get_operator"); BIND_ENUM_CONSTANT(OP_ADD); BIND_ENUM_CONSTANT(OP_SUB); @@ -790,6 +856,9 @@ void VisualShaderNodeVectorOp::_bind_methods() { BIND_ENUM_CONSTANT(OP_MAX); BIND_ENUM_CONSTANT(OP_MIN); BIND_ENUM_CONSTANT(OP_CROSS); + BIND_ENUM_CONSTANT(OP_ATAN2); + BIND_ENUM_CONSTANT(OP_REFLECT); + BIND_ENUM_CONSTANT(OP_STEP); } VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() { @@ -824,7 +893,7 @@ String VisualShaderNodeColorOp::get_output_port_name(int p_port) const { return "op"; //no output port means the editor will be used as port } -String VisualShaderNodeColorOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeColorOp::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) const { String code; static const char *axisn[3] = { "x", "y", "z" }; @@ -972,12 +1041,16 @@ String VisualShaderNodeTransformMult::get_output_port_name(int p_port) const { return "mult"; //no output port means the editor will be used as port } -String VisualShaderNodeTransformMult::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeTransformMult::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) const { if (op == OP_AxB) { return "\t" + p_output_vars[0] + " = " + p_input_vars[0] + " * " + p_input_vars[1] + ";\n"; - } else { + } else if (op == OP_BxA) { return "\t" + p_output_vars[0] + " = " + p_input_vars[1] + " * " + p_input_vars[0] + ";\n"; + } else if (op == OP_AxB_COMP) { + return "\t" + p_output_vars[0] + " = matrixCompMult( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; + } else { + return "\t" + p_output_vars[0] + " = matrixCompMult( " + p_input_vars[1] + " , " + p_input_vars[0] + " );\n"; } } @@ -1003,10 +1076,12 @@ void VisualShaderNodeTransformMult::_bind_methods() { ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeTransformMult::set_operator); ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeTransformMult::get_operator); - ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "A x B,B x A"), "set_operator", "get_operator"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "A x B,B x A,A x B(per component),B x A(per component)"), "set_operator", "get_operator"); BIND_ENUM_CONSTANT(OP_AxB); BIND_ENUM_CONSTANT(OP_BxA); + BIND_ENUM_CONSTANT(OP_AxB_COMP); + BIND_ENUM_CONSTANT(OP_BxA_COMP); } VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() { @@ -1041,7 +1116,7 @@ String VisualShaderNodeTransformVecMult::get_output_port_name(int p_port) const return ""; //no output port means the editor will be used as port } -String VisualShaderNodeTransformVecMult::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeTransformVecMult::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) const { if (op == OP_AxB) { return "\t" + p_output_vars[0] + " = ( " + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 1.0) ).xyz;\n"; } else if (op == OP_BxA) { @@ -1115,9 +1190,9 @@ String VisualShaderNodeScalarFunc::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeScalarFunc::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) const { - static const char *scalar_func_id[FUNC_NEGATE + 1] = { + static const char *scalar_func_id[FUNC_ONEMINUS + 1] = { "sin($)", "cos($)", "tan($)", @@ -1136,8 +1211,20 @@ String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShad "round($)", "ceil($)", "fract($)", - "min(max($,0),1)", + "min(max($,0.0),1.0)", "-($)", + "acosh($)", + "asinh($)", + "atanh($)", + "degrees($)", + "exp2($)", + "inversesqrt($)", + "log2($)", + "radians($)", + "1.0/($)", + "roundEven($)", + "trunc($)", + "1.0-$" }; return "\t" + p_output_vars[0] + " = " + String(scalar_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; @@ -1165,7 +1252,7 @@ void VisualShaderNodeScalarFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_SIN); BIND_ENUM_CONSTANT(FUNC_COS); @@ -1187,6 +1274,18 @@ void VisualShaderNodeScalarFunc::_bind_methods() { BIND_ENUM_CONSTANT(FUNC_FRAC); BIND_ENUM_CONSTANT(FUNC_SATURATE); BIND_ENUM_CONSTANT(FUNC_NEGATE); + BIND_ENUM_CONSTANT(FUNC_ACOSH); + BIND_ENUM_CONSTANT(FUNC_ASINH); + BIND_ENUM_CONSTANT(FUNC_ATANH); + BIND_ENUM_CONSTANT(FUNC_DEGREES); + BIND_ENUM_CONSTANT(FUNC_EXP2); + BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT); + BIND_ENUM_CONSTANT(FUNC_LOG2); + BIND_ENUM_CONSTANT(FUNC_RADIANS); + BIND_ENUM_CONSTANT(FUNC_RECIPROCAL); + BIND_ENUM_CONSTANT(FUNC_ROUNDEVEN); + BIND_ENUM_CONSTANT(FUNC_TRUNC); + BIND_ENUM_CONSTANT(FUNC_ONEMINUS); } VisualShaderNodeScalarFunc::VisualShaderNodeScalarFunc() { @@ -1220,15 +1319,44 @@ String VisualShaderNodeVectorFunc::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeVectorFunc::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) const { - static const char *vec_func_id[FUNC_HSV2RGB + 1] = { + static const char *vec_func_id[FUNC_ONEMINUS + 1] = { "normalize($)", "max(min($,vec3(1.0)),vec3(0.0))", "-($)", "1.0/($)", "", "", + "abs($)", + "acos($)", + "acosh($)", + "asin($)", + "asinh($)", + "atan($)", + "atanh($)", + "ceil($)", + "cos($)", + "cosh($)", + "degrees($)", + "exp($)", + "exp2($)", + "floor($)", + "fract($)", + "inversesqrt($)", + "log($)", + "log2($)", + "radians($)", + "round($)", + "roundEven($)", + "sign($)", + "sin($)", + "sinh($)", + "sqrt($)", + "tan($)", + "tanh($)", + "trunc($)", + "vec3(1.0, 1.0, 1.0)-$" }; String code; @@ -1280,7 +1408,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_NORMALIZE); BIND_ENUM_CONSTANT(FUNC_SATURATE); @@ -1288,6 +1416,35 @@ void VisualShaderNodeVectorFunc::_bind_methods() { BIND_ENUM_CONSTANT(FUNC_RECIPROCAL); BIND_ENUM_CONSTANT(FUNC_RGB2HSV); BIND_ENUM_CONSTANT(FUNC_HSV2RGB); + BIND_ENUM_CONSTANT(FUNC_ABS); + BIND_ENUM_CONSTANT(FUNC_ACOS); + BIND_ENUM_CONSTANT(FUNC_ACOSH); + BIND_ENUM_CONSTANT(FUNC_ASIN); + BIND_ENUM_CONSTANT(FUNC_ASINH); + BIND_ENUM_CONSTANT(FUNC_ATAN); + BIND_ENUM_CONSTANT(FUNC_ATANH); + BIND_ENUM_CONSTANT(FUNC_CEIL); + BIND_ENUM_CONSTANT(FUNC_COS); + BIND_ENUM_CONSTANT(FUNC_COSH); + BIND_ENUM_CONSTANT(FUNC_DEGREES); + BIND_ENUM_CONSTANT(FUNC_EXP); + BIND_ENUM_CONSTANT(FUNC_EXP2); + BIND_ENUM_CONSTANT(FUNC_FLOOR); + BIND_ENUM_CONSTANT(FUNC_FRAC); + BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT); + BIND_ENUM_CONSTANT(FUNC_LOG); + BIND_ENUM_CONSTANT(FUNC_LOG2); + BIND_ENUM_CONSTANT(FUNC_RADIANS); + BIND_ENUM_CONSTANT(FUNC_ROUND); + BIND_ENUM_CONSTANT(FUNC_ROUNDEVEN); + BIND_ENUM_CONSTANT(FUNC_SIGN); + BIND_ENUM_CONSTANT(FUNC_SIN); + BIND_ENUM_CONSTANT(FUNC_SINH); + BIND_ENUM_CONSTANT(FUNC_SQRT); + BIND_ENUM_CONSTANT(FUNC_TAN); + BIND_ENUM_CONSTANT(FUNC_TANH); + BIND_ENUM_CONSTANT(FUNC_TRUNC); + BIND_ENUM_CONSTANT(FUNC_ONEMINUS); } VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() { @@ -1295,6 +1452,172 @@ VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() { set_input_port_default_value(0, Vector3()); } +////////////// ColorFunc + +String VisualShaderNodeColorFunc::get_caption() const { + return "ColorFunc"; +} + +int VisualShaderNodeColorFunc::get_input_port_count() const { + return 1; +} + +VisualShaderNodeColorFunc::PortType VisualShaderNodeColorFunc::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeColorFunc::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeColorFunc::get_output_port_count() const { + return 1; +} + +VisualShaderNodeColorFunc::PortType VisualShaderNodeColorFunc::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeColorFunc::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeColorFunc::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) const { + + String code; + + switch (func) { + case FUNC_GRAYSCALE: + code += "\t{\n"; + code += "\t\tvec3 c = " + p_input_vars[0] + ";\n"; + code += "\t\tfloat max1 = max(c.r, c.g);\n"; + code += "\t\tfloat max2 = max(max1, c.b);\n"; + code += "\t\tfloat max3 = max(max1, max2);\n"; + code += "\t\t" + p_output_vars[0] + " = vec3(max3, max3, max3);\n"; + code += "\t}\n"; + break; + case FUNC_SEPIA: + code += "\t{\n"; + code += "\t\tvec3 c = " + p_input_vars[0] + ";\n"; + code += "\t\tfloat r = (c.r * .393) + (c.g *.769) + (c.b * .189);\n"; + code += "\t\tfloat g = (c.r * .349) + (c.g *.686) + (c.b * .168);\n"; + code += "\t\tfloat b = (c.r * .272) + (c.g *.534) + (c.b * .131);\n"; + code += "\t\t" + p_output_vars[0] + " = vec3(r, g, b);\n"; + code += "\t}\n"; + break; + } + + return code; +} + +void VisualShaderNodeColorFunc::set_function(Function p_func) { + + func = p_func; + emit_changed(); +} + +VisualShaderNodeColorFunc::Function VisualShaderNodeColorFunc::get_function() const { + + return func; +} + +Vector<StringName> VisualShaderNodeColorFunc::get_editable_properties() const { + Vector<StringName> props; + props.push_back("function"); + return props; +} + +void VisualShaderNodeColorFunc::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeColorFunc::set_function); + ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeColorFunc::get_function); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,Sepia"), "set_function", "get_function"); + + BIND_ENUM_CONSTANT(FUNC_GRAYSCALE); + BIND_ENUM_CONSTANT(FUNC_SEPIA); +} + +VisualShaderNodeColorFunc::VisualShaderNodeColorFunc() { + func = FUNC_GRAYSCALE; + set_input_port_default_value(0, Vector3()); +} + +////////////// Transform Func + +String VisualShaderNodeTransformFunc::get_caption() const { + return "TransformFunc"; +} + +int VisualShaderNodeTransformFunc::get_input_port_count() const { + return 1; +} + +VisualShaderNodeTransformFunc::PortType VisualShaderNodeTransformFunc::get_input_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} + +String VisualShaderNodeTransformFunc::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeTransformFunc::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTransformFunc::PortType VisualShaderNodeTransformFunc::get_output_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} + +String VisualShaderNodeTransformFunc::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeTransformFunc::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) const { + + static const char *funcs[FUNC_TRANSPOSE + 1] = { + "inverse($)", + "transpose($)" + }; + + String code; + code += "\t" + p_output_vars[0] + "=" + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; + return code; +} + +void VisualShaderNodeTransformFunc::set_function(Function p_func) { + + func = p_func; + emit_changed(); +} + +VisualShaderNodeTransformFunc::Function VisualShaderNodeTransformFunc::get_function() const { + + return func; +} + +Vector<StringName> VisualShaderNodeTransformFunc::get_editable_properties() const { + Vector<StringName> props; + props.push_back("function"); + return props; +} + +void VisualShaderNodeTransformFunc::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeTransformFunc::set_function); + ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeTransformFunc::get_function); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Inverse,Transpose"), "set_function", "get_function"); + + BIND_ENUM_CONSTANT(FUNC_INVERSE); + BIND_ENUM_CONSTANT(FUNC_TRANSPOSE); +} + +VisualShaderNodeTransformFunc::VisualShaderNodeTransformFunc() { + func = FUNC_INVERSE; + set_input_port_default_value(0, Transform()); +} + ////////////// Dot Product String VisualShaderNodeDotProduct::get_caption() const { @@ -1321,7 +1644,7 @@ String VisualShaderNodeDotProduct::get_output_port_name(int p_port) const { return "dot"; } -String VisualShaderNodeDotProduct::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeDotProduct::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) const { return "\t" + p_output_vars[0] + " = dot( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; } @@ -1356,7 +1679,7 @@ String VisualShaderNodeVectorLen::get_output_port_name(int p_port) const { return "length"; } -String VisualShaderNodeVectorLen::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeVectorLen::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) const { return "\t" + p_output_vars[0] + " = length( " + p_input_vars[0] + " );\n"; } @@ -1364,10 +1687,674 @@ VisualShaderNodeVectorLen::VisualShaderNodeVectorLen() { set_input_port_default_value(0, Vector3()); } +////////////// Determinant + +String VisualShaderNodeDeterminant::get_caption() const { + return "Determinant"; +} + +int VisualShaderNodeDeterminant::get_input_port_count() const { + return 1; +} + +VisualShaderNodeScalarClamp::PortType VisualShaderNodeDeterminant::get_input_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} + +String VisualShaderNodeDeterminant::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeDeterminant::get_output_port_count() const { + return 1; +} + +VisualShaderNodeDeterminant::PortType VisualShaderNodeDeterminant::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeDeterminant::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeDeterminant::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) const { + return "\t" + p_output_vars[0] + " = determinant( " + p_input_vars[0] + " );\n"; +} + +VisualShaderNodeDeterminant::VisualShaderNodeDeterminant() { + set_input_port_default_value(0, Transform()); +} + +////////////// Scalar Derivative Function + +String VisualShaderNodeScalarDerivativeFunc::get_caption() const { + return "ScalarDerivativeFunc"; +} + +int VisualShaderNodeScalarDerivativeFunc::get_input_port_count() const { + return 1; +} + +VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeScalarDerivativeFunc::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeScalarDerivativeFunc::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeScalarDerivativeFunc::get_output_port_count() const { + return 1; +} + +VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeScalarDerivativeFunc::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeScalarDerivativeFunc::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeScalarDerivativeFunc::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) const { + + static const char *funcs[FUNC_Y + 1] = { + "fwidth($)", + "dFdx($)", + "dFdy($)" + }; + + String code; + code += "\t" + p_output_vars[0] + "=" + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; + return code; +} + +void VisualShaderNodeScalarDerivativeFunc::set_function(Function p_func) { + + func = p_func; + emit_changed(); +} + +VisualShaderNodeScalarDerivativeFunc::Function VisualShaderNodeScalarDerivativeFunc::get_function() const { + + return func; +} + +Vector<StringName> VisualShaderNodeScalarDerivativeFunc::get_editable_properties() const { + Vector<StringName> props; + props.push_back("function"); + return props; +} + +void VisualShaderNodeScalarDerivativeFunc::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarDerivativeFunc::set_function); + ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarDerivativeFunc::get_function); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function"); + + BIND_ENUM_CONSTANT(FUNC_SUM); + BIND_ENUM_CONSTANT(FUNC_X); + BIND_ENUM_CONSTANT(FUNC_Y); +} + +VisualShaderNodeScalarDerivativeFunc::VisualShaderNodeScalarDerivativeFunc() { + func = FUNC_SUM; + set_input_port_default_value(0, 0.0); +} + +////////////// Vector Derivative Function + +String VisualShaderNodeVectorDerivativeFunc::get_caption() const { + return "VectorDerivativeFunc"; +} + +int VisualShaderNodeVectorDerivativeFunc::get_input_port_count() const { + return 1; +} + +VisualShaderNodeVectorDerivativeFunc::PortType VisualShaderNodeVectorDerivativeFunc::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorDerivativeFunc::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeVectorDerivativeFunc::get_output_port_count() const { + return 1; +} + +VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeVectorDerivativeFunc::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorDerivativeFunc::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeVectorDerivativeFunc::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) const { + + static const char *funcs[FUNC_Y + 1] = { + "fwidth($)", + "dFdx($)", + "dFdy($)" + }; + + String code; + code += "\t" + p_output_vars[0] + "=" + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; + return code; +} + +void VisualShaderNodeVectorDerivativeFunc::set_function(Function p_func) { + + func = p_func; + emit_changed(); +} + +VisualShaderNodeVectorDerivativeFunc::Function VisualShaderNodeVectorDerivativeFunc::get_function() const { + + return func; +} + +Vector<StringName> VisualShaderNodeVectorDerivativeFunc::get_editable_properties() const { + Vector<StringName> props; + props.push_back("function"); + return props; +} + +void VisualShaderNodeVectorDerivativeFunc::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorDerivativeFunc::set_function); + ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorDerivativeFunc::get_function); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function"); + + BIND_ENUM_CONSTANT(FUNC_SUM); + BIND_ENUM_CONSTANT(FUNC_X); + BIND_ENUM_CONSTANT(FUNC_Y); +} + +VisualShaderNodeVectorDerivativeFunc::VisualShaderNodeVectorDerivativeFunc() { + func = FUNC_SUM; + set_input_port_default_value(0, Vector3()); +} + +////////////// Scalar Clamp + +String VisualShaderNodeScalarClamp::get_caption() const { + return "ScalarClamp"; +} + +int VisualShaderNodeScalarClamp::get_input_port_count() const { + return 3; +} + +VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeScalarClamp::get_input_port_name(int p_port) const { + if (p_port == 0) + return ""; + else if (p_port == 1) + return "min"; + else if (p_port == 2) + return "max"; + return ""; +} + +int VisualShaderNodeScalarClamp::get_output_port_count() const { + return 1; +} + +VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeScalarClamp::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeScalarClamp::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) const { + return "\t" + p_output_vars[0] + " = clamp( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeScalarClamp::VisualShaderNodeScalarClamp() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 1.0); +} + +////////////// Vector Clamp + +String VisualShaderNodeVectorClamp::get_caption() const { + return "VectorClamp"; +} + +int VisualShaderNodeVectorClamp::get_input_port_count() const { + return 3; +} + +VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorClamp::get_input_port_name(int p_port) const { + if (p_port == 0) + return ""; + else if (p_port == 1) + return "min"; + else if (p_port == 2) + return "max"; + return ""; +} + +int VisualShaderNodeVectorClamp::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorClamp::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeVectorClamp::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) const { + return "\t" + p_output_vars[0] + " = clamp( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeVectorClamp::VisualShaderNodeVectorClamp() { + set_input_port_default_value(0, Vector3(0, 0, 0)); + set_input_port_default_value(1, Vector3(0, 0, 0)); + set_input_port_default_value(2, Vector3(1, 1, 1)); +} + +////////////// FaceForward + +String VisualShaderNodeFaceForward::get_caption() const { + return "FaceForward"; +} + +int VisualShaderNodeFaceForward::get_input_port_count() const { + return 3; +} + +VisualShaderNodeFaceForward::PortType VisualShaderNodeFaceForward::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeFaceForward::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "N"; + case 1: + return "I"; + case 2: + return "Nref"; + default: + return ""; + } +} + +int VisualShaderNodeFaceForward::get_output_port_count() const { + return 1; +} + +VisualShaderNodeFaceForward::PortType VisualShaderNodeFaceForward::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeFaceForward::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeFaceForward::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) const { + return "\t" + p_output_vars[0] + " = faceforward( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeFaceForward::VisualShaderNodeFaceForward() { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); +} + +////////////// Outer Product + +String VisualShaderNodeOuterProduct::get_caption() const { + return "OuterProduct"; +} + +int VisualShaderNodeOuterProduct::get_input_port_count() const { + return 2; +} + +VisualShaderNodeFaceForward::PortType VisualShaderNodeOuterProduct::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeOuterProduct::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "c"; + case 1: + return "r"; + default: + return ""; + } +} + +int VisualShaderNodeOuterProduct::get_output_port_count() const { + return 1; +} + +VisualShaderNodeOuterProduct::PortType VisualShaderNodeOuterProduct::get_output_port_type(int p_port) const { + return PORT_TYPE_TRANSFORM; +} + +String VisualShaderNodeOuterProduct::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeOuterProduct::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) const { + return "\t" + p_output_vars[0] + " = outerProduct( " + p_input_vars[0] + ", " + p_input_vars[1] + " );\n"; +} + +VisualShaderNodeOuterProduct::VisualShaderNodeOuterProduct() { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); +} + +////////////// Vector-Scalar Step + +String VisualShaderNodeVectorScalarStep::get_caption() const { + return "VectorScalarStep"; +} + +int VisualShaderNodeVectorScalarStep::get_input_port_count() const { + return 2; +} + +VisualShaderNodeVectorScalarStep::PortType VisualShaderNodeVectorScalarStep::get_input_port_type(int p_port) const { + if (p_port == 0) { + return PORT_TYPE_SCALAR; + } + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorScalarStep::get_input_port_name(int p_port) const { + if (p_port == 0) + return "edge"; + else if (p_port == 1) + return "x"; + return ""; +} + +int VisualShaderNodeVectorScalarStep::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorScalarStep::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorScalarStep::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeVectorScalarStep::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) const { + return "\t" + p_output_vars[0] + " = step( " + p_input_vars[0] + ", " + p_input_vars[1] + " );\n"; +} + +VisualShaderNodeVectorScalarStep::VisualShaderNodeVectorScalarStep() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); +} + +////////////// Scalar SmoothStep + +String VisualShaderNodeScalarSmoothStep::get_caption() const { + return "ScalarSmoothStep"; +} + +int VisualShaderNodeScalarSmoothStep::get_input_port_count() const { + return 3; +} + +VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeScalarSmoothStep::get_input_port_name(int p_port) const { + if (p_port == 0) + return "edge0"; + else if (p_port == 1) + return "edge1"; + else if (p_port == 2) + return "x"; + return ""; +} + +int VisualShaderNodeScalarSmoothStep::get_output_port_count() const { + return 1; +} + +VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeScalarSmoothStep::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeScalarSmoothStep::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) const { + return "\t" + p_output_vars[0] + " = smoothstep( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeScalarSmoothStep::VisualShaderNodeScalarSmoothStep() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); +} + +////////////// Vector SmoothStep + +String VisualShaderNodeVectorSmoothStep::get_caption() const { + return "VectorSmoothStep"; +} + +int VisualShaderNodeVectorSmoothStep::get_input_port_count() const { + return 3; +} + +VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorSmoothStep::get_input_port_name(int p_port) const { + if (p_port == 0) + return "edge0"; + else if (p_port == 1) + return "edge1"; + else if (p_port == 2) + return "x"; + return ""; +} + +int VisualShaderNodeVectorSmoothStep::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorSmoothStep::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorSmoothStep::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeVectorSmoothStep::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) const { + return "\t" + p_output_vars[0] + " = smoothstep( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeVectorSmoothStep::VisualShaderNodeVectorSmoothStep() { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); +} + +////////////// Vector-Scalar SmoothStep + +String VisualShaderNodeVectorScalarSmoothStep::get_caption() const { + return "VectorScalarSmoothStep"; +} + +int VisualShaderNodeVectorScalarSmoothStep::get_input_port_count() const { + return 3; +} + +VisualShaderNodeVectorScalarSmoothStep::PortType VisualShaderNodeVectorScalarSmoothStep::get_input_port_type(int p_port) const { + if (p_port == 0) { + return PORT_TYPE_SCALAR; + } else if (p_port == 1) { + return PORT_TYPE_SCALAR; + } + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorScalarSmoothStep::get_input_port_name(int p_port) const { + if (p_port == 0) + return "edge0"; + else if (p_port == 1) + return "edge1"; + else if (p_port == 2) + return "x"; + return ""; +} + +int VisualShaderNodeVectorScalarSmoothStep::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorScalarSmoothStep::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorScalarSmoothStep::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeVectorScalarSmoothStep::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) const { + return "\t" + p_output_vars[0] + " = smoothstep( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeVectorScalarSmoothStep::VisualShaderNodeVectorScalarSmoothStep() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); +} + +////////////// Distance + +String VisualShaderNodeVectorDistance::get_caption() const { + return "Distance"; +} + +int VisualShaderNodeVectorDistance::get_input_port_count() const { + return 2; +} + +VisualShaderNodeVectorDistance::PortType VisualShaderNodeVectorDistance::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorDistance::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "p0"; + } else if (p_port == 1) { + return "p1"; + } + return ""; +} + +int VisualShaderNodeVectorDistance::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVectorDistance::PortType VisualShaderNodeVectorDistance::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeVectorDistance::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeVectorDistance::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) const { + return "\t" + p_output_vars[0] + " = distance( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; +} + +VisualShaderNodeVectorDistance::VisualShaderNodeVectorDistance() { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); +} + +////////////// Refract Vector + +String VisualShaderNodeVectorRefract::get_caption() const { + return "Refract"; +} + +int VisualShaderNodeVectorRefract::get_input_port_count() const { + return 3; +} + +VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_input_port_type(int p_port) const { + + if (p_port == 2) { + return PORT_TYPE_SCALAR; + } + + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorRefract::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "I"; + } else if (p_port == 1) { + return "N"; + } else if (p_port == 2) { + return "eta"; + } + return ""; +} + +int VisualShaderNodeVectorRefract::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorRefract::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeVectorRefract::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) const { + return "\t" + p_output_vars[0] + " = refract( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, 0.0); +} + ////////////// Scalar Interp String VisualShaderNodeScalarInterp::get_caption() const { - return "ScalarInterp"; + return "Mix"; } int VisualShaderNodeScalarInterp::get_input_port_count() const { @@ -1396,7 +2383,7 @@ String VisualShaderNodeScalarInterp::get_output_port_name(int p_port) const { return "mix"; } -String VisualShaderNodeScalarInterp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeScalarInterp::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) const { return "\t" + p_output_vars[0] + " = mix( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n"; } @@ -1409,7 +2396,7 @@ VisualShaderNodeScalarInterp::VisualShaderNodeScalarInterp() { ////////////// Vector Interp String VisualShaderNodeVectorInterp::get_caption() const { - return "VectorInterp"; + return "Mix"; } int VisualShaderNodeVectorInterp::get_input_port_count() const { @@ -1438,7 +2425,7 @@ String VisualShaderNodeVectorInterp::get_output_port_name(int p_port) const { return "mix"; } -String VisualShaderNodeVectorInterp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeVectorInterp::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) const { return "\t" + p_output_vars[0] + " = mix( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n"; } @@ -1479,7 +2466,7 @@ String VisualShaderNodeVectorCompose::get_output_port_name(int p_port) const { return "vec"; } -String VisualShaderNodeVectorCompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeVectorCompose::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) const { return "\t" + p_output_vars[0] + " = vec3( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n"; } @@ -1524,7 +2511,7 @@ String VisualShaderNodeTransformCompose::get_output_port_name(int p_port) const return "xform"; } -String VisualShaderNodeTransformCompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeTransformCompose::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) const { return "\t" + p_output_vars[0] + " = mat4( vec4(" + p_input_vars[0] + ", 0.0) , vec4(" + p_input_vars[1] + ", 0.0) , vec4(" + p_input_vars[2] + ",0.0), vec4(" + p_input_vars[3] + ",1.0) );\n"; } @@ -1567,7 +2554,7 @@ String VisualShaderNodeVectorDecompose::get_output_port_name(int p_port) const { } } -String VisualShaderNodeVectorDecompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeVectorDecompose::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) const { String code; code += "\t" + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n"; code += "\t" + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n"; @@ -1613,7 +2600,7 @@ String VisualShaderNodeTransformDecompose::get_output_port_name(int p_port) cons } } -String VisualShaderNodeTransformDecompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeTransformDecompose::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) const { String code; code += "\t" + p_output_vars[0] + " = " + p_input_vars[0] + "[0].xyz;\n"; code += "\t" + p_output_vars[1] + " = " + p_input_vars[0] + "[1].xyz;\n"; @@ -1655,13 +2642,54 @@ String VisualShaderNodeScalarUniform::get_output_port_name(int p_port) const { String VisualShaderNodeScalarUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { return "uniform float " + get_uniform_name() + ";\n"; } -String VisualShaderNodeScalarUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeScalarUniform::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) const { return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } VisualShaderNodeScalarUniform::VisualShaderNodeScalarUniform() { } +////////////// Boolean Uniform + +String VisualShaderNodeBooleanUniform::get_caption() const { + return "BooleanUniform"; +} + +int VisualShaderNodeBooleanUniform::get_input_port_count() const { + return 0; +} + +VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_input_port_type(int p_port) const { + return PORT_TYPE_BOOLEAN; +} + +String VisualShaderNodeBooleanUniform::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeBooleanUniform::get_output_port_count() const { + return 1; +} + +VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_output_port_type(int p_port) const { + return PORT_TYPE_BOOLEAN; +} + +String VisualShaderNodeBooleanUniform::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform bool " + get_uniform_name() + ";\n"; +} + +String VisualShaderNodeBooleanUniform::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) const { + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +} + +VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() { +} + ////////////// Color Uniform String VisualShaderNodeColorUniform::get_caption() const { @@ -1693,7 +2721,7 @@ String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, Visual return "uniform vec4 " + get_uniform_name() + " : hint_color;\n"; } -String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeColorUniform::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) const { String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; return code; @@ -1731,7 +2759,7 @@ String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualS return "uniform vec3 " + get_uniform_name() + ";\n"; } -String VisualShaderNodeVec3Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeVec3Uniform::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) const { return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } @@ -1767,7 +2795,7 @@ String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, Vi return "uniform mat4 " + get_uniform_name() + ";\n"; } -String VisualShaderNodeTransformUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeTransformUniform::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) const { return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } @@ -1823,7 +2851,7 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu return code; } -String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeTextureUniform::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) const { String id = get_uniform_name(); String code = "\t{\n"; @@ -1918,9 +2946,209 @@ String VisualShaderNodeCubeMapUniform::get_output_port_name(int p_port) const { return p_port == 0 ? "rgb" : "alpha"; } -String VisualShaderNodeCubeMapUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const { +String VisualShaderNodeCubeMapUniform::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) const { return String(); } VisualShaderNodeCubeMapUniform::VisualShaderNodeCubeMapUniform() { } + +////////////// If + +String VisualShaderNodeIf::get_caption() const { + return "If"; +} + +int VisualShaderNodeIf::get_input_port_count() const { + return 6; +} + +VisualShaderNodeIf::PortType VisualShaderNodeIf::get_input_port_type(int p_port) const { + if (p_port == 0 || p_port == 1 || p_port == 2) { + return PORT_TYPE_SCALAR; + } + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeIf::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "a"; + case 1: + return "b"; + case 2: + return "tolerance"; + case 3: + return "a == b"; + case 4: + return "a > b"; + case 5: + return "a < b"; + default: + return ""; + } +} + +int VisualShaderNodeIf::get_output_port_count() const { + return 1; +} + +VisualShaderNodeIf::PortType VisualShaderNodeIf::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeIf::get_output_port_name(int p_port) const { + return "result"; +} + +String VisualShaderNodeIf::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) const { + + String code; + code += "\tif(abs(" + p_input_vars[0] + "-" + p_input_vars[1] + ")<" + p_input_vars[2] + ")\n"; // abs(a - b) < tolerance eg. a == b + code += "\t{\n"; + code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[3] + ";\n"; + code += "\t}\n"; + code += "\telse if(" + p_input_vars[0] + "<" + p_input_vars[1] + ")\n"; // a < b + code += "\t{\n"; + code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[5] + ";\n"; + code += "\t}\n"; + code += "\telse\n"; // a > b (or a >= b if abs(a - b) < tolerance is false) + code += "\t{\n"; + code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[4] + ";\n"; + code += "\t}\n"; + return code; +} + +VisualShaderNodeIf::VisualShaderNodeIf() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, CMP_EPSILON); + set_input_port_default_value(3, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(4, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(5, Vector3(0.0, 0.0, 0.0)); +} + +////////////// Switch + +String VisualShaderNodeSwitch::get_caption() const { + return "Switch"; +} + +int VisualShaderNodeSwitch::get_input_port_count() const { + return 3; +} + +VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int p_port) const { + if (p_port == 0) { + return PORT_TYPE_BOOLEAN; + } + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeSwitch::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "value"; + case 1: + return "true"; + case 2: + return "false"; + default: + return ""; + } +} + +int VisualShaderNodeSwitch::get_output_port_count() const { + return 1; +} + +VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeSwitch::get_output_port_name(int p_port) const { + return "result"; +} + +String VisualShaderNodeSwitch::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) const { + + String code; + code += "\tif(" + p_input_vars[0] + ")\n"; + code += "\t{\n"; + code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[1] + ";\n"; + code += "\t}\n"; + code += "\telse\n"; + code += "\t{\n"; + code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[2] + ";\n"; + code += "\t}\n"; + return code; +} + +VisualShaderNodeSwitch::VisualShaderNodeSwitch() { + set_input_port_default_value(0, false); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); +} + +////////////// Fresnel + +String VisualShaderNodeFresnel::get_caption() const { + return "Fresnel"; +} + +int VisualShaderNodeFresnel::get_input_port_count() const { + return 4; +} + +VisualShaderNodeFresnel::PortType VisualShaderNodeFresnel::get_input_port_type(int p_port) const { + switch (p_port) { + case 0: + return PORT_TYPE_VECTOR; + case 1: + return PORT_TYPE_VECTOR; + case 2: + return PORT_TYPE_BOOLEAN; + case 3: + return PORT_TYPE_SCALAR; + default: + return PORT_TYPE_VECTOR; + } +} + +String VisualShaderNodeFresnel::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "normal"; + case 1: + return "view"; + case 2: + return "invert"; + case 3: + return "power"; + default: + return ""; + } +} + +int VisualShaderNodeFresnel::get_output_port_count() const { + return 1; +} + +VisualShaderNodeFresnel::PortType VisualShaderNodeFresnel::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeFresnel::get_output_port_name(int p_port) const { + return "result"; +} + +String VisualShaderNodeFresnel::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) const { + return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + p_input_vars[0] + ", " + p_input_vars[1] + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + p_input_vars[0] + ", " + p_input_vars[1] + "), 0.0, 1.0), " + p_input_vars[3] + "));"; +} + +VisualShaderNodeFresnel::VisualShaderNodeFresnel() { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, false); + set_input_port_default_value(3, 1.0); +} diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 3057f7239a..df753276e4 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -33,10 +33,12 @@ #include "scene/resources/visual_shader.h" -/// CONSTANTS /// +/////////////////////////////////////// +/// CONSTANTS +/////////////////////////////////////// class VisualShaderNodeScalarConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarConstant, VisualShaderNode) + GDCLASS(VisualShaderNodeScalarConstant, VisualShaderNode); float constant; protected: @@ -53,7 +55,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_constant(float p_value); float get_constant() const; @@ -63,8 +65,40 @@ public: VisualShaderNodeScalarConstant(); }; +/////////////////////////////////////// + +class VisualShaderNodeBooleanConstant : public VisualShaderNode { + GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNode); + bool constant; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + void set_constant(bool p_value); + bool get_constant() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeBooleanConstant(); +}; + +/////////////////////////////////////// + class VisualShaderNodeColorConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode) + GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode); Color constant; protected: @@ -81,7 +115,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_constant(Color p_value); Color get_constant() const; @@ -91,8 +125,10 @@ public: VisualShaderNodeColorConstant(); }; +/////////////////////////////////////// + class VisualShaderNodeVec3Constant : public VisualShaderNode { - GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNode) + GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNode); Vector3 constant; protected: @@ -109,7 +145,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_constant(Vector3 p_value); Vector3 get_constant() const; @@ -119,8 +155,10 @@ public: VisualShaderNodeVec3Constant(); }; +/////////////////////////////////////// + class VisualShaderNodeTransformConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNode) + GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNode); Transform constant; protected: @@ -137,7 +175,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_constant(Transform p_value); Transform get_constant() const; @@ -147,10 +185,12 @@ public: VisualShaderNodeTransformConstant(); }; -////////////////////////////////// +/////////////////////////////////////// +/// TEXTURES +/////////////////////////////////////// class VisualShaderNodeTexture : public VisualShaderNode { - GDCLASS(VisualShaderNodeTexture, VisualShaderNode) + GDCLASS(VisualShaderNodeTexture, VisualShaderNode); Ref<Texture> texture; public: @@ -187,7 +227,7 @@ public: 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) 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 + 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 void set_source(Source p_source); Source get_source() const; @@ -208,10 +248,10 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeTexture::TextureType) VARIANT_ENUM_CAST(VisualShaderNodeTexture::Source) -////////////////////////////////// +/////////////////////////////////////// class VisualShaderNodeCubeMap : public VisualShaderNode { - GDCLASS(VisualShaderNodeCubeMap, VisualShaderNode) + GDCLASS(VisualShaderNodeCubeMap, VisualShaderNode); Ref<CubeMap> cube_map; public: @@ -240,7 +280,7 @@ public: 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) 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 + 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 void set_cube_map(Ref<CubeMap> p_value); Ref<CubeMap> get_cube_map() const; @@ -254,10 +294,13 @@ public: }; VARIANT_ENUM_CAST(VisualShaderNodeCubeMap::TextureType) + +/////////////////////////////////////// +/// OPS /////////////////////////////////////// class VisualShaderNodeScalarOp : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarOp, VisualShaderNode) + GDCLASS(VisualShaderNodeScalarOp, VisualShaderNode); public: enum Operator { @@ -269,7 +312,8 @@ public: OP_POW, OP_MAX, OP_MIN, - OP_ATAN2 + OP_ATAN2, + OP_STEP }; protected: @@ -288,7 +332,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_operator(Operator p_op); Operator get_operator() const; @@ -301,7 +345,7 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeScalarOp::Operator) class VisualShaderNodeVectorOp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorOp, VisualShaderNode) + GDCLASS(VisualShaderNodeVectorOp, VisualShaderNode); public: enum Operator { @@ -313,8 +357,10 @@ public: OP_POW, OP_MAX, OP_MIN, - OP_CROSS - + OP_CROSS, + OP_ATAN2, + OP_REFLECT, + OP_STEP }; protected: @@ -333,7 +379,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_operator(Operator p_op); Operator get_operator() const; @@ -345,8 +391,10 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeVectorOp::Operator) +/////////////////////////////////////// + class VisualShaderNodeColorOp : public VisualShaderNode { - GDCLASS(VisualShaderNodeColorOp, VisualShaderNode) + GDCLASS(VisualShaderNodeColorOp, VisualShaderNode); public: enum Operator { @@ -358,7 +406,7 @@ public: OP_DODGE, OP_BURN, OP_SOFT_LIGHT, - OP_HARD_LIGHT, + OP_HARD_LIGHT }; protected: @@ -377,7 +425,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_operator(Operator p_op); Operator get_operator() const; @@ -389,13 +437,19 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeColorOp::Operator) +/////////////////////////////////////// +/// TRANSFORM-TRANSFORM MULTIPLICATION +/////////////////////////////////////// + class VisualShaderNodeTransformMult : public VisualShaderNode { - GDCLASS(VisualShaderNodeTransformMult, VisualShaderNode) + GDCLASS(VisualShaderNodeTransformMult, VisualShaderNode); public: enum Operator { OP_AxB, OP_BxA, + OP_AxB_COMP, + OP_BxA_COMP }; protected: @@ -414,7 +468,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_operator(Operator p_op); Operator get_operator() const; @@ -426,8 +480,12 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeTransformMult::Operator) +/////////////////////////////////////// +/// TRANSFORM-VECTOR MULTIPLICATION +/////////////////////////////////////// + class VisualShaderNodeTransformVecMult : public VisualShaderNode { - GDCLASS(VisualShaderNodeTransformVecMult, VisualShaderNode) + GDCLASS(VisualShaderNodeTransformVecMult, VisualShaderNode); public: enum Operator { @@ -453,7 +511,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_operator(Operator p_op); Operator get_operator() const; @@ -466,9 +524,11 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeTransformVecMult::Operator) /////////////////////////////////////// +/// SCALAR FUNC +/////////////////////////////////////// class VisualShaderNodeScalarFunc : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarFunc, VisualShaderNode) + GDCLASS(VisualShaderNodeScalarFunc, VisualShaderNode); public: enum Function { @@ -492,6 +552,18 @@ public: FUNC_FRAC, FUNC_SATURATE, FUNC_NEGATE, + FUNC_ACOSH, + FUNC_ASINH, + FUNC_ATANH, + FUNC_DEGREES, + FUNC_EXP2, + FUNC_INVERSE_SQRT, + FUNC_LOG2, + FUNC_RADIANS, + FUNC_RECIPROCAL, + FUNC_ROUNDEVEN, + FUNC_TRUNC, + FUNC_ONEMINUS }; protected: @@ -510,7 +582,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_function(Function p_func); Function get_function() const; @@ -523,9 +595,11 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeScalarFunc::Function) /////////////////////////////////////// +/// VECTOR FUNC +/////////////////////////////////////// class VisualShaderNodeVectorFunc : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorFunc, VisualShaderNode) + GDCLASS(VisualShaderNodeVectorFunc, VisualShaderNode); public: enum Function { @@ -535,6 +609,35 @@ public: FUNC_RECIPROCAL, FUNC_RGB2HSV, FUNC_HSV2RGB, + FUNC_ABS, + FUNC_ACOS, + FUNC_ACOSH, + FUNC_ASIN, + FUNC_ASINH, + FUNC_ATAN, + FUNC_ATANH, + FUNC_CEIL, + FUNC_COS, + FUNC_COSH, + FUNC_DEGREES, + FUNC_EXP, + FUNC_EXP2, + FUNC_FLOOR, + FUNC_FRAC, + FUNC_INVERSE_SQRT, + FUNC_LOG, + FUNC_LOG2, + FUNC_RADIANS, + FUNC_ROUND, + FUNC_ROUNDEVEN, + FUNC_SIGN, + FUNC_SIN, + FUNC_SINH, + FUNC_SQRT, + FUNC_TAN, + FUNC_TANH, + FUNC_TRUNC, + FUNC_ONEMINUS }; protected: @@ -553,7 +656,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 void set_function(Function p_func); Function get_function() const; @@ -566,9 +669,93 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeVectorFunc::Function) /////////////////////////////////////// +/// COLOR FUNC +/////////////////////////////////////// + +class VisualShaderNodeColorFunc : public VisualShaderNode { + GDCLASS(VisualShaderNodeColorFunc, VisualShaderNode); + +public: + enum Function { + FUNC_GRAYSCALE, + FUNC_SEPIA + }; + +protected: + Function func; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + void set_function(Function p_op); + Function get_function() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeColorFunc(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeColorFunc::Function) + +/////////////////////////////////////// +/// TRANSFORM FUNC +/////////////////////////////////////// + +class VisualShaderNodeTransformFunc : public VisualShaderNode { + GDCLASS(VisualShaderNodeTransformFunc, VisualShaderNode); + +public: + enum Function { + FUNC_INVERSE, + FUNC_TRANSPOSE + }; + +protected: + Function func; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + void set_function(Function p_op); + Function get_function() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeTransformFunc(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeTransformFunc::Function) + +/////////////////////////////////////// +/// DOT +/////////////////////////////////////// class VisualShaderNodeDotProduct : public VisualShaderNode { - GDCLASS(VisualShaderNodeDotProduct, VisualShaderNode) + GDCLASS(VisualShaderNodeDotProduct, VisualShaderNode); public: virtual String get_caption() const; @@ -581,15 +768,17 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeDotProduct(); }; /////////////////////////////////////// +/// LENGTH +/////////////////////////////////////// class VisualShaderNodeVectorLen : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorLen, VisualShaderNode) + GDCLASS(VisualShaderNodeVectorLen, VisualShaderNode); public: virtual String get_caption() const; @@ -602,15 +791,346 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeVectorLen(); }; /////////////////////////////////////// +/// DETERMINANT +/////////////////////////////////////// + +class VisualShaderNodeDeterminant : public VisualShaderNode { + GDCLASS(VisualShaderNodeDeterminant, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeDeterminant(); +}; + +/////////////////////////////////////// +/// CLAMP +/////////////////////////////////////// + +class VisualShaderNodeScalarClamp : public VisualShaderNode { + GDCLASS(VisualShaderNodeScalarClamp, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeScalarClamp(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeVectorClamp : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorClamp, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeVectorClamp(); +}; + +/////////////////////////////////////// +/// DERIVATIVE FUNCTIONS +/////////////////////////////////////// + +class VisualShaderNodeScalarDerivativeFunc : public VisualShaderNode { + GDCLASS(VisualShaderNodeScalarDerivativeFunc, VisualShaderNode); + +public: + enum Function { + FUNC_SUM, + FUNC_X, + FUNC_Y + }; + +protected: + Function func; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + void set_function(Function p_op); + Function get_function() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeScalarDerivativeFunc(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeScalarDerivativeFunc::Function) + +/////////////////////////////////////// + +class VisualShaderNodeVectorDerivativeFunc : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorDerivativeFunc, VisualShaderNode); + +public: + enum Function { + FUNC_SUM, + FUNC_X, + FUNC_Y + }; + +protected: + Function func; + + static void _bind_methods(); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + void set_function(Function p_op); + Function get_function() const; + + virtual Vector<StringName> get_editable_properties() const; + + VisualShaderNodeVectorDerivativeFunc(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeVectorDerivativeFunc::Function) + +/////////////////////////////////////// +/// FACEFORWARD +/////////////////////////////////////// + +class VisualShaderNodeFaceForward : public VisualShaderNode { + GDCLASS(VisualShaderNodeFaceForward, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeFaceForward(); +}; + +/////////////////////////////////////// +/// OUTER PRODUCT +/////////////////////////////////////// + +class VisualShaderNodeOuterProduct : public VisualShaderNode { + GDCLASS(VisualShaderNodeOuterProduct, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeOuterProduct(); +}; + +/////////////////////////////////////// +/// STEP +/////////////////////////////////////// + +class VisualShaderNodeVectorScalarStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorScalarStep, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeVectorScalarStep(); +}; + +/////////////////////////////////////// +/// SMOOTHSTEP +/////////////////////////////////////// + +class VisualShaderNodeScalarSmoothStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeScalarSmoothStep, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeScalarSmoothStep(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeVectorSmoothStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorSmoothStep, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeVectorSmoothStep(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeVectorScalarSmoothStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorScalarSmoothStep, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeVectorScalarSmoothStep(); +}; + +/////////////////////////////////////// +/// DISTANCE +/////////////////////////////////////// + +class VisualShaderNodeVectorDistance : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorDistance, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeVectorDistance(); +}; + +/////////////////////////////////////// +/// REFRACT +/////////////////////////////////////// + +class VisualShaderNodeVectorRefract : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorRefract, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeVectorRefract(); +}; + +/////////////////////////////////////// +/// MIX +/////////////////////////////////////// class VisualShaderNodeScalarInterp : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarInterp, VisualShaderNode) + GDCLASS(VisualShaderNodeScalarInterp, VisualShaderNode); public: virtual String get_caption() const; @@ -623,7 +1143,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeScalarInterp(); }; @@ -631,7 +1151,7 @@ public: /////////////////////////////////////// class VisualShaderNodeVectorInterp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorInterp, VisualShaderNode) + GDCLASS(VisualShaderNodeVectorInterp, VisualShaderNode); public: virtual String get_caption() const; @@ -644,15 +1164,17 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeVectorInterp(); }; /////////////////////////////////////// +/// COMPOSE +/////////////////////////////////////// class VisualShaderNodeVectorCompose : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorCompose, VisualShaderNode) + GDCLASS(VisualShaderNodeVectorCompose, VisualShaderNode); public: virtual String get_caption() const; @@ -665,7 +1187,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeVectorCompose(); }; @@ -673,7 +1195,7 @@ public: /////////////////////////////////////// class VisualShaderNodeTransformCompose : public VisualShaderNode { - GDCLASS(VisualShaderNodeTransformCompose, VisualShaderNode) + GDCLASS(VisualShaderNodeTransformCompose, VisualShaderNode); public: virtual String get_caption() const; @@ -686,15 +1208,17 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeTransformCompose(); }; /////////////////////////////////////// +/// DECOMPOSE +/////////////////////////////////////// class VisualShaderNodeVectorDecompose : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorDecompose, VisualShaderNode) + GDCLASS(VisualShaderNodeVectorDecompose, VisualShaderNode); public: virtual String get_caption() const; @@ -707,7 +1231,7 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeVectorDecompose(); }; @@ -715,7 +1239,7 @@ public: /////////////////////////////////////// class VisualShaderNodeTransformDecompose : public VisualShaderNode { - GDCLASS(VisualShaderNodeTransformDecompose, VisualShaderNode) + GDCLASS(VisualShaderNodeTransformDecompose, VisualShaderNode); public: virtual String get_caption() const; @@ -728,15 +1252,17 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeTransformDecompose(); }; /////////////////////////////////////// +/// UNIFORMS +/////////////////////////////////////// class VisualShaderNodeScalarUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeScalarUniform, VisualShaderNodeUniform) + GDCLASS(VisualShaderNodeScalarUniform, VisualShaderNodeUniform); public: virtual String get_caption() const; @@ -750,13 +1276,37 @@ public: virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeScalarUniform(); }; +/////////////////////////////////////// + +class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform { + GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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 + + VisualShaderNodeBooleanUniform(); +}; + +/////////////////////////////////////// + class VisualShaderNodeColorUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform) + GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform); public: virtual String get_caption() const; @@ -770,13 +1320,15 @@ public: virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeColorUniform(); }; +/////////////////////////////////////// + class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform) + GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform); public: virtual String get_caption() const; @@ -790,13 +1342,15 @@ public: virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeVec3Uniform(); }; +/////////////////////////////////////// + class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform) + GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform); public: virtual String get_caption() const; @@ -810,15 +1364,16 @@ public: virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeTransformUniform(); }; -////////////////////////////////// +/////////////////////////////////////// class VisualShaderNodeTextureUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeTextureUniform, VisualShaderNodeUniform) + GDCLASS(VisualShaderNodeTextureUniform, VisualShaderNodeUniform); + public: enum TextureType { TYPE_DATA, @@ -851,7 +1406,7 @@ public: virtual String get_output_port_name(int p_port) 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) 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 + 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 Vector<StringName> get_editable_properties() const; @@ -867,10 +1422,10 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureType) VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::ColorDefault) -////////////////////////////////// +/////////////////////////////////////// class VisualShaderNodeCubeMapUniform : public VisualShaderNode { - GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNode) + GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNode); public: virtual String get_caption() const; @@ -883,9 +1438,78 @@ public: virtual PortType get_output_port_type(int p_port) const; virtual String get_output_port_name(int p_port) 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) 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 + 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 VisualShaderNodeCubeMapUniform(); }; +/////////////////////////////////////// +/// IF +/////////////////////////////////////// + +class VisualShaderNodeIf : public VisualShaderNode { + GDCLASS(VisualShaderNodeIf, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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; + + VisualShaderNodeIf(); +}; + +/////////////////////////////////////// +/// SWITCH +/////////////////////////////////////// + +class VisualShaderNodeSwitch : public VisualShaderNode { + GDCLASS(VisualShaderNodeSwitch, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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; + + VisualShaderNodeSwitch(); +}; + +/////////////////////////////////////// +/// FRESNEL +/////////////////////////////////////// + +class VisualShaderNodeFresnel : public VisualShaderNode { + GDCLASS(VisualShaderNodeFresnel, VisualShaderNode); + +public: + virtual String get_caption() const; + + 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 int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) 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; + + VisualShaderNodeFresnel(); +}; + #endif // VISUAL_SHADER_NODES_H diff --git a/scene/resources/world.cpp b/scene/resources/world.cpp index b4588cd87c..0ca5d7eb36 100644 --- a/scene/resources/world.cpp +++ b/scene/resources/world.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/world.h b/scene/resources/world.h index 4ba6b13476..05d5ceb411 100644 --- a/scene/resources/world.h +++ b/scene/resources/world.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index dd78d04104..13b45f58dc 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index 88ad392f85..e0c671e1a7 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index e468b3dab4..634f4d7160 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -203,4 +203,6 @@ SceneStringNames::SceneStringNames() { _mesh_changed = StaticCString::create("_mesh_changed"); parameters_base_path = "parameters/"; + + tracks_changed = "tracks_changed"; } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 25e2c5d4a6..bc75165b8c 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* 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 */ @@ -32,7 +32,7 @@ #define SCENE_STRING_NAMES_H #include "core/node_path.h" -#include "core/string_db.h" +#include "core/string_name.h" class SceneStringNames { friend void register_scene_types(); @@ -205,6 +205,8 @@ public: StringName parameters_base_path; + StringName tracks_changed; + enum { MAX_MATERIALS = 32 }; |