diff options
Diffstat (limited to 'scene/resources')
137 files changed, 12446 insertions, 7204 deletions
diff --git a/scene/resources/SCsub b/scene/resources/SCsub index 3a86b22835..f4dc7a46fb 100644 --- a/scene/resources/SCsub +++ b/scene/resources/SCsub @@ -2,6 +2,25 @@ Import("env") -env.add_source_files(env.scene_sources, "*.cpp") +# Thirdparty code + +thirdparty_obj = [] + +thirdparty_sources = "#thirdparty/misc/mikktspace.c" + +env_thirdparty = env.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) +env.scene_sources += thirdparty_obj + +# Godot source files + +scene_obj = [] + +env.add_source_files(scene_obj, "*.cpp") +env.scene_sources += scene_obj + +# Needed to force rebuilding the scene files when the thirdparty code is updated. +env.Depends(scene_obj, thirdparty_obj) SConscript("default_theme/SCsub") diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index c9fc68233d..cc1dafd0db 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,9 +31,7 @@ #include "animation.h" #include "scene/scene_string_names.h" -#include "core/math/geometry.h" - -#define ANIM_MIN_LENGTH 0.001 +#include "core/math/geometry_3d.h" bool Animation::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; @@ -582,6 +580,10 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const { } } +void Animation::reset_state() { + clear(); +} + int Animation::add_track(TrackType p_type, int p_at_pos) { if (p_at_pos < 0 || p_at_pos >= tracks.size()) { p_at_pos = tracks.size(); @@ -721,7 +723,6 @@ bool Animation::track_get_interpolation_loop_wrap(int p_track) const { /* template<class T> int Animation::_insert_pos(float p_time, T& p_keys) { - // simple, linear time inset that should be fast enough in reality. int idx=p_keys.size(); @@ -734,14 +735,12 @@ int Animation::_insert_pos(float p_time, T& p_keys) { p_keys.insert(idx,T()); return idx; } else if (p_keys[idx-1].time == p_time) { - // condition for replacing. return idx-1; } idx--; } - } */ @@ -752,7 +751,9 @@ int Animation::_insert(float p_time, T &p_keys, const V &p_value) { while (true) { // Condition for replacement. if (idx > 0 && Math::is_equal_approx(p_keys[idx - 1].time, p_time)) { + float transition = p_keys[idx - 1].transition; p_keys.write[idx - 1] = p_value; + p_keys.write[idx - 1].transition = transition; return idx - 1; // Condition for insert. @@ -811,8 +812,8 @@ int Animation::transform_track_insert_key(int p_track, float p_time, const Vecto return ret; } -void Animation::track_remove_key_at_position(int p_track, float p_pos) { - int idx = track_find_key(p_track, p_pos, true); +void Animation::track_remove_key_at_time(int p_track, float p_time) { + int idx = track_find_key(p_track, p_time, true); ERR_FAIL_COND(idx < 0); track_remove_key(p_track, idx); } @@ -1607,7 +1608,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola bool result = true; int next = 0; - float c = 0; + float c = 0.0; // prepare for all cases of interpolation if (loop && p_loop_wrap) { @@ -2281,8 +2282,8 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const { int iterations = 10; 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 low = 0.0; // 0% of the current animation segment + float high = 1.0; // 100% of the current animation segment float middle; Vector2 start(0, bt->values[idx].value.value); @@ -2577,7 +2578,10 @@ 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)); + if (track_get_type(p_track) == TYPE_VALUE) { + 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)); } @@ -2606,7 +2610,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("transform_track_insert_key", "track_idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key); ClassDB::bind_method(D_METHOD("track_insert_key", "track_idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1)); ClassDB::bind_method(D_METHOD("track_remove_key", "track_idx", "key_idx"), &Animation::track_remove_key); - ClassDB::bind_method(D_METHOD("track_remove_key_at_position", "track_idx", "position"), &Animation::track_remove_key_at_position); + ClassDB::bind_method(D_METHOD("track_remove_key_at_time", "track_idx", "time"), &Animation::track_remove_key_at_time); ClassDB::bind_method(D_METHOD("track_set_key_value", "track_idx", "key", "value"), &Animation::track_set_key_value); ClassDB::bind_method(D_METHOD("track_set_key_transition", "track_idx", "key_idx", "transition"), &Animation::track_set_key_transition); ClassDB::bind_method(D_METHOD("track_set_key_time", "track_idx", "key_idx", "time"), &Animation::track_set_key_time); @@ -2628,6 +2632,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "track_idx"), &Animation::value_track_get_update_mode); ClassDB::bind_method(D_METHOD("value_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_value_track_get_key_indices); + ClassDB::bind_method(D_METHOD("value_track_interpolate", "track_idx", "time_sec"), &Animation::value_track_interpolate); ClassDB::bind_method(D_METHOD("method_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_method_track_get_key_indices); ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name); @@ -2730,7 +2735,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons } Vector3 s[2] = { v0, v2 }; - real_t d = Geometry::get_closest_point_to_segment(v1, s).distance_to(v1); + real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); if (d > pd.length() * p_alowed_linear_err) { return false; //beyond allowed error for colinearity @@ -2820,7 +2825,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons } Vector3 s[2] = { v0, v2 }; - real_t d = Geometry::get_closest_point_to_segment(v1, s).distance_to(v1); + real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); if (d > pd.length() * p_alowed_linear_err) { return false; //beyond allowed error for colinearity @@ -2835,7 +2840,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons erase = true; } else { erase = true; - real_t lt = -1; + real_t lt = -1.0; for (int j = 0; j < 3; j++) { //search for t on first, one must be it if (t[j] != -1) { @@ -2918,11 +2923,7 @@ void Animation::optimize(float p_allowed_linear_err, float p_allowed_angular_err } } -Animation::Animation() { - step = 0.1; - loop = false; - length = 1; -} +Animation::Animation() {} Animation::~Animation() { for (int i = 0; i < tracks.size(); i++) { diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 722a400fd6..fd22cc445c 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,9 @@ #ifndef ANIMATION_H #define ANIMATION_H -#include "core/resource.h" +#include "core/io/resource.h" + +#define ANIM_MIN_LENGTH 0.001 class Animation : public Resource { GDCLASS(Animation, Resource); @@ -63,28 +65,19 @@ public: private: struct Track { - TrackType type; - InterpolationType interpolation; - bool loop_wrap; + TrackType type = TrackType::TYPE_ANIMATION; + InterpolationType interpolation = INTERPOLATION_LINEAR; + bool loop_wrap = true; NodePath path; // path to something - bool imported; - bool enabled; - Track() { - interpolation = INTERPOLATION_LINEAR; - imported = false; - loop_wrap = true; - enabled = true; - } + bool imported = false; + bool enabled = false; + Track() {} virtual ~Track() {} }; struct Key { - float transition; - float time; // time in secs - Key() { - transition = 1; - time = 0; - } + float transition = 1.0; + float time = 0.0; // time in secs }; // transform key holds either Vector3 or Quaternion @@ -110,13 +103,12 @@ private: /* PROPERTY VALUE TRACK */ struct ValueTrack : public Track { - UpdateMode update_mode; - bool update_on_seek; + UpdateMode update_mode = UPDATE_CONTINUOUS; + bool update_on_seek = false; Vector<TKey<Variant>> values; ValueTrack() { type = TYPE_VALUE; - update_mode = UPDATE_CONTINUOUS; } }; @@ -137,7 +129,7 @@ private: struct BezierKey { Vector2 in_handle; //relative (x always <0) Vector2 out_handle; //relative (x always >0) - float value; + float value = 0.0; }; struct BezierTrack : public Track { @@ -152,11 +144,9 @@ private: struct AudioKey { RES stream; - float start_offset; //offset from start - float end_offset; //offset from end, if 0 then full length or infinite + float start_offset = 0.0; //offset from start + float end_offset = 0.0; //offset from end, if 0 then full length or infinite AudioKey() { - start_offset = 0; - end_offset = 0; } }; @@ -215,9 +205,9 @@ private: _FORCE_INLINE_ void _value_track_get_key_indices_in_range(const ValueTrack *vt, float from_time, float to_time, List<int> *p_indices) const; _FORCE_INLINE_ void _method_track_get_key_indices_in_range(const MethodTrack *mt, float from_time, float to_time, List<int> *p_indices) const; - float length; - float step; - bool loop; + float length = 1.0; + float step = 0.1; + bool loop = false; // bind helpers private: @@ -262,6 +252,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + static void _bind_methods(); public: @@ -293,7 +285,7 @@ public: 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); + void track_remove_key_at_time(int p_track, float p_time); int track_get_key_count(int p_track) const; Variant track_get_key_value(int p_track, int p_key_idx) const; float track_get_key_time(int p_track, int p_key_idx) const; diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index f02e7987a9..06a91fb2f8 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +261,8 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in sign = -1; } - float base_rate = AudioServer::get_singleton()->get_mix_rate(); + float global_rate_scale = AudioServer::get_singleton()->get_global_rate_scale(); + float base_rate = AudioServer::get_singleton()->get_mix_rate() * global_rate_scale; float srate = base->mix_rate; srate *= p_rate_scale; float fincrement = srate / base_rate; @@ -402,11 +403,7 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in } } -AudioStreamPlaybackSample::AudioStreamPlaybackSample() { - active = false; - offset = 0; - sign = 1; -} +AudioStreamPlaybackSample::AudioStreamPlaybackSample() {} ///////////////////// @@ -650,16 +647,7 @@ void AudioStreamSample::_bind_methods() { BIND_ENUM_CONSTANT(LOOP_BACKWARD); } -AudioStreamSample::AudioStreamSample() { - format = FORMAT_8_BITS; - loop_mode = LOOP_DISABLED; - stereo = false; - loop_begin = 0; - loop_end = 0; - mix_rate = 44100; - data = nullptr; - data_bytes = 0; -} +AudioStreamSample::AudioStreamSample() {} AudioStreamSample::~AudioStreamSample() { if (data) { diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h index 2bd358117c..70b8ba79ad 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,19 +44,19 @@ class AudioStreamPlaybackSample : public AudioStreamPlayback { }; struct IMA_ADPCM_State { - int16_t step_index; - int32_t predictor; + int16_t step_index = 0; + int32_t predictor = 0; /* values at loop point */ - int16_t loop_step_index; - int32_t loop_predictor; - int32_t last_nibble; - int32_t loop_pos; - int32_t window_ofs; + int16_t loop_step_index = 0; + int32_t loop_predictor = 0; + int32_t last_nibble = 0; + int32_t loop_pos = 0; + int32_t window_ofs = 0; } ima_adpcm[2]; - int64_t offset; - int sign; - bool active; + int64_t offset = 0; + int sign = 1; + bool active = false; friend class AudioStreamSample; Ref<AudioStreamSample> base; @@ -64,16 +64,16 @@ class AudioStreamPlaybackSample : public AudioStreamPlayback { void do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &offset, int32_t &increment, uint32_t amount, IMA_ADPCM_State *ima_adpcm); public: - virtual void start(float p_from_pos = 0.0); - virtual void stop(); - virtual bool is_playing() const; + virtual void start(float p_from_pos = 0.0) override; + virtual void stop() override; + virtual bool is_playing() const override; - virtual int get_loop_count() const; //times it looped + virtual int get_loop_count() const override; //times it looped - virtual float get_playback_position() const; - virtual void seek(float p_time); + virtual float get_playback_position() const override; + virtual void seek(float p_time) override; - virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames); + virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override; AudioStreamPlaybackSample(); }; @@ -103,14 +103,14 @@ private: DATA_PAD = 16 //padding for interpolation }; - Format format; - LoopMode loop_mode; - bool stereo; - int loop_begin; - int loop_end; - int mix_rate; - void *data; - uint32_t data_bytes; + Format format = FORMAT_8_BITS; + LoopMode loop_mode = LOOP_DISABLED; + bool stereo = false; + int loop_begin = 0; + int loop_end = 0; + int mix_rate = 44100; + void *data = nullptr; + uint32_t data_bytes = 0; protected: static void _bind_methods(); @@ -134,15 +134,15 @@ public: void set_stereo(bool p_enable); bool is_stereo() const; - virtual float get_length() const; //if supported, otherwise return 0 + virtual float get_length() const override; //if supported, otherwise return 0 void set_data(const Vector<uint8_t> &p_data); Vector<uint8_t> get_data() const; Error save_to_wav(const String &p_path); - virtual Ref<AudioStreamPlayback> instance_playback(); - virtual String get_stream_name() const; + virtual Ref<AudioStreamPlayback> instance_playback() override; + virtual String get_stream_name() const override; AudioStreamSample(); ~AudioStreamSample(); diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 10f0de8ff8..8ffc7b4b4c 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 @@ void BitMap::create(const Size2 &p_size) { } void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshold) { - ERR_FAIL_COND(p_image.is_null() || p_image->empty()); + ERR_FAIL_COND(p_image.is_null() || p_image->is_empty()); Ref<Image> img = p_image->duplicate(); img->convert(Image::FORMAT_LA8); ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8); @@ -63,7 +63,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol } void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) { - Rect2i current = Rect2i(0, 0, width, height).clip(p_rect); + Rect2i current = Rect2i(0, 0, width, height).intersection(p_rect); uint8_t *data = bitmask.ptrw(); for (int i = current.position.x; i < current.position.x + current.size.x; i++) { @@ -346,7 +346,7 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) { } int index = -1; - float dist = 0; + float dist = 0.0; //not looping first and last point for (size_t i = 1, size = v.size(); i < size - 1; ++i) { float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]); @@ -406,8 +406,8 @@ static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, struct FillBitsStackEntry { Point2i pos; - int i; - int j; + int i = 0; + int j = 0; }; static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) { @@ -482,7 +482,7 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_ } Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const { - Rect2i r = Rect2i(0, 0, width, height).clip(p_rect); + Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect); print_verbose("BitMap: Rect: " + r); Point2i from; @@ -522,7 +522,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { bool bit_value = p_pixels > 0; p_pixels = Math::abs(p_pixels); - Rect2i r = Rect2i(0, 0, width, height).clip(p_rect); + Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect); Ref<BitMap> copy; copy.instance(); @@ -677,9 +677,6 @@ void BitMap::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); } -BitMap::BitMap() { - width = 0; - height = 0; -} +BitMap::BitMap() {} ////////////////////////////////////// diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h index 59f3b4dc3c..68fd0b999a 100644 --- a/scene/resources/bit_map.h +++ b/scene/resources/bit_map.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,17 +31,17 @@ #ifndef BIT_MAP_H #define BIT_MAP_H -#include "core/image.h" +#include "core/io/image.h" +#include "core/io/resource.h" #include "core/io/resource_loader.h" -#include "core/resource.h" class BitMap : public Resource { GDCLASS(BitMap, Resource); OBJ_SAVE_TYPE(BitMap); Vector<uint8_t> bitmask; - int width; - int height; + int width = 0; + int height = 0; Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const; diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp index 69339faf76..6e7adc0bd7 100644 --- a/scene/resources/box_shape_3d.cpp +++ b/scene/resources/box_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,11 +31,11 @@ #include "box_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> BoxShape3D::get_debug_mesh_lines() { +Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const { Vector<Vector3> lines; AABB aabb; - aabb.position = -get_extents(); - aabb.size = aabb.position * -2; + aabb.position = -size / 2; + aabb.size = size; for (int i = 0; i < 12; i++) { Vector3 a, b; @@ -48,33 +48,32 @@ Vector<Vector3> BoxShape3D::get_debug_mesh_lines() { } real_t BoxShape3D::get_enclosing_radius() const { - return extents.length(); + return size.length() / 2; } void BoxShape3D::_update_shape() { - PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), extents); + PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), size / 2); Shape3D::_update_shape(); } -void BoxShape3D::set_extents(const Vector3 &p_extents) { - extents = p_extents; +void BoxShape3D::set_size(const Vector3 &p_size) { + size = p_size; _update_shape(); notify_change_to_owners(); - _change_notify("extents"); } -Vector3 BoxShape3D::get_extents() const { - return extents; +Vector3 BoxShape3D::get_size() const { + return size; } void BoxShape3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_extents", "extents"), &BoxShape3D::set_extents); - ClassDB::bind_method(D_METHOD("get_extents"), &BoxShape3D::get_extents); + ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxShape3D::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &BoxShape3D::get_size); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); } BoxShape3D::BoxShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_BOX)) { - set_extents(Vector3(1, 1, 1)); + set_size(Vector3(2, 2, 2)); } diff --git a/scene/resources/box_shape_3d.h b/scene/resources/box_shape_3d.h index e00b523815..fce05d61ed 100644 --- a/scene/resources/box_shape_3d.h +++ b/scene/resources/box_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,19 +35,19 @@ class BoxShape3D : public Shape3D { GDCLASS(BoxShape3D, Shape3D); - Vector3 extents; + Vector3 size; protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: - void set_extents(const Vector3 &p_extents); - Vector3 get_extents() const; + void set_size(const Vector3 &p_size); + Vector3 get_size() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override; BoxShape3D(); }; diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp new file mode 100644 index 0000000000..4038338e1e --- /dev/null +++ b/scene/resources/camera_effects.cpp @@ -0,0 +1,197 @@ +/*************************************************************************/ +/* camera_effects.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "camera_effects.h" + +#include "servers/rendering_server.h" + +RID CameraEffects::get_rid() const { + return camera_effects; +} + +// DOF blur + +void CameraEffects::set_dof_blur_far_enabled(bool p_enabled) { + dof_blur_far_enabled = p_enabled; + _update_dof_blur(); + notify_property_list_changed(); +} + +bool CameraEffects::is_dof_blur_far_enabled() const { + return dof_blur_far_enabled; +} + +void CameraEffects::set_dof_blur_far_distance(float p_distance) { + dof_blur_far_distance = p_distance; + _update_dof_blur(); +} + +float CameraEffects::get_dof_blur_far_distance() const { + return dof_blur_far_distance; +} + +void CameraEffects::set_dof_blur_far_transition(float p_distance) { + dof_blur_far_transition = p_distance; + _update_dof_blur(); +} + +float CameraEffects::get_dof_blur_far_transition() const { + return dof_blur_far_transition; +} + +void CameraEffects::set_dof_blur_near_enabled(bool p_enabled) { + dof_blur_near_enabled = p_enabled; + _update_dof_blur(); + notify_property_list_changed(); +} + +bool CameraEffects::is_dof_blur_near_enabled() const { + return dof_blur_near_enabled; +} + +void CameraEffects::set_dof_blur_near_distance(float p_distance) { + dof_blur_near_distance = p_distance; + _update_dof_blur(); +} + +float CameraEffects::get_dof_blur_near_distance() const { + return dof_blur_near_distance; +} + +void CameraEffects::set_dof_blur_near_transition(float p_distance) { + dof_blur_near_transition = p_distance; + _update_dof_blur(); +} + +float CameraEffects::get_dof_blur_near_transition() const { + return dof_blur_near_transition; +} + +void CameraEffects::set_dof_blur_amount(float p_amount) { + dof_blur_amount = p_amount; + _update_dof_blur(); +} + +float CameraEffects::get_dof_blur_amount() const { + return dof_blur_amount; +} + +void CameraEffects::_update_dof_blur() { + RS::get_singleton()->camera_effects_set_dof_blur( + camera_effects, + dof_blur_far_enabled, + dof_blur_far_distance, + dof_blur_far_transition, + dof_blur_near_enabled, + dof_blur_near_distance, + dof_blur_near_transition, + dof_blur_amount); +} + +// Custom exposure + +void CameraEffects::set_override_exposure_enabled(bool p_enabled) { + override_exposure_enabled = p_enabled; + _update_override_exposure(); +} + +bool CameraEffects::is_override_exposure_enabled() const { + return override_exposure_enabled; +} + +void CameraEffects::set_override_exposure(float p_exposure) { + override_exposure = p_exposure; + _update_override_exposure(); +} + +float CameraEffects::get_override_exposure() const { + return override_exposure; +} + +void CameraEffects::_update_override_exposure() { + RS::get_singleton()->camera_effects_set_custom_exposure( + camera_effects, + override_exposure_enabled, + override_exposure); +} + +// Private methods, constructor and destructor + +void CameraEffects::_bind_methods() { + // DOF blur + + ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraEffects::set_dof_blur_far_enabled); + ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraEffects::is_dof_blur_far_enabled); + ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraEffects::set_dof_blur_far_distance); + ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraEffects::get_dof_blur_far_distance); + ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraEffects::set_dof_blur_far_transition); + ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraEffects::get_dof_blur_far_transition); + + ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraEffects::set_dof_blur_near_enabled); + ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraEffects::is_dof_blur_near_enabled); + ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraEffects::set_dof_blur_near_distance); + ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraEffects::get_dof_blur_near_distance); + ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraEffects::set_dof_blur_near_transition); + ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraEffects::get_dof_blur_near_transition); + + ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraEffects::set_dof_blur_amount); + ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraEffects::get_dof_blur_amount); + + ADD_GROUP("DOF Blur", "dof_blur_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); + + // Override exposure + + ClassDB::bind_method(D_METHOD("set_override_exposure_enabled", "enabled"), &CameraEffects::set_override_exposure_enabled); + ClassDB::bind_method(D_METHOD("is_override_exposure_enabled"), &CameraEffects::is_override_exposure_enabled); + ClassDB::bind_method(D_METHOD("set_override_exposure", "exposure"), &CameraEffects::set_override_exposure); + ClassDB::bind_method(D_METHOD("get_override_exposure"), &CameraEffects::get_override_exposure); + + ADD_GROUP("Override Exposure", "override_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_exposure_enabled"), "set_override_exposure_enabled", "is_override_exposure_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "override_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_override_exposure", "get_override_exposure"); +} + +CameraEffects::CameraEffects() { + camera_effects = RS::get_singleton()->camera_effects_create(); + + _update_dof_blur(); + _update_override_exposure(); +} + +CameraEffects::~CameraEffects() { + RS::get_singleton()->free(camera_effects); +} diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h new file mode 100644 index 0000000000..28aa6b8660 --- /dev/null +++ b/scene/resources/camera_effects.h @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* camera_effects.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CAMERA_EFFECTS_H +#define CAMERA_EFFECTS_H + +#include "core/io/resource.h" +#include "core/templates/rid.h" + +class CameraEffects : public Resource { + GDCLASS(CameraEffects, Resource); + +private: + RID camera_effects; + + // DOF blur + bool dof_blur_far_enabled = false; + float dof_blur_far_distance = 10.0; + float dof_blur_far_transition = 5.0; + + bool dof_blur_near_enabled = false; + float dof_blur_near_distance = 2.0; + float dof_blur_near_transition = 1.0; + + float dof_blur_amount = 0.1; + void _update_dof_blur(); + + // Override exposure + bool override_exposure_enabled = false; + float override_exposure = 1.0; + void _update_override_exposure(); + +protected: + static void _bind_methods(); + +public: + virtual RID get_rid() const override; + + // DOF blur + void set_dof_blur_far_enabled(bool p_enabled); + bool is_dof_blur_far_enabled() const; + void set_dof_blur_far_distance(float p_distance); + float get_dof_blur_far_distance() const; + void set_dof_blur_far_transition(float p_distance); + float get_dof_blur_far_transition() const; + + void set_dof_blur_near_enabled(bool p_enabled); + bool is_dof_blur_near_enabled() const; + void set_dof_blur_near_distance(float p_distance); + float get_dof_blur_near_distance() const; + void set_dof_blur_near_transition(float p_distance); + float get_dof_blur_near_transition() const; + + void set_dof_blur_amount(float p_amount); + float get_dof_blur_amount() const; + + // Override exposure + void set_override_exposure_enabled(bool p_enabled); + bool is_override_exposure_enabled() const; + void set_override_exposure(float p_exposure); + float get_override_exposure() const; + + CameraEffects(); + ~CameraEffects(); +}; + +#endif // CAMERA_EFFECTS_H diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index 0e784e04ff..e5edba8a67 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,17 +30,19 @@ #include "capsule_shape_2d.h" +#include "core/math/geometry_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" Vector<Vector2> CapsuleShape2D::_get_points() const { Vector<Vector2> points; + const real_t turn_step = Math_TAU / 24.0; for (int i = 0; i < 24; i++) { Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5); - points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs); + points.push_back(Vector2(Math::sin(i * turn_step), Math::cos(i * turn_step)) * get_radius() + ofs); if (i == 6 || i == 18) { - points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs); + points.push_back(Vector2(Math::sin(i * turn_step), Math::cos(i * turn_step)) * get_radius() - ofs); } } @@ -48,7 +50,7 @@ Vector<Vector2> CapsuleShape2D::_get_points() const { } bool CapsuleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - return Geometry::is_point_in_polygon(p_point, _get_points()); + return Geometry2D::is_point_in_polygon(p_point, _get_points()); } void CapsuleShape2D::_update_shape() { @@ -83,6 +85,11 @@ void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector<Color> col; col.push_back(p_color); RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); + // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. + RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color); + } } Rect2 CapsuleShape2D::get_rect() const { @@ -110,7 +117,5 @@ void CapsuleShape2D::_bind_methods() { CapsuleShape2D::CapsuleShape2D() : Shape2D(PhysicsServer2D::get_singleton()->capsule_shape_create()) { - radius = 10; - height = 20; _update_shape(); } diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h index fe401a610c..439b67e8c3 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,8 +36,8 @@ class CapsuleShape2D : public Shape2D { GDCLASS(CapsuleShape2D, Shape2D); - real_t height; - real_t radius; + real_t height = 20.0; + real_t radius = 10.0; void _update_shape(); Vector<Vector2> _get_points() const; @@ -46,7 +46,7 @@ protected: static void _bind_methods(); public: - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override; void set_height(real_t p_height); real_t get_height() const; @@ -54,9 +54,9 @@ public: void set_radius(real_t p_radius); real_t get_radius() const; - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - virtual real_t get_enclosing_radius() const; + virtual void draw(const RID &p_to_rid, const Color &p_color) override; + virtual Rect2 get_rect() const override; + virtual real_t get_enclosing_radius() const override; CapsuleShape2D(); }; diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp index 28fc0d470c..226fe1ecd2 100644 --- a/scene/resources/capsule_shape_3d.cpp +++ b/scene/resources/capsule_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #include "capsule_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() { +Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const { float radius = get_radius(); float height = get_height(); @@ -82,7 +82,6 @@ void CapsuleShape3D::set_radius(float p_radius) { radius = p_radius; _update_shape(); notify_change_to_owners(); - _change_notify("radius"); } float CapsuleShape3D::get_radius() const { @@ -93,7 +92,6 @@ void CapsuleShape3D::set_height(float p_height) { height = p_height; _update_shape(); notify_change_to_owners(); - _change_notify("height"); } float CapsuleShape3D::get_height() const { @@ -106,13 +104,11 @@ void CapsuleShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape3D::set_height); ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape3D::get_height); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,4096,0.001"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,4096,0.001"), "set_height", "get_height"); } CapsuleShape3D::CapsuleShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CAPSULE)) { - radius = 1.0; - height = 1.0; _update_shape(); } diff --git a/scene/resources/capsule_shape_3d.h b/scene/resources/capsule_shape_3d.h index 5892f97709..25645ecf9d 100644 --- a/scene/resources/capsule_shape_3d.h +++ b/scene/resources/capsule_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,13 +35,13 @@ class CapsuleShape3D : public Shape3D { GDCLASS(CapsuleShape3D, Shape3D); - float radius; - float height; + float radius = 1.0; + float height = 1.0; protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: void set_radius(float p_radius); @@ -49,8 +49,8 @@ public: void set_height(float p_height); float get_height() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override; CapsuleShape3D(); }; diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index dc1bf3b185..f06bc4248d 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -71,17 +71,22 @@ real_t CircleShape2D::get_enclosing_radius() const { void CircleShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector<Vector2> points; + const real_t turn_step = Math_TAU / 24.0; for (int i = 0; i < 24; i++) { - points.push_back(Vector2(Math::cos(i * Math_PI * 2 / 24.0), Math::sin(i * Math_PI * 2 / 24.0)) * get_radius()); + points.push_back(Vector2(Math::cos(i * turn_step), Math::sin(i * turn_step)) * get_radius()); } Vector<Color> col; col.push_back(p_color); RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); + // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. + RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color); + } } CircleShape2D::CircleShape2D() : Shape2D(PhysicsServer2D::get_singleton()->circle_shape_create()) { - radius = 10; _update_shape(); } diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h index 8b064f4d9f..333f299236 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,21 +36,21 @@ class CircleShape2D : public Shape2D { GDCLASS(CircleShape2D, Shape2D); - real_t radius; + real_t radius = 10.0; void _update_shape(); protected: static void _bind_methods(); public: - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override; void set_radius(real_t p_radius); real_t get_radius() const; - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - virtual real_t get_enclosing_radius() const; + virtual void draw(const RID &p_to_rid, const Color &p_color) override; + virtual Rect2 get_rect() const override; + virtual real_t get_enclosing_radius() const override; CircleShape2D(); }; diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp index 2154633111..0c767c8a52 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "concave_polygon_shape_2d.h" +#include "core/math/geometry_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" @@ -42,7 +43,7 @@ bool ConcavePolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, do const Vector2 *r = s.ptr(); for (int i = 0; i < len; i += 2) { - Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, &r[i]); + Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, &r[i]); if (p_point.distance_to(closest) < p_tolerance) { return true; } @@ -97,7 +98,7 @@ Rect2 ConcavePolygonShape2D::get_rect() const { real_t ConcavePolygonShape2D::get_enclosing_radius() const { Vector<Vector2> data = get_segments(); const Vector2 *read = data.ptr(); - real_t r = 0; + real_t r = 0.0; for (int i(0); i < data.size(); i++) { r = MAX(read[i].length_squared(), r); } diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h index f89995567e..98ae341e97 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 +40,14 @@ protected: static void _bind_methods(); public: - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override; void set_segments(const Vector<Vector2> &p_segments); Vector<Vector2> get_segments() const; - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - virtual real_t get_enclosing_radius() const; + virtual void draw(const RID &p_to_rid, const Color &p_color) override; + virtual Rect2 get_rect() const override; + virtual real_t get_enclosing_radius() const override; ConcavePolygonShape2D(); }; diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp index 7315945c03..f067695d7d 100644 --- a/scene/resources/concave_polygon_shape_3d.cpp +++ b/scene/resources/concave_polygon_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "servers/physics_server_3d.h" -Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() { +Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const { Set<DrawEdge> edges; Vector<Vector3> data = get_faces(); @@ -63,7 +63,7 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() { real_t ConcavePolygonShape3D::get_enclosing_radius() const { Vector<Vector3> data = get_faces(); const Vector3 *read = data.ptr(); - real_t r = 0; + real_t r = 0.0; for (int i(0); i < data.size(); i++) { r = MAX(read[i].length_squared(), r); } diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h index c268ed9f37..391459a3d7 100644 --- a/scene/resources/concave_polygon_shape_3d.h +++ b/scene/resources/concave_polygon_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 +59,14 @@ class ConcavePolygonShape3D : public Shape3D { protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: void set_faces(const Vector<Vector3> &p_faces); Vector<Vector3> get_faces() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override; ConcavePolygonShape3D(); }; diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp index 7df7c3ac72..d331f83daf 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,17 +30,17 @@ #include "convex_polygon_shape_2d.h" -#include "core/math/geometry.h" +#include "core/math/geometry_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - return Geometry::is_point_in_polygon(p_point, points); + return Geometry2D::is_point_in_polygon(p_point, points); } void ConvexPolygonShape2D::_update_shape() { Vector<Vector2> final_points = points; - if (Geometry::is_polygon_clockwise(final_points)) { //needs to be counter clockwise + if (Geometry2D::is_polygon_clockwise(final_points)) { //needs to be counter clockwise final_points.invert(); } PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), final_points); @@ -48,7 +48,7 @@ void ConvexPolygonShape2D::_update_shape() { } void ConvexPolygonShape2D::set_point_cloud(const Vector<Vector2> &p_points) { - Vector<Point2> hull = Geometry::convex_hull_2d(p_points); + Vector<Point2> hull = Geometry2D::convex_hull(p_points); ERR_FAIL_COND(hull.size() < 3); set_points(hull); } @@ -75,6 +75,11 @@ void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector<Color> col; col.push_back(p_color); RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); + // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. + RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color); + } } Rect2 ConvexPolygonShape2D::get_rect() const { @@ -91,7 +96,7 @@ Rect2 ConvexPolygonShape2D::get_rect() const { } real_t ConvexPolygonShape2D::get_enclosing_radius() const { - real_t r = 0; + real_t r = 0.0; for (int i(0); i < get_points().size(); i++) { r = MAX(get_points()[i].length_squared(), r); } diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h index 83c250c0ce..1813b608bd 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,15 +43,15 @@ protected: static void _bind_methods(); public: - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override; void set_point_cloud(const Vector<Vector2> &p_points); void set_points(const Vector<Vector2> &p_points); Vector<Vector2> get_points() const; - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - virtual real_t get_enclosing_radius() const; + virtual void draw(const RID &p_to_rid, const Color &p_color) override; + virtual Rect2 get_rect() const override; + virtual real_t get_enclosing_radius() const override; ConvexPolygonShape2D(); }; diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp index e52df73663..9e030bc077 100644 --- a/scene/resources/convex_polygon_shape_3d.cpp +++ b/scene/resources/convex_polygon_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,12 +32,12 @@ #include "core/math/quick_hull.h" #include "servers/physics_server_3d.h" -Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() { +Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const { Vector<Vector3> points = get_points(); if (points.size() > 3) { Vector<Vector3> varr = Variant(points); - Geometry::MeshData md; + Geometry3D::MeshData md; Error err = QuickHull::build(varr, md); if (err == OK) { Vector<Vector3> lines; @@ -56,7 +56,7 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() { real_t ConvexPolygonShape3D::get_enclosing_radius() const { Vector<Vector3> data = get_points(); const Vector3 *read = data.ptr(); - real_t r = 0; + real_t r = 0.0; for (int i(0); i < data.size(); i++) { r = MAX(read[i].length_squared(), r); } diff --git a/scene/resources/convex_polygon_shape_3d.h b/scene/resources/convex_polygon_shape_3d.h index 0e3dde47a5..edd127c8f4 100644 --- a/scene/resources/convex_polygon_shape_3d.h +++ b/scene/resources/convex_polygon_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 +40,14 @@ class ConvexPolygonShape3D : public Shape3D { protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: void set_points(const Vector<Vector3> &p_points); Vector<Vector3> get_points() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override; ConvexPolygonShape3D(); }; diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index de076670cf..bc479e557a 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,11 +47,6 @@ static _FORCE_INLINE_ T _bezier_interp(real_t t, T start, T control_1, T control const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed"; Curve::Curve() { - _bake_resolution = 100; - _baked_cache_dirty = false; - _min_value = 0; - _max_value = 1; - _minmax_set_once = 0b00; } int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent, TangentMode left_mode, TangentMode right_mode) { @@ -602,7 +597,7 @@ void Curve2D::remove_point(int p_index) { } void Curve2D::clear_points() { - if (!points.empty()) { + if (!points.is_empty()) { points.clear(); baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); @@ -683,7 +678,7 @@ void Curve2D::_bake() const { for (int i = 0; i < points.size() - 1; i++) { float step = 0.1; // at least 10 substeps ought to be enough? - float p = 0; + float p = 0.0; while (p < 1.0) { float np = p + step; @@ -993,12 +988,9 @@ void Curve2D::_bind_methods() { } Curve2D::Curve2D() { - baked_cache_dirty = false; - baked_max_ofs = 0; /* add_point(Vector2(-1,0,0)); add_point(Vector2(0,2,0)); add_point(Vector2(0,3,5));*/ - bake_interval = 5; } /***********************************************************************************/ @@ -1087,7 +1079,7 @@ void Curve3D::remove_point(int p_index) { } void Curve3D::clear_points() { - if (!points.empty()) { + if (!points.is_empty()) { points.clear(); baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); @@ -1178,7 +1170,7 @@ void Curve3D::_bake() const { for (int i = 0; i < points.size() - 1; i++) { float step = 0.1; // at least 10 substeps ought to be enough? - float p = 0; + float p = 0.0; while (p < 1.0) { float np = p + step; @@ -1669,11 +1661,7 @@ void Curve3D::_bind_methods() { } Curve3D::Curve3D() { - baked_cache_dirty = false; - baked_max_ofs = 0; /* add_point(Vector3(-1,0,0)); add_point(Vector3(0,2,0)); add_point(Vector3(0,3,5));*/ - bake_interval = 0.2; - up_vector_enabled = true; } diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 57ddaf897d..402c893cd8 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef CURVE_H #define CURVE_H -#include "core/resource.h" +#include "core/io/resource.h" // y(x) curve class Curve : public Resource { @@ -51,21 +51,17 @@ public: struct Point { Vector2 pos; - real_t left_tangent; - real_t right_tangent; - TangentMode left_mode; - TangentMode right_mode; + real_t left_tangent = 0.0; + real_t right_tangent = 0.0; + TangentMode left_mode = TANGENT_FREE; + TangentMode right_mode = TANGENT_FREE; Point() { - left_tangent = 0; - right_tangent = 0; - left_mode = TANGENT_FREE; - right_mode = TANGENT_FREE; } Point(Vector2 p_pos, - real_t p_left = 0, - real_t p_right = 0, + real_t p_left = 0.0, + real_t p_right = 0.0, TangentMode p_left_mode = TANGENT_FREE, TangentMode p_right_mode = TANGENT_FREE) { pos = p_pos; @@ -137,12 +133,12 @@ private: void mark_dirty(); Vector<Point> _points; - bool _baked_cache_dirty; + bool _baked_cache_dirty = false; Vector<real_t> _baked_cache; - int _bake_resolution; - float _min_value; - float _max_value; - int _minmax_set_once; // Encodes whether min and max have been set a first time, first bit for min and second for max. + int _bake_resolution = 100; + float _min_value = 0.0; + float _max_value = 1.0; + int _minmax_set_once = 0b00; // Encodes whether min and max have been set a first time, first bit for min and second for max. }; VARIANT_ENUM_CAST(Curve::TangentMode) @@ -159,17 +155,17 @@ class Curve2D : public Resource { Vector<Point> points; struct BakedPoint { - float ofs; + float ofs = 0.0; Vector2 point; }; - mutable bool baked_cache_dirty; + mutable bool baked_cache_dirty = false; mutable PackedVector2Array baked_point_cache; - mutable float baked_max_ofs; + mutable float baked_max_ofs = 0.0; void _bake() const; - float bake_interval; + float bake_interval = 5.0; void _bake_segment2d(Map<float, Vector2> &r_bake, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, float p_tol) const; Dictionary _get_data() const; @@ -214,28 +210,26 @@ class Curve3D : public Resource { Vector3 in; Vector3 out; Vector3 pos; - float tilt; - - Point() { tilt = 0; } + float tilt = 0.0; }; Vector<Point> points; struct BakedPoint { - float ofs; + float ofs = 0.0; Vector3 point; }; - mutable bool baked_cache_dirty; + mutable bool baked_cache_dirty = false; mutable PackedVector3Array baked_point_cache; mutable PackedFloat32Array baked_tilt_cache; mutable PackedVector3Array baked_up_vector_cache; - mutable float baked_max_ofs; + mutable float baked_max_ofs = 0.0; void _bake() const; - float bake_interval; - bool up_vector_enabled; + float bake_interval = 0.2; + bool up_vector_enabled = true; void _bake_segment3d(Map<float, Vector3> &r_bake, float p_begin, float p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, float p_tol) const; Dictionary _get_data() const; diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp index 44786d6025..63bdc8d26d 100644 --- a/scene/resources/cylinder_shape_3d.cpp +++ b/scene/resources/cylinder_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #include "cylinder_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() { +Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const { float radius = get_radius(); float height = get_height(); @@ -75,7 +75,6 @@ void CylinderShape3D::set_radius(float p_radius) { radius = p_radius; _update_shape(); notify_change_to_owners(); - _change_notify("radius"); } float CylinderShape3D::get_radius() const { @@ -86,7 +85,6 @@ void CylinderShape3D::set_height(float p_height) { height = p_height; _update_shape(); notify_change_to_owners(); - _change_notify("height"); } float CylinderShape3D::get_height() const { @@ -99,13 +97,11 @@ void CylinderShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape3D::set_height); ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape3D::get_height); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,4096,0.001"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,4096,0.001"), "set_height", "get_height"); } CylinderShape3D::CylinderShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CYLINDER)) { - radius = 1.0; - height = 2.0; _update_shape(); } diff --git a/scene/resources/cylinder_shape_3d.h b/scene/resources/cylinder_shape_3d.h index 23d206cbab..d1b8364672 100644 --- a/scene/resources/cylinder_shape_3d.h +++ b/scene/resources/cylinder_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,12 +35,12 @@ class CylinderShape3D : public Shape3D { GDCLASS(CylinderShape3D, Shape3D); - float radius; - float height; + float radius = 1.0; + float height = 2.0; protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: void set_radius(float p_radius); @@ -48,8 +48,8 @@ public: void set_height(float p_height); float get_height() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override; CylinderShape3D(); }; diff --git a/scene/resources/default_theme/arrow_left.png b/scene/resources/default_theme/arrow_left.png Binary files differnew file mode 100644 index 0000000000..4163059dd3 --- /dev/null +++ b/scene/resources/default_theme/arrow_left.png diff --git a/scene/resources/default_theme/bookmark.png b/scene/resources/default_theme/bookmark.png Binary files differnew file mode 100644 index 0000000000..9718cf53b6 --- /dev/null +++ b/scene/resources/default_theme/bookmark.png diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index f5b987e8df..a94209c75f 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,13 +38,15 @@ #include "font_hidpi.inc" #include "font_lodpi.inc" +#include "servers/text_server.h" + typedef Map<const void *, Ref<ImageTexture>> TexCacheMap; static TexCacheMap *tex_cache; -static float scale = 1; +static float scale = 1.0; template <class T> -static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, float p_right, float p_botton, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_botton = -1, bool p_draw_center = true) { +static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) { Ref<ImageTexture> texture; if (tex_cache->has(p_src)) { @@ -62,24 +64,35 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, fl Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); style->set_texture(texture); - style->set_margin_size(MARGIN_LEFT, p_left * scale); - style->set_margin_size(MARGIN_RIGHT, p_right * scale); - style->set_margin_size(MARGIN_BOTTOM, p_botton * scale); - style->set_margin_size(MARGIN_TOP, p_top * scale); - style->set_default_margin(MARGIN_LEFT, p_margin_left * scale); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * scale); - style->set_default_margin(MARGIN_BOTTOM, p_margin_botton * scale); - style->set_default_margin(MARGIN_TOP, p_margin_top * scale); + style->set_margin_size(SIDE_LEFT, p_left * scale); + style->set_margin_size(SIDE_RIGHT, p_right * scale); + style->set_margin_size(SIDE_BOTTOM, p_bottom * scale); + style->set_margin_size(SIDE_TOP, p_top * scale); + style->set_default_margin(SIDE_LEFT, p_margin_left * scale); + style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); + style->set_default_margin(SIDE_TOP, p_margin_top * scale); style->set_draw_center(p_draw_center); return style; } -static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox, float p_left, float p_top, float p_right, float p_botton) { - p_sbox->set_expand_margin_size(MARGIN_LEFT, p_left * scale); - p_sbox->set_expand_margin_size(MARGIN_TOP, p_top * scale); - p_sbox->set_expand_margin_size(MARGIN_RIGHT, p_right * scale); - p_sbox->set_expand_margin_size(MARGIN_BOTTOM, p_botton * scale); +static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { + Ref<StyleBoxFlat> style(memnew(StyleBoxFlat)); + style->set_bg_color(p_color); + style->set_default_margin(SIDE_LEFT, p_margin_left * scale); + style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); + style->set_default_margin(SIDE_TOP, p_margin_top * scale); + + return style; +} + +static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox, float p_left, float p_top, float p_right, float p_bottom) { + p_sbox->set_expand_margin_size(SIDE_LEFT, p_left * scale); + p_sbox->set_expand_margin_size(SIDE_TOP, p_top * scale); + p_sbox->set_expand_margin_size(SIDE_RIGHT, p_right * scale); + p_sbox->set_expand_margin_size(SIDE_BOTTOM, p_bottom * scale); return p_sbox; } @@ -95,14 +108,35 @@ static Ref<Texture2D> make_icon(T p_src) { return texture; } -static Ref<BitmapFont> make_font(int p_height, int p_ascent, int p_charcount, const int *p_char_rects, int p_kerning_count, const int *p_kernings, int p_w, int p_h, const unsigned char *p_img) { - Ref<BitmapFont> font(memnew(BitmapFont)); +static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, bool p_flip_x = false) { + if (!p_flip_y && !p_flip_x) { + return p_texture; + } + + Ref<ImageTexture> texture(memnew(ImageTexture)); + Ref<Image> img = p_texture->get_data(); + img = img->duplicate(); + + if (p_flip_y) { + img->flip_y(); + } + if (p_flip_x) { + img->flip_x(); + } + + texture->create_from_image(img); + return texture; +} + +static Ref<FontData> make_font(int p_height, int p_ascent, int p_charcount, const int *p_char_rects, int p_kerning_count, const int *p_kernings, int p_w, int p_h, const unsigned char *p_img) { + Ref<FontData> font(memnew(FontData)); + font->new_bitmap(p_height, p_ascent, p_height); Ref<Image> image = memnew(Image(p_img)); Ref<ImageTexture> tex = memnew(ImageTexture); tex->create_from_image(image); - font->add_texture(tex); + font->bitmap_add_texture(tex); for (int i = 0; i < p_charcount; i++) { const int *c = &p_char_rects[i * 8]; @@ -116,26 +150,23 @@ static Ref<BitmapFont> make_font(int p_height, int p_ascent, int p_charcount, co Point2 align(c[6], c[5]); int advance = c[7]; - font->add_char(chr, 0, frect, align, advance); + font->bitmap_add_char(chr, 0, frect, align, advance); } for (int i = 0; i < p_kerning_count; i++) { - font->add_kerning_pair(p_kernings[i * 3 + 0], p_kernings[i * 3 + 1], p_kernings[i * 3 + 2]); + font->bitmap_add_kerning_pair(p_kernings[i * 3 + 0], p_kernings[i * 3 + 1], p_kernings[i * 3 + 2]); } - font->set_height(p_height); - font->set_ascent(p_ascent); - return font; } -static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_botton = -1) { +static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBox> style(memnew(StyleBoxEmpty)); - style->set_default_margin(MARGIN_LEFT, p_margin_left * scale); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * scale); - style->set_default_margin(MARGIN_BOTTOM, p_margin_botton * scale); - style->set_default_margin(MARGIN_TOP, p_margin_top * scale); + style->set_default_margin(SIDE_LEFT, p_margin_left * scale); + style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); + style->set_default_margin(SIDE_TOP, p_margin_top * scale); return style; } @@ -148,12 +179,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Font Colors Color control_font_color = Color(0.88, 0.88, 0.88); - Color control_font_color_lower = Color(0.63, 0.63, 0.63); - Color control_font_color_low = Color(0.69, 0.69, 0.69); - Color control_font_color_hover = Color(0.94, 0.94, 0.94); - Color control_font_color_disabled = Color(0.9, 0.9, 0.9, 0.2); - Color control_font_color_pressed = Color(1, 1, 1); - Color font_color_selection = Color(0.49, 0.49, 0.49); + Color control_font_lower_color = Color(0.63, 0.63, 0.63); + Color control_font_low_color = Color(0.69, 0.69, 0.69); + Color control_font_hover_color = Color(0.94, 0.94, 0.94); + Color control_font_disabled_color = Color(0.9, 0.9, 0.9, 0.2); + Color control_font_pressed_color = Color(1, 1, 1); + + Color control_selection_color = Color(0.49, 0.49, 0.49); // Panel @@ -164,7 +196,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxTexture> focus = make_stylebox(focus_png, 5, 5, 5, 5); for (int i = 0; i < 4; i++) { - focus->set_expand_margin_size(Margin(i), 1 * scale); + focus->set_expand_margin_size(Side(i), 1 * scale); } // Button @@ -181,12 +213,22 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("disabled", "Button", sb_button_disabled); theme->set_stylebox("focus", "Button", sb_button_focus); - theme->set_font("font", "Button", default_font); + theme->set_font("font", "Button", Ref<Font>()); + theme->set_font_size("font_size", "Button", -1); + theme->set_constant("outline_size", "Button", 0 * scale); theme->set_color("font_color", "Button", control_font_color); - theme->set_color("font_color_pressed", "Button", control_font_color_pressed); - theme->set_color("font_color_hover", "Button", control_font_color_hover); - theme->set_color("font_color_disabled", "Button", control_font_color_disabled); + theme->set_color("font_pressed_color", "Button", control_font_pressed_color); + theme->set_color("font_hover_color", "Button", control_font_hover_color); + theme->set_color("font_hover_pressed_color", "Button", control_font_pressed_color); + theme->set_color("font_disabled_color", "Button", control_font_disabled_color); + theme->set_color("font_outline_color", "Button", Color(1, 1, 1)); + + theme->set_color("icon_normal_color", "Button", Color(1, 1, 1, 1)); + theme->set_color("icon_pressed_color", "Button", Color(1, 1, 1, 1)); + theme->set_color("icon_hover_color", "Button", Color(1, 1, 1, 1)); + theme->set_color("icon_hover_pressed_color", "Button", Color(1, 1, 1, 1)); + theme->set_color("icon_disabled_color", "Button", Color(1, 1, 1, 1)); theme->set_constant("hseparation", "Button", 2 * scale); @@ -194,12 +236,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("focus", "LinkButton", focus); - theme->set_font("font", "LinkButton", default_font); + theme->set_font("font", "LinkButton", Ref<Font>()); + theme->set_font_size("font_size", "LinkButton", -1); theme->set_color("font_color", "LinkButton", control_font_color); - theme->set_color("font_color_pressed", "LinkButton", control_font_color_pressed); - theme->set_color("font_color_hover", "LinkButton", control_font_color_hover); + theme->set_color("font_pressed_color", "LinkButton", control_font_pressed_color); + theme->set_color("font_hover_color", "LinkButton", control_font_hover_color); + theme->set_color("font_outline_color", "LinkButton", Color(1, 1, 1)); + theme->set_constant("outline_size", "LinkButton", 0); theme->set_constant("underline_spacing", "LinkButton", 2 * scale); // ColorPickerButton @@ -210,56 +255,57 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("disabled", "ColorPickerButton", sb_button_disabled); theme->set_stylebox("focus", "ColorPickerButton", sb_button_focus); - theme->set_font("font", "ColorPickerButton", default_font); + theme->set_font("font", "ColorPickerButton", Ref<Font>()); + theme->set_font_size("font_size", "ColorPickerButton", -1); theme->set_color("font_color", "ColorPickerButton", Color(1, 1, 1, 1)); - theme->set_color("font_color_pressed", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1)); - theme->set_color("font_color_hover", "ColorPickerButton", Color(1, 1, 1, 1)); - theme->set_color("font_color_disabled", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3)); + theme->set_color("font_pressed_color", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1)); + theme->set_color("font_hover_color", "ColorPickerButton", Color(1, 1, 1, 1)); + theme->set_color("font_disabled_color", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3)); + theme->set_color("font_outline_color", "ColorPickerButton", Color(1, 1, 1)); theme->set_constant("hseparation", "ColorPickerButton", 2 * scale); - - // ToolButton - - theme->set_stylebox("normal", "ToolButton", make_empty_stylebox(6, 4, 6, 4)); - theme->set_stylebox("pressed", "ToolButton", make_stylebox(button_pressed_png, 4, 4, 4, 4, 6, 4, 6, 4)); - theme->set_stylebox("hover", "ToolButton", make_stylebox(button_normal_png, 4, 4, 4, 4, 6, 4, 6, 4)); - theme->set_stylebox("disabled", "ToolButton", make_empty_stylebox(6, 4, 6, 4)); - theme->set_stylebox("focus", "ToolButton", focus); - theme->set_font("font", "ToolButton", default_font); - - theme->set_color("font_color", "ToolButton", control_font_color); - theme->set_color("font_color_pressed", "ToolButton", control_font_color_pressed); - theme->set_color("font_color_hover", "ToolButton", control_font_color_hover); - theme->set_color("font_color_disabled", "ToolButton", Color(0.9, 0.95, 1, 0.3)); - - theme->set_constant("hseparation", "ToolButton", 3); + theme->set_constant("outline_size", "ColorPickerButton", 0); // OptionButton + Ref<StyleBox> sb_optbutton_focus = sb_expand(make_stylebox(button_focus_png, 4, 4, 4, 4, 6, 2, 6, 2), 2, 2, 2, 2); + theme->set_stylebox("focus", "OptionButton", sb_optbutton_focus); + Ref<StyleBox> sb_optbutton_normal = sb_expand(make_stylebox(option_button_normal_png, 4, 4, 21, 4, 6, 3, 9, 3), 2, 2, 2, 2); Ref<StyleBox> sb_optbutton_pressed = sb_expand(make_stylebox(option_button_pressed_png, 4, 4, 21, 4, 6, 3, 9, 3), 2, 2, 2, 2); Ref<StyleBox> sb_optbutton_hover = sb_expand(make_stylebox(option_button_hover_png, 4, 4, 21, 4, 6, 2, 9, 2), 2, 2, 2, 2); Ref<StyleBox> sb_optbutton_disabled = sb_expand(make_stylebox(option_button_disabled_png, 4, 4, 21, 4, 6, 2, 9, 2), 2, 2, 2, 2); - Ref<StyleBox> sb_optbutton_focus = sb_expand(make_stylebox(button_focus_png, 4, 4, 4, 4, 6, 2, 6, 2), 2, 2, 2, 2); theme->set_stylebox("normal", "OptionButton", sb_optbutton_normal); theme->set_stylebox("pressed", "OptionButton", sb_optbutton_pressed); theme->set_stylebox("hover", "OptionButton", sb_optbutton_hover); theme->set_stylebox("disabled", "OptionButton", sb_optbutton_disabled); - theme->set_stylebox("focus", "OptionButton", sb_optbutton_focus); + + Ref<StyleBox> sb_optbutton_normal_mirrored = sb_expand(make_stylebox(option_button_normal_mirrored_png, 21, 4, 4, 4, 9, 3, 6, 3), 2, 2, 2, 2); + Ref<StyleBox> sb_optbutton_pressed_mirrored = sb_expand(make_stylebox(option_button_pressed_mirrored_png, 21, 4, 4, 4, 9, 3, 6, 3), 2, 2, 2, 2); + Ref<StyleBox> sb_optbutton_hover_mirrored = sb_expand(make_stylebox(option_button_hover_mirrored_png, 21, 4, 4, 4, 9, 2, 6, 2), 2, 2, 2, 2); + Ref<StyleBox> sb_optbutton_disabled_mirrored = sb_expand(make_stylebox(option_button_disabled_mirrored_png, 21, 4, 4, 4, 9, 2, 6, 2), 2, 2, 2, 2); + + theme->set_stylebox("normal_mirrored", "OptionButton", sb_optbutton_normal_mirrored); + theme->set_stylebox("pressed_mirrored", "OptionButton", sb_optbutton_pressed_mirrored); + theme->set_stylebox("hover_mirrored", "OptionButton", sb_optbutton_hover_mirrored); + theme->set_stylebox("disabled_mirrored", "OptionButton", sb_optbutton_disabled_mirrored); theme->set_icon("arrow", "OptionButton", make_icon(option_arrow_png)); - theme->set_font("font", "OptionButton", default_font); + theme->set_font("font", "OptionButton", Ref<Font>()); + theme->set_font_size("font_size", "OptionButton", -1); theme->set_color("font_color", "OptionButton", control_font_color); - theme->set_color("font_color_pressed", "OptionButton", control_font_color_pressed); - theme->set_color("font_color_hover", "OptionButton", control_font_color_hover); - theme->set_color("font_color_disabled", "OptionButton", control_font_color_disabled); + theme->set_color("font_pressed_color", "OptionButton", control_font_pressed_color); + theme->set_color("font_hover_color", "OptionButton", control_font_hover_color); + theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color); + theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1)); theme->set_constant("hseparation", "OptionButton", 2 * scale); theme->set_constant("arrow_margin", "OptionButton", 2 * scale); + theme->set_constant("outline_size", "OptionButton", 0); // MenuButton @@ -269,27 +315,30 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("disabled", "MenuButton", sb_button_disabled); theme->set_stylebox("focus", "MenuButton", sb_button_focus); - theme->set_font("font", "MenuButton", default_font); + theme->set_font("font", "MenuButton", Ref<Font>()); + theme->set_font_size("font_size", "MenuButton", -1); theme->set_color("font_color", "MenuButton", control_font_color); - theme->set_color("font_color_pressed", "MenuButton", control_font_color_pressed); - theme->set_color("font_color_hover", "MenuButton", control_font_color_hover); - theme->set_color("font_color_disabled", "MenuButton", Color(1, 1, 1, 0.3)); + theme->set_color("font_pressed_color", "MenuButton", control_font_pressed_color); + theme->set_color("font_hover_color", "MenuButton", control_font_hover_color); + theme->set_color("font_disabled_color", "MenuButton", Color(1, 1, 1, 0.3)); + theme->set_color("font_outline_color", "MenuButton", Color(1, 1, 1)); theme->set_constant("hseparation", "MenuButton", 3 * scale); + theme->set_constant("outline_size", "MenuButton", 0); // CheckBox Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty); - cbx_empty->set_default_margin(MARGIN_LEFT, 4 * scale); - cbx_empty->set_default_margin(MARGIN_RIGHT, 4 * scale); - cbx_empty->set_default_margin(MARGIN_TOP, 4 * scale); - cbx_empty->set_default_margin(MARGIN_BOTTOM, 4 * scale); + cbx_empty->set_default_margin(SIDE_LEFT, 4 * scale); + cbx_empty->set_default_margin(SIDE_RIGHT, 4 * scale); + cbx_empty->set_default_margin(SIDE_TOP, 4 * scale); + cbx_empty->set_default_margin(SIDE_BOTTOM, 4 * scale); Ref<StyleBox> cbx_focus = focus; - cbx_focus->set_default_margin(MARGIN_LEFT, 4 * scale); - cbx_focus->set_default_margin(MARGIN_RIGHT, 4 * scale); - cbx_focus->set_default_margin(MARGIN_TOP, 4 * scale); - cbx_focus->set_default_margin(MARGIN_BOTTOM, 4 * scale); + cbx_focus->set_default_margin(SIDE_LEFT, 4 * scale); + cbx_focus->set_default_margin(SIDE_RIGHT, 4 * scale); + cbx_focus->set_default_margin(SIDE_TOP, 4 * scale); + cbx_focus->set_default_margin(SIDE_BOTTOM, 4 * scale); theme->set_stylebox("normal", "CheckBox", cbx_empty); theme->set_stylebox("pressed", "CheckBox", cbx_empty); @@ -303,24 +352,27 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png)); theme->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png)); - theme->set_font("font", "CheckBox", default_font); + theme->set_font("font", "CheckBox", Ref<Font>()); + theme->set_font_size("font_size", "CheckBox", -1); theme->set_color("font_color", "CheckBox", control_font_color); - theme->set_color("font_color_pressed", "CheckBox", control_font_color_pressed); - theme->set_color("font_color_hover", "CheckBox", control_font_color_hover); - theme->set_color("font_color_hover_pressed", "CheckBox", control_font_color_pressed); - theme->set_color("font_color_disabled", "CheckBox", control_font_color_disabled); + theme->set_color("font_pressed_color", "CheckBox", control_font_pressed_color); + theme->set_color("font_hover_color", "CheckBox", control_font_hover_color); + theme->set_color("font_hover_pressed_color", "CheckBox", control_font_pressed_color); + theme->set_color("font_disabled_color", "CheckBox", control_font_disabled_color); + theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1)); theme->set_constant("hseparation", "CheckBox", 4 * scale); theme->set_constant("check_vadjust", "CheckBox", 0 * scale); + theme->set_constant("outline_size", "CheckBox", 0); // CheckButton Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty); - cb_empty->set_default_margin(MARGIN_LEFT, 6 * scale); - cb_empty->set_default_margin(MARGIN_RIGHT, 6 * scale); - cb_empty->set_default_margin(MARGIN_TOP, 4 * scale); - cb_empty->set_default_margin(MARGIN_BOTTOM, 4 * scale); + cb_empty->set_default_margin(SIDE_LEFT, 6 * scale); + cb_empty->set_default_margin(SIDE_RIGHT, 6 * scale); + cb_empty->set_default_margin(SIDE_TOP, 4 * scale); + cb_empty->set_default_margin(SIDE_BOTTOM, 4 * scale); theme->set_stylebox("normal", "CheckButton", cb_empty); theme->set_stylebox("pressed", "CheckButton", cb_empty); @@ -334,29 +386,39 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const 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); + theme->set_icon("on_mirrored", "CheckButton", make_icon(toggle_on_mirrored_png)); + theme->set_icon("on_disabled_mirrored", "CheckButton", make_icon(toggle_on_disabled_mirrored_png)); + theme->set_icon("off_mirrored", "CheckButton", make_icon(toggle_off_mirrored_png)); + theme->set_icon("off_disabled_mirrored", "CheckButton", make_icon(toggle_off_disabled_mirrored_png)); + + theme->set_font("font", "CheckButton", Ref<Font>()); + theme->set_font_size("font_size", "CheckButton", -1); theme->set_color("font_color", "CheckButton", control_font_color); - theme->set_color("font_color_pressed", "CheckButton", control_font_color_pressed); - theme->set_color("font_color_hover", "CheckButton", control_font_color_hover); - theme->set_color("font_color_hover_pressed", "CheckButton", control_font_color_pressed); - theme->set_color("font_color_disabled", "CheckButton", control_font_color_disabled); + theme->set_color("font_pressed_color", "CheckButton", control_font_pressed_color); + theme->set_color("font_hover_color", "CheckButton", control_font_hover_color); + theme->set_color("font_hover_pressed_color", "CheckButton", control_font_pressed_color); + theme->set_color("font_disabled_color", "CheckButton", control_font_disabled_color); + theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1)); theme->set_constant("hseparation", "CheckButton", 4 * scale); theme->set_constant("check_vadjust", "CheckButton", 0 * scale); + theme->set_constant("outline_size", "CheckButton", 0); // Label theme->set_stylebox("normal", "Label", memnew(StyleBoxEmpty)); - theme->set_font("font", "Label", default_font); + theme->set_font("font", "Label", Ref<Font>()); + theme->set_font_size("font_size", "Label", -1); theme->set_color("font_color", "Label", Color(1, 1, 1)); - theme->set_color("font_color_shadow", "Label", Color(0, 0, 0, 0)); - theme->set_color("font_outline_modulate", "Label", Color(1, 1, 1)); + theme->set_color("font_shadow_color", "Label", Color(0, 0, 0, 0)); + theme->set_color("font_outline_color", "Label", Color(1, 1, 1)); theme->set_constant("shadow_offset_x", "Label", 1 * scale); theme->set_constant("shadow_offset_y", "Label", 1 * scale); - theme->set_constant("shadow_as_outline", "Label", 0 * scale); + theme->set_constant("outline_size", "Label", 0); + theme->set_constant("shadow_outline_size", "Label", 1 * scale); theme->set_constant("line_spacing", "Label", 3 * scale); // LineEdit @@ -365,17 +427,20 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("focus", "LineEdit", focus); theme->set_stylebox("read_only", "LineEdit", make_stylebox(line_edit_disabled_png, 6, 6, 6, 6)); - theme->set_font("font", "LineEdit", default_font); + theme->set_font("font", "LineEdit", Ref<Font>()); + theme->set_font_size("font_size", "LineEdit", -1); theme->set_color("font_color", "LineEdit", control_font_color); - theme->set_color("font_color_selected", "LineEdit", Color(0, 0, 0)); - theme->set_color("font_color_uneditable", "LineEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); - theme->set_color("cursor_color", "LineEdit", control_font_color_hover); - theme->set_color("selection_color", "LineEdit", font_color_selection); + theme->set_color("font_selected_color", "LineEdit", Color(0, 0, 0)); + theme->set_color("font_uneditable_color", "LineEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_outline_color", "LineEdit", Color(1, 1, 1)); + theme->set_color("cursor_color", "LineEdit", control_font_hover_color); + theme->set_color("selection_color", "LineEdit", control_selection_color); theme->set_color("clear_button_color", "LineEdit", control_font_color); - theme->set_color("clear_button_color_pressed", "LineEdit", control_font_color_pressed); + theme->set_color("clear_button_color_pressed", "LineEdit", control_font_pressed_color); - theme->set_constant("minimum_spaces", "LineEdit", 12 * scale); + theme->set_constant("minimum_character_width", "LineEdit", 4); + theme->set_constant("outline_size", "LineEdit", 0); theme->set_icon("clear", "LineEdit", make_icon(line_edit_clear_png)); @@ -384,10 +449,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("bg", "ProgressBar", make_stylebox(progress_bar_png, 4, 4, 4, 4, 0, 0, 0, 0)); theme->set_stylebox("fg", "ProgressBar", make_stylebox(progress_fill_png, 6, 6, 6, 6, 2, 1, 2, 1)); - theme->set_font("font", "ProgressBar", default_font); + theme->set_font("font", "ProgressBar", Ref<Font>()); + theme->set_font_size("font_size", "ProgressBar", -1); + + theme->set_color("font_color", "ProgressBar", control_font_hover_color); + theme->set_color("font_shadow_color", "ProgressBar", Color(0, 0, 0)); + theme->set_color("font_outline_color", "ProgressBar", Color(1, 1, 1)); - theme->set_color("font_color", "ProgressBar", control_font_color_hover); - theme->set_color("font_color_shadow", "ProgressBar", Color(0, 0, 0)); + theme->set_constant("outline_size", "ProgressBar", 0); // TextEdit @@ -398,42 +467,82 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const 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); + theme->set_font("font", "TextEdit", Ref<Font>()); + theme->set_font_size("font_size", "TextEdit", -1); theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0)); theme->set_color("completion_background_color", "TextEdit", Color(0.17, 0.16, 0.2)); theme->set_color("completion_selected_color", "TextEdit", Color(0.26, 0.26, 0.27)); theme->set_color("completion_existing_color", "TextEdit", Color(0.87, 0.87, 0.87, 0.13)); - theme->set_color("completion_scroll_color", "TextEdit", control_font_color_pressed); + theme->set_color("completion_scroll_color", "TextEdit", control_font_pressed_color); theme->set_color("completion_font_color", "TextEdit", Color(0.67, 0.67, 0.67)); theme->set_color("font_color", "TextEdit", control_font_color); - theme->set_color("font_color_selected", "TextEdit", Color(0, 0, 0)); - theme->set_color("font_color_readonly", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); - theme->set_color("selection_color", "TextEdit", font_color_selection); + theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0)); + theme->set_color("font_readonly_color", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1)); + theme->set_color("selection_color", "TextEdit", control_selection_color); 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); theme->set_color("caret_background_color", "TextEdit", Color(0, 0, 0)); - theme->set_color("symbol_color", "TextEdit", control_font_color_hover); theme->set_color("brace_mismatch_color", "TextEdit", Color(1, 0.2, 0.2)); - theme->set_color("line_number_color", "TextEdit", Color(0.67, 0.67, 0.67, 0.4)); - theme->set_color("safe_line_number_color", "TextEdit", Color(0.67, 0.78, 0.67, 0.6)); - theme->set_color("function_color", "TextEdit", Color(0.4, 0.64, 0.81)); - theme->set_color("member_variable_color", "TextEdit", Color(0.9, 0.31, 0.35)); - theme->set_color("number_color", "TextEdit", Color(0.92, 0.58, 0.2)); theme->set_color("word_highlighted_color", "TextEdit", Color(0.8, 0.9, 0.9, 0.15)); theme->set_constant("completion_lines", "TextEdit", 7); theme->set_constant("completion_max_width", "TextEdit", 50); theme->set_constant("completion_scroll_width", "TextEdit", 3); theme->set_constant("line_spacing", "TextEdit", 4 * scale); + theme->set_constant("outline_size", "TextEdit", 0); + + // CodeEdit + + theme->set_stylebox("normal", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); + theme->set_stylebox("focus", "CodeEdit", focus); + theme->set_stylebox("read_only", "CodeEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0)); + theme->set_stylebox("completion", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); + + theme->set_icon("tab", "CodeEdit", make_icon(tab_png)); + theme->set_icon("space", "CodeEdit", make_icon(space_png)); + theme->set_icon("breakpoint", "CodeEdit", make_icon(graph_port_png)); + theme->set_icon("bookmark", "CodeEdit", make_icon(bookmark_png)); + theme->set_icon("executing_line", "CodeEdit", make_icon(arrow_right_png)); + theme->set_icon("can_fold", "CodeEdit", make_icon(arrow_down_png)); + theme->set_icon("folded", "CodeEdit", make_icon(arrow_right_png)); + + theme->set_font("font", "CodeEdit", Ref<Font>()); + theme->set_font_size("font_size", "CodeEdit", -1); + + theme->set_color("background_color", "CodeEdit", Color(0, 0, 0, 0)); + theme->set_color("completion_background_color", "CodeEdit", Color(0.17, 0.16, 0.2)); + theme->set_color("completion_selected_color", "CodeEdit", Color(0.26, 0.26, 0.27)); + theme->set_color("completion_existing_color", "CodeEdit", Color(0.87, 0.87, 0.87, 0.13)); + theme->set_color("completion_scroll_color", "CodeEdit", control_font_pressed_color); + theme->set_color("completion_font_color", "CodeEdit", Color(0.67, 0.67, 0.67)); + theme->set_color("font_color", "CodeEdit", control_font_color); + theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0)); + theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1)); + theme->set_color("selection_color", "CodeEdit", control_selection_color); + theme->set_color("mark_color", "CodeEdit", Color(1.0, 0.4, 0.4, 0.4)); + theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8)); + theme->set_color("breakpoint_color", "CodeEdit", Color(0.9, 0.29, 0.3)); + theme->set_color("executing_line_color", "CodeEdit", Color(0.98, 0.89, 0.27)); + theme->set_color("code_folding_color", "CodeEdit", Color(0.8, 0.8, 0.8, 0.8)); + theme->set_color("current_line_color", "CodeEdit", Color(0.25, 0.25, 0.26, 0.8)); + theme->set_color("caret_color", "CodeEdit", control_font_color); + theme->set_color("caret_background_color", "CodeEdit", Color(0, 0, 0)); + theme->set_color("brace_mismatch_color", "CodeEdit", Color(1, 0.2, 0.2)); + theme->set_color("line_number_color", "CodeEdit", Color(0.67, 0.67, 0.67, 0.4)); + theme->set_color("safe_line_number_color", "CodeEdit", Color(0.67, 0.78, 0.67, 0.6)); + theme->set_color("word_highlighted_color", "CodeEdit", Color(0.8, 0.9, 0.9, 0.15)); + + theme->set_constant("completion_lines", "CodeEdit", 7); + theme->set_constant("completion_max_width", "CodeEdit", 50); + theme->set_constant("completion_scroll_width", "CodeEdit", 3); + theme->set_constant("line_spacing", "CodeEdit", 4 * scale); + theme->set_constant("outline_size", "CodeEdit", 0); Ref<Texture2D> empty_icon = memnew(ImageTexture); @@ -489,7 +598,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("updown", "SpinBox", make_icon(spinbox_updown_png)); - //scroll container + // ScrollContainer + Ref<StyleBoxEmpty> empty; empty.instance(); theme->set_stylebox("bg", "ScrollContainer", empty); @@ -501,7 +611,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("scaleborder_size", "Window", 4 * scale); theme->set_font("title_font", "Window", large_font); + theme->set_font_size("title_font_size", "Window", -1); + theme->set_color("title_color", "Window", Color(0, 0, 0)); + theme->set_color("title_outline_modulate", "Window", Color(1, 1, 1)); + + theme->set_constant("title_outline_size", "Window", 0); theme->set_constant("title_height", "Window", 20 * scale); theme->set_constant("resize_margin", "Window", 4 * scale); @@ -522,7 +637,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxTexture> selected = make_stylebox(selection_png, 6, 6, 6, 6); for (int i = 0; i < 4; i++) { - selected->set_expand_margin_size(Margin(i), 2 * scale); + selected->set_expand_margin_size(Side(i), 2 * scale); } theme->set_stylebox("panel", "PopupPanel", style_pp); @@ -546,16 +661,23 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("radio_checked", "PopupMenu", make_icon(radio_checked_png)); theme->set_icon("radio_unchecked", "PopupMenu", make_icon(radio_unchecked_png)); theme->set_icon("submenu", "PopupMenu", make_icon(submenu_png)); + theme->set_icon("submenu_mirrored", "PopupMenu", make_icon(submenu_mirrored_png)); - theme->set_font("font", "PopupMenu", default_font); + theme->set_font("font", "PopupMenu", Ref<Font>()); + theme->set_font_size("font_size", "PopupMenu", -1); theme->set_color("font_color", "PopupMenu", control_font_color); - theme->set_color("font_color_accel", "PopupMenu", Color(0.7, 0.7, 0.7, 0.8)); - theme->set_color("font_color_disabled", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8)); - theme->set_color("font_color_hover", "PopupMenu", control_font_color); + theme->set_color("font_accelerator_color", "PopupMenu", Color(0.7, 0.7, 0.7, 0.8)); + theme->set_color("font_disabled_color", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8)); + theme->set_color("font_hover_color", "PopupMenu", control_font_color); + theme->set_color("font_separator_color", "PopupMenu", control_font_color); + theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1)); theme->set_constant("hseparation", "PopupMenu", 4 * scale); theme->set_constant("vseparation", "PopupMenu", 4 * scale); + theme->set_constant("outline_size", "PopupMenu", 0); + theme->set_constant("item_start_padding", "PopupMenu", 2 * scale); + theme->set_constant("item_end_padding", "PopupMenu", 2 * scale); // GraphNode @@ -568,8 +690,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const 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); + //graphsb->set_expand_margin_size(SIDE_LEFT,10); + //graphsb->set_expand_margin_size(SIDE_RIGHT,10); theme->set_stylebox("frame", "GraphNode", graphsb); theme->set_stylebox("selectedframe", "GraphNode", graphsbselected); theme->set_stylebox("defaultframe", "GraphNode", graphsbdefault); @@ -582,7 +704,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("port", "GraphNode", make_icon(graph_port_png)); theme->set_icon("close", "GraphNode", make_icon(graph_node_close_png)); theme->set_icon("resizer", "GraphNode", make_icon(window_resizer_png)); - theme->set_font("title_font", "GraphNode", default_font); + theme->set_font("title_font", "GraphNode", Ref<Font>()); theme->set_color("title_color", "GraphNode", Color(0, 0, 0, 1)); theme->set_color("close_color", "GraphNode", Color(0, 0, 0, 1)); theme->set_color("resizer_color", "GraphNode", Color(0, 0, 0, 1)); @@ -615,17 +737,20 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("select_arrow", "Tree", make_icon(dropdown_png)); theme->set_icon("arrow", "Tree", make_icon(arrow_down_png)); theme->set_icon("arrow_collapsed", "Tree", make_icon(arrow_right_png)); + theme->set_icon("arrow_collapsed_mirrored", "Tree", make_icon(arrow_left_png)); - theme->set_font("title_button_font", "Tree", default_font); - theme->set_font("font", "Tree", default_font); + theme->set_font("title_button_font", "Tree", Ref<Font>()); + theme->set_font("font", "Tree", Ref<Font>()); + theme->set_font_size("font_size", "Tree", -1); theme->set_color("title_button_color", "Tree", control_font_color); - theme->set_color("font_color", "Tree", control_font_color_low); - theme->set_color("font_color_selected", "Tree", control_font_color_pressed); + theme->set_color("font_color", "Tree", control_font_low_color); + theme->set_color("font_selected_color", "Tree", control_font_pressed_color); + theme->set_color("font_outline_color", "Tree", Color(1, 1, 1)); theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1)); theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2)); theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27)); - theme->set_color("custom_button_font_highlight", "Tree", control_font_color_hover); + theme->set_color("custom_button_font_highlight", "Tree", control_font_hover_color); theme->set_constant("hseparation", "Tree", 4 * scale); theme->set_constant("vseparation", "Tree", 4 * scale); @@ -635,8 +760,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("draw_guides", "Tree", 1); theme->set_constant("scroll_border", "Tree", 4); theme->set_constant("scroll_speed", "Tree", 12); + theme->set_constant("outline_size", "Tree", 0); // ItemList + Ref<StyleBoxTexture> item_selected = make_stylebox(selection_png, 4, 4, 4, 4, 8, 2, 8, 2); Ref<StyleBoxTexture> item_selected_oof = make_stylebox(selection_oof_png, 4, 4, 4, 4, 8, 2, 8, 2); @@ -646,24 +773,30 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("vseparation", "ItemList", 2); theme->set_constant("icon_margin", "ItemList", 4); theme->set_constant("line_separation", "ItemList", 2 * scale); - theme->set_font("font", "ItemList", default_font); - theme->set_color("font_color", "ItemList", control_font_color_lower); - theme->set_color("font_color_selected", "ItemList", control_font_color_pressed); + + theme->set_font("font", "ItemList", Ref<Font>()); + theme->set_font_size("font_size", "ItemList", -1); + + theme->set_color("font_color", "ItemList", control_font_lower_color); + theme->set_color("font_selected_color", "ItemList", control_font_pressed_color); + theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1)); theme->set_color("guide_color", "ItemList", Color(0, 0, 0, 0.1)); theme->set_stylebox("selected", "ItemList", item_selected_oof); theme->set_stylebox("selected_focus", "ItemList", item_selected); theme->set_stylebox("cursor", "ItemList", focus); theme->set_stylebox("cursor_unfocused", "ItemList", focus); + theme->set_constant("outline_size", "ItemList", 0); + // TabContainer Ref<StyleBoxTexture> tc_sb = sb_expand(make_stylebox(tab_container_bg_png, 4, 4, 4, 4, 4, 4, 4, 4), 3, 3, 3, 3); - tc_sb->set_expand_margin_size(MARGIN_TOP, 2 * scale); - tc_sb->set_default_margin(MARGIN_TOP, 8 * scale); + tc_sb->set_expand_margin_size(SIDE_TOP, 2 * scale); + tc_sb->set_default_margin(SIDE_TOP, 8 * scale); - 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_selected", "TabContainer", sb_expand(make_stylebox(tab_current_png, 4, 4, 4, 1, 16, 4, 16, 4), 2, 2, 2, 2)); + theme->set_stylebox("tab_unselected", "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); @@ -674,19 +807,22 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("menu", "TabContainer", make_icon(tab_menu_png)); theme->set_icon("menu_highlight", "TabContainer", make_icon(tab_menu_hl_png)); - theme->set_font("font", "TabContainer", default_font); + theme->set_font("font", "TabContainer", Ref<Font>()); + theme->set_font_size("font_size", "TabContainer", -1); - theme->set_color("font_color_fg", "TabContainer", control_font_color_hover); - theme->set_color("font_color_bg", "TabContainer", control_font_color_low); - theme->set_color("font_color_disabled", "TabContainer", control_font_color_disabled); + theme->set_color("font_selected_color", "TabContainer", control_font_hover_color); + theme->set_color("font_unselected_color", "TabContainer", control_font_low_color); + theme->set_color("font_disabled_color", "TabContainer", control_font_disabled_color); + theme->set_color("font_outline_color", "TabContainer", Color(1, 1, 1)); theme->set_constant("side_margin", "TabContainer", 8 * scale); - theme->set_constant("hseparation", "TabContainer", 4 * scale); + theme->set_constant("icon_separation", "TabContainer", 4 * scale); + theme->set_constant("outline_size", "TabContainer", 0); // Tabs - 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_selected", "Tabs", sb_expand(make_stylebox(tab_current_png, 4, 3, 4, 1, 16, 3, 16, 2), 2, 2, 2, 2)); + theme->set_stylebox("tab_unselected", "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)); @@ -698,13 +834,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("decrement_highlight", "Tabs", make_icon(scroll_button_left_hl_png)); theme->set_icon("close", "Tabs", make_icon(tab_close_png)); - theme->set_font("font", "Tabs", default_font); + theme->set_font("font", "Tabs", Ref<Font>()); + theme->set_font_size("font_size", "Tabs", -1); - theme->set_color("font_color_fg", "Tabs", control_font_color_hover); - theme->set_color("font_color_bg", "Tabs", control_font_color_low); - theme->set_color("font_color_disabled", "Tabs", control_font_color_disabled); + theme->set_color("font_selected_color", "Tabs", control_font_hover_color); + theme->set_color("font_unselected_color", "Tabs", control_font_low_color); + theme->set_color("font_disabled_color", "Tabs", control_font_disabled_color); + theme->set_color("font_outline_color", "Tabs", Color(1, 1, 1)); theme->set_constant("hseparation", "Tabs", 4 * scale); + theme->set_constant("outline_size", "Tabs", 0); // Separators @@ -712,7 +851,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("separator", "VSeparator", make_stylebox(hseparator_png, 3, 3, 3, 3)); theme->set_icon("close", "Icons", make_icon(icon_close_png)); - theme->set_font("normal", "Fonts", default_font); + theme->set_font("normal", "Fonts", Ref<Font>()); theme->set_font("large", "Fonts", large_font); theme->set_constant("separation", "HSeparator", 4 * scale); @@ -726,7 +865,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // FileDialog theme->set_icon("folder", "FileDialog", make_icon(icon_folder_png)); + theme->set_icon("file", "FileDialog", make_icon(icon_file_png)); theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1)); + theme->set_color("file_icon_modulate", "FileDialog", Color(1, 1, 1)); theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7)); // ColorPicker @@ -750,35 +891,46 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxTexture> style_tt = make_stylebox(tooltip_bg_png, 4, 4, 4, 4); for (int i = 0; i < 4; i++) { - style_tt->set_expand_margin_size((Margin)i, 4 * scale); + style_tt->set_expand_margin_size((Side)i, 4 * scale); } theme->set_stylebox("panel", "TooltipPanel", style_tt); - theme->set_font("font", "TooltipLabel", default_font); + theme->set_font("font", "TooltipLabel", Ref<Font>()); + theme->set_font_size("font_size", "TooltipLabel", -1); theme->set_color("font_color", "TooltipLabel", Color(0, 0, 0)); - theme->set_color("font_color_shadow", "TooltipLabel", Color(0, 0, 0, 0.1)); + theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0.1)); + theme->set_color("font_outline_color", "TooltipLabel", Color(1, 1, 1)); theme->set_constant("shadow_offset_x", "TooltipLabel", 1); theme->set_constant("shadow_offset_y", "TooltipLabel", 1); + theme->set_constant("outline_size", "TooltipLabel", 0); // RichTextLabel theme->set_stylebox("focus", "RichTextLabel", focus); theme->set_stylebox("normal", "RichTextLabel", make_empty_stylebox(0, 0, 0, 0)); - theme->set_font("normal_font", "RichTextLabel", default_font); - theme->set_font("bold_font", "RichTextLabel", default_font); - theme->set_font("italics_font", "RichTextLabel", default_font); - theme->set_font("bold_italics_font", "RichTextLabel", default_font); - theme->set_font("mono_font", "RichTextLabel", default_font); + theme->set_font("normal_font", "RichTextLabel", Ref<Font>()); + theme->set_font("bold_font", "RichTextLabel", Ref<Font>()); + theme->set_font("italics_font", "RichTextLabel", Ref<Font>()); + theme->set_font("bold_italics_font", "RichTextLabel", Ref<Font>()); + theme->set_font("mono_font", "RichTextLabel", Ref<Font>()); + + theme->set_font_size("normal_font_size", "RichTextLabel", -1); + theme->set_font_size("bold_font_size", "RichTextLabel", -1); + theme->set_font_size("italics_font_size", "RichTextLabel", -1); + theme->set_font_size("bold_italics_font_size", "RichTextLabel", -1); + theme->set_font_size("mono_font_size", "RichTextLabel", -1); theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1)); - theme->set_color("font_color_selected", "RichTextLabel", font_color_selection); + theme->set_color("font_selected_color", "RichTextLabel", Color(0, 0, 0)); theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8)); - theme->set_color("font_color_shadow", "RichTextLabel", Color(0, 0, 0, 0)); + theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0)); + + theme->set_color("font_outline_color", "RichTextLabel", Color(1, 1, 1)); theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * scale); theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * scale); @@ -788,6 +940,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale); theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale); + theme->set_constant("outline_size", "RichTextLabel", 0); + + theme->set_color("table_odd_row_bg", "RichTextLabel", Color(0, 0, 0, 0)); + theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0)); + theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0)); + // Containers theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1)); @@ -816,6 +974,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("reset", "GraphEdit", make_icon(icon_zoom_reset_png)); theme->set_icon("more", "GraphEdit", make_icon(icon_zoom_more_png)); theme->set_icon("snap", "GraphEdit", make_icon(icon_snap_grid_png)); + theme->set_icon("minimap", "GraphEdit", make_icon(icon_grid_minimap_png)); theme->set_stylebox("bg", "GraphEdit", make_stylebox(tree_bg_png, 4, 4, 4, 5)); theme->set_color("grid_minor", "GraphEdit", Color(1, 1, 1, 0.05)); theme->set_color("grid_major", "GraphEdit", Color(1, 1, 1, 0.2)); @@ -826,9 +985,23 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale); // Visual Node Ports + theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale); theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale); + theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0)); + Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0); + style_minimap_camera->set_border_color(Color(0.65, 0.65, 0.65, 0.45)); + style_minimap_camera->set_border_width_all(1); + theme->set_stylebox("camera", "GraphEditMinimap", style_minimap_camera); + Ref<StyleBoxFlat> style_minimap_node = make_flat_stylebox(Color(1, 1, 1), 0, 0, 0, 0); + style_minimap_node->set_corner_radius_all(2); + theme->set_stylebox("node", "GraphEditMinimap", style_minimap_node); + + Ref<Texture2D> resizer_icon = make_icon(window_resizer_png); + theme->set_icon("resizer", "GraphEditMinimap", flip_icon(resizer_icon, true, true)); + theme->set_color("resizer_color", "GraphEditMinimap", Color(1, 1, 1, 0.85)); + // Theme default_icon = make_icon(error_icon_png); @@ -844,12 +1017,17 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) { Ref<StyleBox> default_style; Ref<Texture2D> default_icon; Ref<Font> default_font; + int default_font_size = 16; if (p_font.is_valid()) { default_font = p_font; } else if (p_hidpi) { - default_font = make_font(_hidpi_font_height, _hidpi_font_ascent, _hidpi_font_charcount, &_hidpi_font_charrects[0][0], _hidpi_font_kerning_pair_count, &_hidpi_font_kerning_pairs[0][0], _hidpi_font_img_width, _hidpi_font_img_height, _hidpi_font_img_data); + Ref<FontData> font_data = make_font(_hidpi_font_height, _hidpi_font_ascent, _hidpi_font_charcount, &_hidpi_font_charrects[0][0], _hidpi_font_kerning_pair_count, &_hidpi_font_kerning_pairs[0][0], _hidpi_font_img_width, _hidpi_font_img_height, _hidpi_font_img_data); + default_font.instance(); + default_font->add_data(font_data); } else { - default_font = make_font(_lodpi_font_height, _lodpi_font_ascent, _lodpi_font_charcount, &_lodpi_font_charrects[0][0], _lodpi_font_kerning_pair_count, &_lodpi_font_kerning_pairs[0][0], _lodpi_font_img_width, _lodpi_font_img_height, _lodpi_font_img_data); + Ref<FontData> font_data = make_font(_lodpi_font_height, _lodpi_font_ascent, _lodpi_font_charcount, &_lodpi_font_charrects[0][0], _lodpi_font_kerning_pair_count, &_lodpi_font_kerning_pairs[0][0], _lodpi_font_img_width, _lodpi_font_img_height, _lodpi_font_img_data); + default_font.instance(); + default_font->add_data(font_data); } Ref<Font> large_font = default_font; fill_default_theme(t, default_font, large_font, default_icon, default_style, p_hidpi ? 2.0 : 1.0); @@ -858,6 +1036,7 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) { Theme::set_default_icon(default_icon); Theme::set_default_style(default_style); Theme::set_default_font(default_font); + Theme::set_default_font_size(default_font_size); } void clear_default_theme() { diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index 46f89a9b50..a7b2bec5a4 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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_lodpi.inc b/scene/resources/default_theme/font_lodpi.inc index 959e2c1d7b..d2f5851224 100644 --- a/scene/resources/default_theme/font_lodpi.inc +++ b/scene/resources/default_theme/font_lodpi.inc @@ -8,7 +8,7 @@ static const int _lodpi_font_charrects[191][8]={ {224,85,180,5,11,0,1,7}, {192,32,16,11,13,-2,-1,9}, {96,2,216,3,2,0,3,8}, -{160,1734439808,0,0,0,11,0,4}, +{160,0,0,0,0,11,0,4}, {32,0,0,0,0,11,0,4}, {33,65,234,2,10,1,1,4}, {225,112,169,5,11,0,1,7}, diff --git a/scene/resources/default_theme/icon_file.png b/scene/resources/default_theme/icon_file.png Binary files differnew file mode 100644 index 0000000000..bb4c361a8d --- /dev/null +++ b/scene/resources/default_theme/icon_file.png diff --git a/scene/resources/default_theme/icon_grid_minimap.png b/scene/resources/default_theme/icon_grid_minimap.png Binary files differnew file mode 100644 index 0000000000..00a6179d5e --- /dev/null +++ b/scene/resources/default_theme/icon_grid_minimap.png diff --git a/scene/resources/default_theme/option_button_disabled_mirrored.png b/scene/resources/default_theme/option_button_disabled_mirrored.png Binary files differnew file mode 100644 index 0000000000..9d149a35ca --- /dev/null +++ b/scene/resources/default_theme/option_button_disabled_mirrored.png diff --git a/scene/resources/default_theme/option_button_hover_mirrored.png b/scene/resources/default_theme/option_button_hover_mirrored.png Binary files differnew file mode 100644 index 0000000000..d49c165645 --- /dev/null +++ b/scene/resources/default_theme/option_button_hover_mirrored.png diff --git a/scene/resources/default_theme/option_button_normal_mirrored.png b/scene/resources/default_theme/option_button_normal_mirrored.png Binary files differnew file mode 100644 index 0000000000..feec848f33 --- /dev/null +++ b/scene/resources/default_theme/option_button_normal_mirrored.png diff --git a/scene/resources/default_theme/option_button_pressed_mirrored.png b/scene/resources/default_theme/option_button_pressed_mirrored.png Binary files differnew file mode 100644 index 0000000000..94cabb18d6 --- /dev/null +++ b/scene/resources/default_theme/option_button_pressed_mirrored.png diff --git a/scene/resources/default_theme/submenu_mirrored.png b/scene/resources/default_theme/submenu_mirrored.png Binary files differnew file mode 100644 index 0000000000..1142b9ba9f --- /dev/null +++ b/scene/resources/default_theme/submenu_mirrored.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 0a4e557451..b905c9db69 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -6,10 +6,18 @@ static const unsigned char arrow_down_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x34, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x32, 0x78, 0xf0, 0x1f, 0x15, 0x52, 0x20, 0xf1, 0x30, 0xee, 0xc1, 0x17, 0xb8, 0xf0, 0xb7, 0x87, 0x69, 0x48, 0xb6, 0xdc, 0xd7, 0xb8, 0x7f, 0x9, 0x2c, 0x7c, 0xfd, 0xb1, 0x2e, 0x9a, 0x3, 0x5e, 0x70, 0x3f, 0x9c, 0xff, 0x70, 0xfe, 0xb, 0x6e, 0x6, 0xea, 0x3, 0x0, 0xfb, 0x81, 0x48, 0xb8, 0x4d, 0xe4, 0x75, 0xd9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char arrow_left_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0xa0, 0x0, 0xdc, 0x4f, 0x78, 0xf0, 0xff, 0xc1, 0xff, 0x7, 0xff, 0x21, 0x3c, 0x46, 0x98, 0xf0, 0x43, 0xed, 0xff, 0x27, 0x19, 0xb8, 0x19, 0x18, 0x18, 0x18, 0x14, 0x18, 0x19, 0x18, 0x18, 0x18, 0x98, 0x20, 0xc2, 0x2f, 0xb8, 0xff, 0xaf, 0x82, 0x8, 0xc3, 0x0, 0x54, 0xe2, 0xe7, 0x14, 0x6, 0x2d, 0x54, 0x83, 0x99, 0x70, 0xd9, 0x8, 0x95, 0x60, 0xcf, 0x61, 0xb8, 0x86, 0x55, 0x42, 0xe2, 0x2b, 0x63, 0x18, 0xc3, 0x57, 0xac, 0x46, 0xc9, 0x5f, 0xfd, 0x9f, 0x43, 0x89, 0x67, 0x19, 0x18, 0x0, 0xf4, 0x30, 0x14, 0x49, 0xef, 0xe6, 0x74, 0x60, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char arrow_right_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x17, 0x3c, 0xf8, 0xf, 0x82, 0xf7, 0x13, 0x70, 0x48, 0x3c, 0xf8, 0xf2, 0x50, 0x1b, 0x43, 0x2, 0xa, 0xaf, 0xbe, 0xe0, 0xc6, 0x2e, 0xf1, 0xff, 0xe1, 0x7c, 0x12, 0x24, 0x10, 0x46, 0x11, 0xb6, 0x1c, 0xe1, 0x5c, 0xa, 0x0, 0x0, 0xe0, 0x14, 0x48, 0xb1, 0x3d, 0x1b, 0x7a, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char bookmark_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, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xed, 0x93, 0x31, 0xa, 0xc0, 0x30, 0xc, 0x3, 0xa5, 0xd0, 0xff, 0x7f, 0x59, 0x1d, 0x8a, 0x42, 0x8, 0x9, 0x95, 0xc9, 0xd2, 0xa1, 0x9a, 0x8c, 0xf1, 0xdd, 0x62, 0x1b, 0x38, 0xc, 0x87, 0x5a, 0x5, 0xae, 0x79, 0xde, 0x2, 0x1, 0x80, 0x94, 0x39, 0x48, 0x76, 0x49, 0x17, 0xa4, 0xf0, 0x24, 0x61, 0x2b, 0x51, 0x8b, 0xfc, 0x82, 0xcf, 0xb, 0x48, 0x7a, 0xdf, 0x75, 0x81, 0xf, 0xe5, 0x29, 0xf7, 0x92, 0x6b, 0x3, 0x1a, 0x1e, 0xda, 0x7c, 0x3d, 0x77, 0x21, 0x7b, 0xa8, 0x74, 0x2e, 0xcb, 0xd, 0xc8, 0x75, 0x13, 0x28, 0x9, 0xed, 0xc2, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char button_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, 0x0, 0xc7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xd0, 0x81, 0x66, 0x43, 0x31, 0x14, 0x87, 0xf1, 0xf, 0x5, 0x17, 0xb8, 0x28, 0x2e, 0x8, 0x71, 0xf3, 0x6, 0x19, 0xb6, 0xb9, 0xcb, 0xac, 0x95, 0xa4, 0xb7, 0xad, 0x6a, 0xd5, 0x68, 0x5f, 0xe4, 0x3e, 0x76, 0x1e, 0xe1, 0xbf, 0x21, 0xa6, 0xab, 0xf8, 0x1, 0x7c, 0x9c, 0x73, 0xe, 0xac, 0xe8, 0xe8, 0x19, 0x30, 0x58, 0xc6, 0xca, 0x62, 0x18, 0xe8, 0xe9, 0x58, 0x41, 0xc7, 0x1a, 0x87, 0x27, 0x10, 0x49, 0xe4, 0x5f, 0x89, 0x48, 0xc0, 0xe3, 0x58, 0xd3, 0x41, 0x8f, 0xb, 0xcb, 0xbd, 0x7c, 0xeb, 0xbf, 0x7b, 0x9, 0xb, 0x8e, 0x1e, 0x6, 0xfc, 0xad, 0x64, 0x6d, 0xb5, 0x79, 0xb0, 0x55, 0xd6, 0xad, 0xe0, 0x19, 0xc0, 0x10, 0xae, 0xda, 0x34, 0x5c, 0x45, 0xc0, 0x80, 0x25, 0x5e, 0xf4, 0xd5, 0x70, 0x11, 0x11, 0xb, 0x23, 0xe9, 0xac, 0xcf, 0x86, 0xb3, 0x48, 0x8c, 0x30, 0x92, 0x4f, 0xa, 0xd, 0x27, 0x91, 0x6b, 0x70, 0xd4, 0x47, 0xc3, 0xf1, 0x2f, 0x48, 0x7, 0x4d, 0xd, 0x87, 0x3a, 0xc2, 0x12, 0x67, 0xbd, 0x37, 0xcc, 0x75, 0x49, 0x43, 0xd8, 0xe9, 0xad, 0x61, 0x57, 0xcf, 0x1c, 0xf0, 0xfb, 0x32, 0xe9, 0xf5, 0xc9, 0xa4, 0x7d, 0x7d, 0x54, 0x8f, 0x7b, 0x59, 0xe6, 0x92, 0x14, 0x1f, 0x24, 0xcd, 0x3f, 0x7b, 0x6b, 0xa, 0xe, 0x6a, 0x82, 0x91, 0x45, 0x30, 0xba, 0x1, 0x4a, 0x51, 0xc4, 0x35, 0x1f, 0xe5, 0xa1, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -150,10 +158,18 @@ static const unsigned char icon_color_pick_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, 0xaa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x9d, 0x8e, 0x35, 0x82, 0x2, 0x41, 0x10, 0x45, 0x3b, 0xda, 0x3d, 0xca, 0xba, 0x44, 0x2b, 0x70, 0x9, 0xdc, 0xe1, 0x20, 0xe8, 0x91, 0x90, 0x78, 0x6e, 0x40, 0x4c, 0x82, 0x74, 0xff, 0xc2, 0x9d, 0x18, 0xa7, 0x6, 0x77, 0x7b, 0x23, 0x2d, 0xaf, 0x4c, 0xdc, 0xc, 0xbd, 0x65, 0x1e, 0x84, 0x80, 0x19, 0x55, 0x34, 0x60, 0x3e, 0xd0, 0xea, 0x17, 0x3d, 0x4a, 0xc8, 0x80, 0x1a, 0x60, 0xc2, 0x4f, 0xfd, 0x30, 0xe0, 0x1b, 0x2d, 0x16, 0xab, 0xa7, 0x2c, 0xe, 0x41, 0x68, 0xa5, 0xb9, 0xca, 0x91, 0x16, 0x2e, 0x54, 0xe0, 0x59, 0x54, 0x91, 0xfe, 0xa3, 0x3a, 0xff, 0xce, 0xab, 0x5b, 0xf, 0xa0, 0x4, 0x8f, 0x7b, 0x4c, 0xd3, 0x1b, 0xca, 0x32, 0xcc, 0x55, 0x7a, 0xf4, 0x76, 0x42, 0x2b, 0x97, 0x3e, 0xae, 0xfa, 0xdd, 0xd2, 0xd2, 0x8e, 0x72, 0xe1, 0x83, 0xaf, 0x9f, 0xa9, 0x28, 0x7d, 0x5b, 0xe2, 0x2a, 0xd, 0xc3, 0xa2, 0x78, 0xfe, 0x7d, 0x51, 0xfc, 0x0, 0x8a, 0x41, 0xcb, 0x3d, 0xb2, 0xae, 0x1c, 0xd3, 0xc, 0xa5, 0x30, 0x81, 0xc6, 0xda, 0x29, 0x8e, 0x83, 0x34, 0x25, 0x29, 0x4a, 0x46, 0x71, 0x1f, 0x33, 0xbe, 0x51, 0x89, 0xaf, 0x78, 0xe3, 0x97, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char icon_file_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, 0x2, 0x3, 0x0, 0x0, 0x0, 0x62, 0x9d, 0x17, 0xf2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 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, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0x42, 0xf, 0xc7, 0x49, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x88, 0x95, 0xf0, 0xc6, 0x2a, 0x0, 0x0, 0x0, 0x21, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x0, 0x1, 0xae, 0x55, 0x2d, 0x20, 0xa2, 0x13, 0x44, 0x74, 0x39, 0x80, 0x88, 0x9, 0x40, 0xa2, 0x1, 0xc4, 0x5d, 0xb5, 0x80, 0x68, 0x2, 0x4, 0x0, 0x95, 0x34, 0x18, 0xe4, 0x5e, 0x46, 0xf7, 0x27, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char icon_folder_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, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x6, 0x78, 0x70, 0xf4, 0xc1, 0x7f, 0x24, 0x78, 0x18, 0x53, 0xc1, 0x7f, 0x54, 0x48, 0x50, 0xc1, 0x43, 0x1b, 0xbc, 0xa, 0x50, 0xad, 0x23, 0xa4, 0xe0, 0xff, 0x70, 0x52, 0x70, 0x18, 0x97, 0xf4, 0xfd, 0x43, 0xd4, 0x88, 0x4a, 0x0, 0x5a, 0xcb, 0x18, 0xab, 0x5e, 0xd9, 0x1a, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char icon_grid_minimap_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, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 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, 0x2, 0xd, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x75, 0x93, 0x31, 0x68, 0x14, 0x51, 0x10, 0x86, 0xbf, 0xd9, 0xd, 0xbb, 0xde, 0x76, 0x82, 0x21, 0xf8, 0xe0, 0xbc, 0x5d, 0x8b, 0x80, 0x69, 0x6c, 0xd2, 0x5a, 0x6a, 0x91, 0xc3, 0xd2, 0x46, 0x22, 0x8, 0x9, 0x89, 0x70, 0x85, 0x10, 0x41, 0xd, 0x24, 0x45, 0xb0, 0xb, 0x68, 0x11, 0x14, 0x24, 0x10, 0x22, 0x62, 0x21, 0x41, 0xe, 0x4b, 0x21, 0xa4, 0xb7, 0x49, 0x17, 0xb1, 0x8, 0xb9, 0xdd, 0xc7, 0x86, 0x33, 0x21, 0xe1, 0x3a, 0x8f, 0x64, 0x61, 0x6f, 0x2c, 0xbc, 0x3b, 0x36, 0xb9, 0xdc, 0xc0, 0x2b, 0xde, 0xcc, 0xfc, 0xf3, 0xff, 0xfc, 0xcc, 0x48, 0xa3, 0xd1, 0x78, 0x20, 0x22, 0x13, 0xbe, 0xef, 0xaf, 0xdf, 0xac, 0xd7, 0x1f, 0xe1, 0x38, 0xd3, 0xa8, 0x2a, 0xf0, 0x45, 0x6a, 0xb5, 0xcf, 0x5c, 0x11, 0xcd, 0x66, 0x33, 0x38, 0x3f, 0x3f, 0x9f, 0x13, 0x91, 0x7d, 0xb1, 0xd6, 0x6e, 0xaa, 0xea, 0xd3, 0xe0, 0xe8, 0xe8, 0xde, 0xe8, 0xee, 0xee, 0x37, 0xc0, 0xe9, 0xf6, 0x75, 0xf0, 0xfd, 0x9, 0x99, 0x9d, 0x6d, 0x15, 0x81, 0x59, 0x96, 0x3d, 0x3, 0x5e, 0x2, 0x63, 0x22, 0xf2, 0x69, 0xa4, 0x57, 0x1c, 0xdd, 0xdb, 0xfb, 0x5b, 0x0, 0x3, 0x38, 0x67, 0x41, 0x30, 0x11, 0xc7, 0xf1, 0x13, 0x0, 0x11, 0x71, 0xb2, 0x2c, 0x7b, 0xd8, 0xad, 0xad, 0x2, 0x6f, 0xb9, 0x0, 0x38, 0x3c, 0xfc, 0x5, 0x9c, 0xf6, 0xff, 0x22, 0x27, 0x27, 0xe3, 0xe3, 0x7f, 0xa, 0x3, 0x67, 0x45, 0xe4, 0xbb, 0xe7, 0x79, 0xb7, 0xc3, 0x30, 0x7c, 0xd7, 0x67, 0xe9, 0xe3, 0x67, 0x66, 0x5c, 0x60, 0x1, 0x50, 0x40, 0x51, 0x7d, 0x71, 0x6b, 0x72, 0xf2, 0x20, 0x8a, 0xa2, 0xf9, 0x28, 0x8a, 0xe6, 0x1, 0x3a, 0x9d, 0xce, 0x4f, 0x63, 0x4c, 0x3b, 0x4d, 0xd3, 0xd2, 0xc0, 0x80, 0x3c, 0xcf, 0xf, 0x92, 0xa9, 0xa9, 0x31, 0x60, 0x5, 0x58, 0x91, 0x5a, 0xed, 0xc7, 0x15, 0xfe, 0x95, 0xac, 0xb5, 0xcf, 0xf3, 0x3c, 0x3f, 0xe8, 0x25, 0x46, 0xa, 0xc5, 0xd, 0x11, 0x59, 0xb3, 0xd5, 0xea, 0x1b, 0xa0, 0x95, 0x54, 0xab, 0x5b, 0x97, 0xd1, 0x22, 0xb2, 0xa6, 0xaa, 0x6d, 0x60, 0xd, 0x58, 0xba, 0xa0, 0x20, 0xc, 0xc3, 0x65, 0xd7, 0x75, 0x23, 0xe0, 0x2e, 0xb0, 0x1, 0x5c, 0xbf, 0xf4, 0x0, 0xbe, 0xba, 0xae, 0x1b, 0x85, 0x61, 0xb8, 0x3c, 0xa0, 0x20, 0x4d, 0xd3, 0x52, 0xb9, 0x5c, 0x6e, 0xc5, 0x71, 0xbc, 0x23, 0x22, 0xd3, 0x61, 0x18, 0xde, 0x2f, 0xb2, 0x27, 0x49, 0xa2, 0xaa, 0xba, 0x53, 0x2e, 0x97, 0x5b, 0x69, 0x9a, 0x96, 0xf2, 0x3c, 0x1f, 0xf0, 0xc0, 0x5a, 0x6b, 0x5f, 0x1, 0x25, 0x86, 0x84, 0xe3, 0x38, 0x9e, 0xb5, 0x76, 0x2e, 0xcf, 0xf3, 0xfd, 0x1, 0x5, 0x22, 0xb2, 0xa1, 0xaa, 0x4b, 0x22, 0x72, 0xad, 0xcb, 0x38, 0xe0, 0x81, 0xaa, 0x7e, 0x0, 0xce, 0x44, 0xe4, 0xbd, 0xaa, 0xbe, 0xbe, 0xa0, 0xa0, 0x52, 0xa9, 0x2c, 0x7a, 0x9e, 0x17, 0x1, 0x3d, 0xe0, 0x55, 0x1e, 0x6c, 0x79, 0x9e, 0x17, 0x55, 0x2a, 0x95, 0xc5, 0x1, 0x5, 0xcd, 0x66, 0x33, 0x30, 0xc6, 0x9c, 0xc6, 0x71, 0xbc, 0x2d, 0x22, 0x8f, 0x87, 0x78, 0xb0, 0x6d, 0x8c, 0x39, 0xed, 0xae, 0x74, 0xdf, 0x83, 0x3a, 0x70, 0x9c, 0x65, 0x59, 0x23, 0x49, 0x92, 0x5, 0x11, 0x9, 0x86, 0x79, 0x20, 0x22, 0x41, 0x92, 0x24, 0xb, 0x59, 0x96, 0x35, 0x80, 0x63, 0xa0, 0x2e, 0x3d, 0xf6, 0xc2, 0x91, 0xdc, 0x0, 0x5c, 0x55, 0x5d, 0xbf, 0x4, 0x9e, 0x3, 0x72, 0xfe, 0xaf, 0xfb, 0xaa, 0xe7, 0x79, 0x1f, 0x8d, 0x31, 0x6d, 0x29, 0x36, 0xf5, 0xce, 0x14, 0xb8, 0x33, 0x44, 0xc4, 0x6f, 0xdf, 0xf7, 0xd7, 0x8d, 0x31, 0xed, 0x5e, 0xe2, 0x1f, 0xb, 0x5c, 0xe2, 0xcb, 0xd, 0x9b, 0x69, 0xcb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char icon_parent_folder_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, 0x68, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x33, 0xb8, 0x27, 0xfe, 0xe0, 0xfc, 0x83, 0x73, 0xf7, 0xc4, 0x71, 0x48, 0xdf, 0x11, 0x7b, 0x78, 0xe9, 0xc1, 0x3f, 0x20, 0xbc, 0xfe, 0x40, 0x12, 0x8f, 0x34, 0x4c, 0x9, 0xa6, 0xe1, 0x57, 0x80, 0x12, 0x17, 0x81, 0xf8, 0x2f, 0x58, 0xe1, 0x15, 0x34, 0x8b, 0x1e, 0x9c, 0x5, 0xa, 0x5e, 0xb8, 0x23, 0x6, 0x52, 0x70, 0x5b, 0x14, 0xac, 0xf0, 0xc, 0xaa, 0x82, 0x7d, 0xf, 0x8e, 0xde, 0x14, 0xf9, 0xcf, 0x8, 0x52, 0xc0, 0xc0, 0x70, 0x5b, 0xf4, 0xe1, 0xc9, 0x7, 0x47, 0xb1, 0xb8, 0x3, 0xaa, 0x0, 0xa, 0x48, 0x52, 0x80, 0xb0, 0xea, 0xc8, 0xc3, 0x83, 0xc, 0x83, 0xe, 0x0, 0x0, 0xb8, 0x27, 0x55, 0x4c, 0xbe, 0xc0, 0xd2, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -206,18 +222,34 @@ static const unsigned char option_button_disabled_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x2f, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3f, 0x3f, 0x5a, 0x5a, 0x5a, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x59, 0x59, 0x59, 0x2a, 0x2a, 0x30, 0x4b, 0x4b, 0x4b, 0x22, 0x22, 0x27, 0x35, 0x35, 0x35, 0x4a, 0x4a, 0x4a, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x56, 0x56, 0x56, 0x62, 0x62, 0x62, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x48, 0x48, 0x48, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x54, 0x54, 0x54, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x52, 0x52, 0x52, 0x42, 0x42, 0x42, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x51, 0x51, 0x51, 0x40, 0x40, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4f, 0x4f, 0x4f, 0x3f, 0x3f, 0x3f, 0x4d, 0x4d, 0x4d, 0x3e, 0x3e, 0x3e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4c, 0x4c, 0x4c, 0x3d, 0x3d, 0x3d, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4a, 0x4a, 0x4a, 0x3b, 0x3b, 0x3b, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x49, 0x49, 0x49, 0x3a, 0x3a, 0x3a, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x39, 0x39, 0x39, 0x47, 0x47, 0x47, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x46, 0x46, 0x46, 0xd3, 0xa7, 0xd4, 0x88, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xec, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0x8e, 0x5, 0x4e, 0x0, 0x31, 0x10, 0x45, 0xff, 0xef, 0x56, 0xc2, 0xe2, 0xee, 0x4e, 0x3c, 0xc8, 0xd, 0xb8, 0x38, 0xa7, 0xc0, 0xdd, 0xdd, 0x5d, 0xbb, 0x94, 0x4c, 0xd2, 0xc1, 0xdf, 0x4a, 0x47, 0x5e, 0x27, 0xc3, 0xc, 0x80, 0x64, 0x24, 0xb8, 0xc7, 0x4f, 0x2c, 0x6b, 0xd5, 0x90, 0xff, 0xdd, 0x23, 0x7e, 0xc1, 0xa2, 0xb6, 0x64, 0xad, 0x26, 0x82, 0xc6, 0xef, 0x45, 0xbc, 0xe3, 0x1, 0x2c, 0x69, 0x9b, 0xc8, 0x7f, 0x5, 0x36, 0x1e, 0x41, 0x84, 0xd6, 0x4, 0x25, 0x90, 0xb7, 0x39, 0x6c, 0x4c, 0x2f, 0xbe, 0x68, 0xdf, 0x13, 0xa1, 0x9e, 0xc8, 0xa4, 0xb7, 0xe7, 0x47, 0x93, 0x63, 0x1b, 0xf9, 0xdc, 0x8, 0x88, 0x60, 0xbf, 0x4, 0xff, 0xd2, 0x56, 0x93, 0xe3, 0xb7, 0xb2, 0xf6, 0x2c, 0x36, 0x1, 0x16, 0xf4, 0x5f, 0x42, 0xc4, 0x17, 0x8f, 0xb5, 0xc0, 0xa5, 0x8, 0x30, 0x5f, 0xc2, 0x5d, 0xcf, 0xc9, 0xd, 0x74, 0x87, 0x8b, 0x5e, 0x56, 0x22, 0x24, 0xf7, 0x6d, 0xc2, 0xd1, 0x80, 0x26, 0x27, 0x5d, 0x5b, 0x67, 0x7d, 0x2f, 0x80, 0x4d, 0xc9, 0x7f, 0x9, 0x63, 0xa7, 0x61, 0x23, 0xc7, 0x74, 0x3d, 0xf, 0xae, 0x41, 0x84, 0x6f, 0x13, 0xe6, 0x26, 0xfa, 0x36, 0x46, 0x73, 0xbc, 0xba, 0x3b, 0xd6, 0xca, 0x8, 0xd0, 0xd6, 0x36, 0x4e, 0x35, 0xeb, 0xad, 0xd7, 0xb0, 0x60, 0x72, 0xdc, 0xda, 0x9c, 0x2, 0x67, 0x76, 0x64, 0x82, 0x99, 0x9b, 0xb6, 0x80, 0xb0, 0x7e, 0x8d, 0xf6, 0x5a, 0xdd, 0xe1, 0xb5, 0xba, 0xba, 0xb1, 0x0, 0xcd, 0xc7, 0x50, 0x23, 0xeb, 0xfb, 0x7f, 0xb4, 0xc8, 0x22, 0x18, 0xdd, 0x0, 0xd5, 0xec, 0x4e, 0x53, 0xc6, 0x18, 0x44, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char option_button_disabled_mirrored_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x2f, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2d, 0x34, 0x2b, 0x2b, 0x31, 0x5a, 0x5a, 0x5a, 0x3e, 0x3e, 0x3e, 0x2a, 0x2a, 0x30, 0x59, 0x59, 0x59, 0x22, 0x22, 0x27, 0x4b, 0x4b, 0x4b, 0x22, 0x22, 0x29, 0x24, 0x24, 0x28, 0x4a, 0x4a, 0x4a, 0x36, 0x36, 0x36, 0x2a, 0x2a, 0x30, 0x2c, 0x2c, 0x32, 0x2d, 0x2d, 0x34, 0x2e, 0x2e, 0x35, 0x2f, 0x2f, 0x36, 0x2a, 0x2a, 0x31, 0x62, 0x62, 0x62, 0x56, 0x56, 0x56, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2b, 0x27, 0x27, 0x2d, 0x28, 0x28, 0x2e, 0x29, 0x29, 0x2f, 0x24, 0x24, 0x28, 0x26, 0x26, 0x2b, 0x54, 0x54, 0x54, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x48, 0x48, 0x48, 0x22, 0x22, 0x26, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x26, 0x26, 0x2c, 0x22, 0x22, 0x27, 0x2d, 0x2d, 0x33, 0x52, 0x52, 0x52, 0x42, 0x42, 0x42, 0x27, 0x27, 0x2b, 0x29, 0x29, 0x2e, 0x2c, 0x2c, 0x31, 0x2e, 0x2e, 0x34, 0x51, 0x51, 0x51, 0x40, 0x40, 0x40, 0x4f, 0x4f, 0x4f, 0x3f, 0x3f, 0x3f, 0x20, 0x20, 0x25, 0x24, 0x24, 0x29, 0x24, 0x24, 0x2a, 0x4d, 0x4d, 0x4d, 0x3e, 0x3e, 0x3e, 0x20, 0x20, 0x23, 0x29, 0x29, 0x2d, 0x2b, 0x2b, 0x30, 0x28, 0x28, 0x2d, 0x4c, 0x4c, 0x4c, 0x3d, 0x3d, 0x3d, 0x1e, 0x1e, 0x22, 0x27, 0x27, 0x2c, 0x22, 0x22, 0x28, 0x4a, 0x4a, 0x4a, 0x3b, 0x3b, 0x3b, 0x1d, 0x1d, 0x21, 0x20, 0x20, 0x24, 0x23, 0x23, 0x27, 0x21, 0x21, 0x25, 0x21, 0x21, 0x26, 0x3a, 0x3a, 0x3a, 0x49, 0x49, 0x49, 0x1e, 0x1e, 0x21, 0x1f, 0x1f, 0x23, 0x1f, 0x1f, 0x24, 0x47, 0x47, 0x47, 0x39, 0x39, 0x39, 0x46, 0x46, 0x46, 0xda, 0x9d, 0x96, 0x5c, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2, 0x7, 0xd, 0x16, 0x1d, 0x22, 0x24, 0x1f, 0x19, 0x11, 0xa, 0x4, 0x1b, 0x2d, 0x3a, 0x43, 0x48, 0x47, 0x46, 0x3f, 0x34, 0x25, 0x15, 0x49, 0xe6, 0xef, 0x77, 0xe6, 0xef, 0xe7, 0xef, 0x4a, 0xe4, 0xef, 0x77, 0x7e, 0xb9, 0x59, 0x66, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x1, 0xf, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x85, 0xd1, 0xd9, 0x52, 0xc2, 0x30, 0x14, 0x80, 0xe1, 0x2a, 0x5a, 0x56, 0x97, 0xb2, 0xb9, 0xef, 0x50, 0x45, 0x4b, 0x6d, 0xe, 0x95, 0xa6, 0xa5, 0x40, 0xab, 0x15, 0x5, 0xdc, 0xc0, 0x8a, 0xa, 0xb8, 0xa1, 0xef, 0xff, 0xc, 0x86, 0x90, 0x30, 0xc, 0x17, 0xfa, 0x5d, 0x26, 0xff, 0x4c, 0x4e, 0x12, 0x41, 0x98, 0x32, 0x33, 0x1b, 0x98, 0x9b, 0x17, 0x83, 0x84, 0x18, 0xa, 0x47, 0xa2, 0xb1, 0xe9, 0x7d, 0x21, 0x16, 0x58, 0x58, 0x5c, 0x5a, 0x96, 0x24, 0x29, 0x9e, 0x48, 0xa6, 0xd2, 0x2b, 0x51, 0xb2, 0xb4, 0xba, 0x96, 0xc9, 0xca, 0x87, 0x47, 0x8c, 0x9c, 0xc9, 0x1d, 0x9f, 0x30, 0xeb, 0x1b, 0xe9, 0x8, 0x9, 0x36, 0x15, 0x25, 0xaf, 0x9e, 0x6a, 0x8c, 0x8a, 0xa0, 0xa0, 0x8f, 0x9c, 0x15, 0xb7, 0x52, 0x61, 0x12, 0xa8, 0x6, 0x56, 0x4d, 0x2b, 0xcb, 0x98, 0xb8, 0xc4, 0x3, 0x5d, 0x2f, 0x24, 0x43, 0xc3, 0xc0, 0x6, 0xcd, 0x2a, 0xcb, 0x4c, 0xe, 0x4a, 0x95, 0x2a, 0x57, 0x49, 0x88, 0x24, 0x70, 0xc, 0x70, 0xcf, 0xcb, 0x17, 0x8c, 0x5, 0x8e, 0x77, 0xc9, 0x79, 0xf1, 0x20, 0x9, 0x80, 0x4, 0xd6, 0x64, 0x50, 0xbb, 0xe2, 0x6a, 0xd2, 0x30, 0xc0, 0xd7, 0xf5, 0x89, 0x19, 0xb4, 0x46, 0xbe, 0x79, 0xc3, 0x35, 0x69, 0x80, 0x6e, 0x15, 0xb8, 0x33, 0xef, 0x99, 0x7, 0x84, 0x5a, 0x6d, 0xae, 0x45, 0x8f, 0xb0, 0x1f, 0xed, 0x86, 0x3f, 0xbe, 0xa6, 0x6f, 0x3f, 0x75, 0x9e, 0xb9, 0xe, 0x1d, 0xd2, 0x78, 0x79, 0xed, 0x62, 0xf0, 0x19, 0xdc, 0xeb, 0x17, 0xdf, 0xb8, 0x77, 0x7a, 0xcd, 0xed, 0x8f, 0xcf, 0x5e, 0xb7, 0x8e, 0x19, 0xe5, 0xab, 0x3f, 0xf8, 0x66, 0xda, 0x3b, 0xf4, 0xa1, 0x76, 0xf7, 0x90, 0xe3, 0x8e, 0x67, 0x70, 0x1, 0xbc, 0x9f, 0x91, 0xc1, 0xfe, 0x1, 0x7d, 0xea, 0x7f, 0x3f, 0xeb, 0xef, 0xef, 0xfe, 0x5, 0xd6, 0xe3, 0x56, 0x89, 0xd8, 0x62, 0xb6, 0x83, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char option_button_hover_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x5f, 0x5a, 0x6b, 0x2a, 0x2a, 0x30, 0x56, 0x53, 0x64, 0x22, 0x22, 0x27, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x67, 0x63, 0x76, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5a, 0x56, 0x65, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x5b, 0x57, 0x66, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x43, 0x40, 0x4c, 0x54, 0x50, 0x5f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x4f, 0x5f, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x5f, 0x5a, 0x6c, 0xd3, 0x26, 0x54, 0x35, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe5, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x85, 0x91, 0x43, 0x62, 0xc5, 0x60, 0x18, 0x45, 0xef, 0x8d, 0x51, 0xdb, 0xee, 0x46, 0xca, 0x6d, 0x77, 0x58, 0xce, 0x6b, 0xdb, 0x7c, 0x8a, 0xad, 0xea, 0x44, 0x1f, 0x4e, 0x92, 0x1f, 0x4c, 0x0, 0xe0, 0x9, 0x61, 0xf0, 0x89, 0x32, 0x12, 0xcd, 0xd4, 0x8, 0xef, 0x1f, 0x35, 0x54, 0xa0, 0x68, 0x1a, 0x34, 0x89, 0x8, 0x86, 0xa4, 0xd, 0x57, 0xb4, 0xdf, 0x79, 0x5, 0x89, 0x94, 0xba, 0xf9, 0xb3, 0xc0, 0xce, 0xeb, 0xf0, 0x17, 0x1c, 0xab, 0x11, 0x9, 0x1a, 0xf9, 0x96, 0x84, 0x5d, 0x5e, 0x43, 0x15, 0x7, 0x2e, 0x42, 0x41, 0x51, 0xd3, 0xbe, 0x67, 0xd5, 0x6b, 0x42, 0x3a, 0x38, 0x9b, 0xf5, 0x2e, 0x20, 0xfa, 0x5, 0x33, 0x41, 0x69, 0xf4, 0xeb, 0x49, 0x6c, 0x19, 0xe6, 0xbd, 0xdd, 0xd, 0x48, 0xa0, 0x92, 0xb, 0x36, 0x72, 0x6a, 0x26, 0xf0, 0x14, 0xa, 0x10, 0x72, 0xe1, 0x7d, 0xf4, 0xf6, 0x35, 0x1b, 0xc3, 0xe3, 0x18, 0x9d, 0x50, 0xf0, 0xe4, 0xc2, 0x17, 0xae, 0x27, 0xd3, 0xe4, 0x6e, 0xe8, 0xf8, 0x7e, 0xbc, 0x1, 0x48, 0x9e, 0x57, 0xf8, 0xc5, 0xfc, 0xbd, 0x7a, 0x98, 0xc4, 0x94, 0x47, 0xbf, 0xe4, 0xce, 0x48, 0x8, 0x6e, 0x69, 0x91, 0x63, 0x47, 0x73, 0x49, 0xbc, 0x77, 0x3e, 0xd7, 0x4b, 0x3b, 0x12, 0x36, 0x16, 0xb3, 0x85, 0x6a, 0x68, 0xce, 0x39, 0x62, 0xc6, 0xba, 0x3d, 0x8d, 0xe7, 0x91, 0x20, 0xac, 0xad, 0xa6, 0xc2, 0xe, 0x6, 0xcc, 0x74, 0xc, 0x2d, 0xe7, 0xf9, 0x55, 0x2, 0x28, 0x94, 0x37, 0xab, 0xee, 0xa1, 0xcc, 0xbf, 0xdb, 0xed, 0x3, 0x70, 0xe6, 0x4f, 0x4a, 0xc3, 0xed, 0xed, 0xf3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char option_button_hover_mirrored_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2d, 0x34, 0x2b, 0x2b, 0x31, 0x5f, 0x5a, 0x6c, 0x42, 0x40, 0x4b, 0x2a, 0x2a, 0x30, 0x5f, 0x5a, 0x6b, 0x22, 0x22, 0x27, 0x56, 0x53, 0x64, 0x22, 0x22, 0x29, 0x24, 0x24, 0x28, 0x57, 0x53, 0x63, 0x3e, 0x3c, 0x47, 0x2a, 0x2a, 0x30, 0x2c, 0x2c, 0x32, 0x2d, 0x2d, 0x34, 0x2e, 0x2e, 0x35, 0x2f, 0x2f, 0x36, 0x2a, 0x2a, 0x31, 0x67, 0x63, 0x76, 0x5a, 0x56, 0x67, 0x5b, 0x57, 0x68, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2b, 0x27, 0x27, 0x2d, 0x28, 0x28, 0x2e, 0x29, 0x29, 0x2f, 0x24, 0x24, 0x28, 0x26, 0x26, 0x2b, 0x5a, 0x56, 0x65, 0x48, 0x45, 0x51, 0x49, 0x46, 0x52, 0x4d, 0x4a, 0x57, 0x22, 0x22, 0x26, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x26, 0x26, 0x2c, 0x5b, 0x57, 0x66, 0x22, 0x22, 0x27, 0x2d, 0x2d, 0x33, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x27, 0x27, 0x2b, 0x29, 0x29, 0x2e, 0x2c, 0x2c, 0x31, 0x2e, 0x2e, 0x34, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x20, 0x20, 0x25, 0x24, 0x24, 0x29, 0x24, 0x24, 0x2a, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x20, 0x20, 0x23, 0x29, 0x29, 0x2d, 0x2b, 0x2b, 0x30, 0x28, 0x28, 0x2d, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x1e, 0x1e, 0x22, 0x27, 0x27, 0x2c, 0x22, 0x22, 0x28, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x1d, 0x1d, 0x21, 0x20, 0x20, 0x24, 0x23, 0x23, 0x27, 0x21, 0x21, 0x25, 0x21, 0x21, 0x26, 0x54, 0x50, 0x5f, 0x43, 0x40, 0x4c, 0x1e, 0x1e, 0x21, 0x1f, 0x1f, 0x23, 0x1f, 0x1f, 0x24, 0x53, 0x4f, 0x5f, 0x42, 0x3f, 0x4c, 0x43, 0x3f, 0x4d, 0x47, 0x43, 0x51, 0x5f, 0x5a, 0x6c, 0x53, 0x4f, 0x5e, 0x53, 0x50, 0x5f, 0x68, 0x6, 0xa3, 0x65, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2, 0x7, 0xd, 0x16, 0x1d, 0x22, 0x24, 0x1f, 0x19, 0x11, 0xa, 0x4, 0x1b, 0x2d, 0x3a, 0x43, 0x48, 0x47, 0x46, 0x3f, 0x34, 0x25, 0x15, 0x49, 0xe6, 0xef, 0x77, 0xe6, 0xef, 0xe7, 0xef, 0x4a, 0xe4, 0xef, 0x77, 0x7e, 0xb9, 0x59, 0x66, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x1, 0x15, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x85, 0xd1, 0xd9, 0x52, 0xc2, 0x30, 0x14, 0x80, 0xe1, 0x2a, 0x5a, 0x56, 0x97, 0xb2, 0xb9, 0x8b, 0xb, 0x54, 0x51, 0x4b, 0x6d, 0x8f, 0x60, 0xd3, 0x62, 0xc1, 0x56, 0x11, 0x5, 0xdc, 0xd0, 0x5a, 0x14, 0x70, 0x5f, 0xdf, 0xff, 0x1, 0xc, 0x69, 0xc2, 0x30, 0x5c, 0xe8, 0x77, 0x99, 0xfc, 0x33, 0x39, 0x49, 0x38, 0x6e, 0xc8, 0xc8, 0xa8, 0x6f, 0x6c, 0x9c, 0xf7, 0x63, 0x7c, 0x20, 0x18, 0xa, 0x47, 0x86, 0xf7, 0xb9, 0x88, 0x6f, 0x62, 0x72, 0x6a, 0x5a, 0x10, 0x84, 0x68, 0x2c, 0x9e, 0x48, 0xce, 0x84, 0xf1, 0xd2, 0xec, 0x5c, 0x3a, 0x23, 0x6e, 0x6c, 0x52, 0x62, 0x3a, 0xbb, 0xb5, 0xed, 0xd9, 0x99, 0x5f, 0x48, 0x86, 0x70, 0xb0, 0x28, 0x49, 0x39, 0x79, 0x57, 0xa1, 0x64, 0x15, 0xf6, 0xf2, 0x9e, 0xc2, 0xfe, 0x52, 0x22, 0x88, 0x3, 0x59, 0x43, 0xb2, 0x6e, 0x64, 0x28, 0x1d, 0x15, 0x59, 0x90, 0x2f, 0x1c, 0xc4, 0x3, 0xbd, 0xc0, 0x4, 0xc5, 0x28, 0x89, 0x54, 0x16, 0x8a, 0xe5, 0x43, 0xa6, 0x1c, 0xe3, 0x71, 0x60, 0x69, 0x60, 0x1f, 0x95, 0x8e, 0x29, 0x3, 0xac, 0xca, 0x9, 0x53, 0x89, 0xfa, 0x71, 0x0, 0x38, 0x30, 0x6, 0x83, 0xea, 0x29, 0x53, 0x15, 0x7a, 0x1, 0x3a, 0xab, 0xd, 0xcc, 0xa0, 0xd4, 0x73, 0x8d, 0x73, 0xa6, 0x41, 0x2, 0xf5, 0x42, 0x82, 0x4b, 0xfd, 0x8a, 0xba, 0x56, 0xd5, 0xe6, 0xd, 0xd3, 0x24, 0x47, 0x98, 0xb7, 0x66, 0xdd, 0xe9, 0x5f, 0xd3, 0x31, 0xef, 0xdc, 0x16, 0xe3, 0x92, 0x21, 0xb5, 0xfb, 0x87, 0x36, 0x2, 0x87, 0x42, 0x9d, 0xee, 0xe3, 0x13, 0xd5, 0x72, 0xc9, 0x35, 0x97, 0x9f, 0x5f, 0x3a, 0xed, 0x1a, 0xa2, 0xa4, 0xd7, 0xee, 0xdb, 0xbb, 0xe7, 0xe3, 0x33, 0x45, 0x1e, 0x6a, 0x65, 0x55, 0xb5, 0xec, 0xfe, 0xc, 0x36, 0xc0, 0xd7, 0xb7, 0xe7, 0x67, 0x6d, 0x9d, 0x3c, 0xf5, 0xbf, 0x9f, 0xf5, 0xf7, 0x77, 0xff, 0x2, 0xa7, 0xc5, 0x58, 0xc8, 0x6e, 0x59, 0x8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char option_button_normal_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x56, 0x52, 0x60, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x52, 0x22, 0x22, 0x27, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x5d, 0x5a, 0x6a, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x46, 0x42, 0x4f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x4e, 0x4b, 0x58, 0x8, 0xd9, 0x10, 0xcb, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe6, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xd1, 0x55, 0x5a, 0xc4, 0x30, 0x14, 0x5, 0xe0, 0x73, 0xea, 0x82, 0xbb, 0x3b, 0x6c, 0x80, 0x45, 0xb0, 0x70, 0x5e, 0xb1, 0x37, 0xdc, 0x75, 0xdc, 0x3d, 0x43, 0x2a, 0x5f, 0x3a, 0x7e, 0x6a, 0xc9, 0xbd, 0x7f, 0x9d, 0x2a, 0x0, 0xa4, 0x16, 0xd, 0xaa, 0x18, 0x8e, 0x41, 0x3f, 0x11, 0xd1, 0xbe, 0x52, 0xc7, 0x48, 0xa8, 0xfb, 0x5e, 0x68, 0xd4, 0x24, 0x96, 0x6a, 0xfc, 0xaf, 0x8b, 0x32, 0xbf, 0x61, 0x90, 0xc6, 0x3c, 0x27, 0x3, 0xce, 0xfe, 0x20, 0x2, 0x4b, 0xd2, 0x45, 0x1f, 0x14, 0xd5, 0x78, 0x5e, 0x36, 0x1c, 0x7d, 0xe5, 0x33, 0x2, 0xb3, 0x84, 0x8a, 0xec, 0xd4, 0xeb, 0x9a, 0x1a, 0x1b, 0x82, 0xf5, 0x79, 0x20, 0x2, 0x46, 0x1f, 0x58, 0x8d, 0x95, 0xe4, 0x6a, 0x1d, 0xcf, 0x4f, 0x89, 0x85, 0x10, 0x80, 0x56, 0x1f, 0x8, 0xf4, 0x53, 0xf7, 0x81, 0x6c, 0x4, 0xa0, 0xf5, 0x41, 0x69, 0xeb, 0xb7, 0xd0, 0x7b, 0x86, 0xcc, 0x36, 0xbb, 0x11, 0x90, 0x66, 0x1f, 0x88, 0xef, 0xbd, 0x64, 0x92, 0x5a, 0x7b, 0x4e, 0xed, 0x34, 0x42, 0x20, 0xa5, 0xd5, 0x7, 0x27, 0x69, 0xfb, 0x51, 0x8d, 0x69, 0x6e, 0xd5, 0xcc, 0xb9, 0x18, 0xf4, 0xaf, 0x40, 0x6e, 0x3f, 0x1d, 0xab, 0xf1, 0xdd, 0xc7, 0xf1, 0x12, 0x45, 0xc, 0xce, 0x4f, 0x17, 0x12, 0xd0, 0xb6, 0xc4, 0x87, 0x1a, 0x6f, 0x2f, 0x48, 0x8b, 0xef, 0x31, 0xd0, 0x6e, 0xce, 0xa8, 0xc0, 0x25, 0x56, 0x7d, 0x5, 0x52, 0xed, 0x6e, 0xae, 0x68, 0x0, 0xd4, 0x86, 0x7f, 0x56, 0x43, 0x62, 0x38, 0xc, 0x46, 0x28, 0xba, 0x1, 0x7a, 0xad, 0x4f, 0x59, 0x90, 0xab, 0xbf, 0xa4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char option_button_normal_mirrored_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2d, 0x34, 0x2b, 0x2b, 0x31, 0x56, 0x53, 0x61, 0x3c, 0x3a, 0x45, 0x2a, 0x2a, 0x30, 0x56, 0x52, 0x60, 0x22, 0x22, 0x27, 0x47, 0x44, 0x52, 0x22, 0x22, 0x29, 0x24, 0x24, 0x28, 0x47, 0x44, 0x50, 0x33, 0x31, 0x3a, 0x2a, 0x2a, 0x30, 0x2c, 0x2c, 0x32, 0x2d, 0x2d, 0x34, 0x2e, 0x2e, 0x35, 0x2f, 0x2f, 0x36, 0x2a, 0x2a, 0x31, 0x5d, 0x5a, 0x6a, 0x51, 0x4f, 0x5d, 0x52, 0x50, 0x5d, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2b, 0x27, 0x27, 0x2d, 0x28, 0x28, 0x2e, 0x29, 0x29, 0x2f, 0x24, 0x24, 0x28, 0x26, 0x26, 0x2b, 0x51, 0x4e, 0x5b, 0x41, 0x3e, 0x49, 0x42, 0x3e, 0x4a, 0x46, 0x42, 0x4e, 0x22, 0x22, 0x26, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x26, 0x26, 0x2c, 0x50, 0x4e, 0x5a, 0x40, 0x3e, 0x48, 0x22, 0x22, 0x27, 0x2d, 0x2d, 0x33, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x27, 0x27, 0x2b, 0x29, 0x29, 0x2e, 0x2c, 0x2c, 0x31, 0x2e, 0x2e, 0x34, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x20, 0x20, 0x25, 0x24, 0x24, 0x29, 0x24, 0x24, 0x2a, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x20, 0x20, 0x23, 0x29, 0x29, 0x2d, 0x2b, 0x2b, 0x30, 0x28, 0x28, 0x2d, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x1e, 0x1e, 0x22, 0x27, 0x27, 0x2c, 0x22, 0x22, 0x28, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x1d, 0x1d, 0x21, 0x20, 0x20, 0x24, 0x23, 0x23, 0x27, 0x21, 0x21, 0x25, 0x21, 0x21, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x47, 0x43, 0x50, 0x1e, 0x1e, 0x21, 0x1f, 0x1f, 0x23, 0x1f, 0x1f, 0x24, 0x44, 0x41, 0x4e, 0x36, 0x34, 0x3e, 0x4e, 0x4b, 0x58, 0x44, 0x41, 0x4c, 0x44, 0x42, 0x4d, 0x7d, 0x2e, 0xcf, 0xc5, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2, 0x7, 0xd, 0x16, 0x1d, 0x22, 0x24, 0x1f, 0x19, 0x11, 0xa, 0x4, 0x1b, 0x2d, 0x3a, 0x43, 0x48, 0x47, 0x46, 0x3f, 0x34, 0x25, 0x15, 0x49, 0xe6, 0xef, 0x77, 0xe6, 0xef, 0xe7, 0xef, 0x4a, 0xe4, 0xef, 0x77, 0x7e, 0xb9, 0x59, 0x66, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x1, 0x13, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x85, 0xd1, 0xd9, 0x52, 0xc2, 0x30, 0x14, 0x80, 0xe1, 0x2a, 0x5a, 0x56, 0x97, 0xb2, 0xb9, 0x8b, 0xb, 0x54, 0x51, 0x4b, 0x6d, 0xf, 0x68, 0xd3, 0xa2, 0x5, 0x5b, 0x40, 0x14, 0x70, 0x3, 0x2b, 0x2a, 0xe0, 0xbe, 0xbd, 0xff, 0x3, 0x18, 0xd2, 0x84, 0x61, 0xb8, 0xd0, 0xef, 0x32, 0xf9, 0x67, 0x72, 0x92, 0x70, 0xdc, 0x88, 0xb1, 0x71, 0xcf, 0xc4, 0x24, 0xef, 0xc5, 0x78, 0x9f, 0x3f, 0x10, 0xc, 0x8d, 0xee, 0x73, 0x21, 0xcf, 0xd4, 0xf4, 0xcc, 0xac, 0x20, 0x8, 0xe1, 0x48, 0x34, 0x16, 0x9f, 0xb, 0xe2, 0xa5, 0xf9, 0x85, 0x64, 0x4a, 0xdc, 0xda, 0xa6, 0xc4, 0x64, 0x7a, 0x67, 0xd7, 0xb5, 0xb7, 0xb8, 0x14, 0xf, 0xe0, 0x60, 0x59, 0x92, 0x32, 0xf2, 0xbe, 0x42, 0xc9, 0x2a, 0x64, 0x73, 0xae, 0x83, 0xc3, 0x95, 0x98, 0x1f, 0x7, 0xb2, 0x86, 0x64, 0xdd, 0x48, 0x51, 0x3a, 0xca, 0x1f, 0x1d, 0x53, 0xb9, 0x6c, 0xd4, 0xd7, 0xf, 0x4c, 0x50, 0x8c, 0x82, 0x48, 0xa5, 0x21, 0x5f, 0x3c, 0x61, 0x8a, 0x11, 0x1e, 0x7, 0x96, 0x6, 0x76, 0xa9, 0x50, 0xa6, 0xc, 0xb0, 0x2a, 0xa7, 0x4c, 0x25, 0xec, 0xc5, 0x1, 0xe0, 0xc0, 0x18, 0xe, 0xaa, 0x67, 0x4c, 0x55, 0xe8, 0x7, 0xe8, 0xbc, 0x36, 0x34, 0x83, 0x52, 0xcf, 0x34, 0x2e, 0x98, 0x6, 0x9, 0xd4, 0x4b, 0x9, 0xae, 0xf4, 0x6b, 0xea, 0x46, 0x55, 0x9b, 0x2d, 0xa6, 0x49, 0x8e, 0x30, 0x6f, 0xcd, 0xba, 0x33, 0xb8, 0xa6, 0x63, 0xde, 0xb5, 0xef, 0x99, 0x36, 0x19, 0x52, 0x7b, 0x78, 0xec, 0x20, 0x70, 0x28, 0xd4, 0xed, 0x3d, 0x3d, 0x33, 0x2f, 0xe4, 0x9a, 0xab, 0xaf, 0x6f, 0xdd, 0x4e, 0xd, 0x51, 0xd2, 0x7b, 0xef, 0xe3, 0x93, 0x6a, 0x25, 0xc8, 0x43, 0xad, 0xad, 0xab, 0x96, 0x3d, 0x98, 0xc1, 0x6, 0xf8, 0xfa, 0x76, 0xfd, 0x6c, 0x6c, 0x92, 0xa7, 0xfe, 0xf7, 0xb3, 0xfe, 0xfe, 0xee, 0x5f, 0xa1, 0x5f, 0x59, 0xbd, 0x75, 0x41, 0x2b, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char option_button_pressed_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x4a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x2f, 0x37, 0x46, 0x43, 0x4f, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x44, 0x50, 0x2a, 0x2a, 0x30, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x27, 0x3d, 0x3a, 0x45, 0x56, 0x52, 0x60, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x43, 0x40, 0x4c, 0x42, 0x40, 0x4b, 0x4c, 0x49, 0x56, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x3a, 0x38, 0x41, 0x36, 0x34, 0x3d, 0x44, 0x41, 0x4c, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x44, 0x42, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x50, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x3f, 0x3d, 0x47, 0x4f, 0x4c, 0x59, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x45, 0x42, 0x4d, 0x41, 0x3e, 0x49, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x52, 0x4e, 0x5c, 0x51, 0x4e, 0x5b, 0x5d, 0x59, 0x69, 0x10, 0x9d, 0xe0, 0x3c, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe6, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xcf, 0x3, 0x62, 0x4, 0x51, 0x10, 0x4, 0xd0, 0xaa, 0x31, 0x62, 0xdb, 0xb8, 0x49, 0x2e, 0x9e, 0x3b, 0xc4, 0xb6, 0x9d, 0xc5, 0x58, 0x1f, 0xc1, 0xd6, 0xe8, 0x77, 0xf7, 0x1b, 0x59, 0x6c, 0x2, 0x20, 0x37, 0xaa, 0xc5, 0x17, 0x7e, 0xc7, 0x62, 0x28, 0x45, 0x75, 0xfe, 0x6c, 0xe1, 0x4f, 0x68, 0x86, 0x41, 0x69, 0x44, 0x51, 0x4b, 0xb1, 0xce, 0xcc, 0xe4, 0x83, 0xd7, 0xb0, 0x48, 0x6b, 0x98, 0xe8, 0x9, 0x38, 0x70, 0x8b, 0xa, 0xcc, 0x12, 0x1a, 0xf0, 0x4d, 0xac, 0x87, 0xf3, 0x96, 0x6f, 0x8e, 0x5f, 0x56, 0xc0, 0x53, 0x20, 0x8f, 0xbf, 0xdb, 0x86, 0x58, 0x5b, 0x9, 0xbf, 0x47, 0x80, 0xa, 0x58, 0x1a, 0x38, 0xad, 0x9, 0x5f, 0xac, 0xe3, 0x20, 0xbc, 0x4b, 0x46, 0x4b, 0x0, 0x3a, 0x1a, 0x24, 0xd0, 0x69, 0x85, 0xc0, 0x63, 0x5, 0x60, 0x68, 0xf0, 0x36, 0x7f, 0xf3, 0xaa, 0xbe, 0xe1, 0x61, 0x81, 0x69, 0x5, 0x72, 0x5b, 0x83, 0xe4, 0x6a, 0x59, 0x16, 0xf7, 0x53, 0x47, 0x77, 0x8b, 0xad, 0x12, 0xe4, 0xb9, 0xa3, 0xc1, 0xe6, 0x83, 0x7b, 0x20, 0xd6, 0xb4, 0xe7, 0xbf, 0xed, 0xe1, 0x1a, 0xd8, 0xfa, 0xdf, 0xb9, 0x70, 0xb8, 0x21, 0xd6, 0xbb, 0x17, 0x1b, 0xe3, 0x4c, 0x6a, 0xb0, 0xbd, 0x25, 0x5, 0x3b, 0x5e, 0x7c, 0x21, 0xc0, 0xc2, 0x68, 0xee, 0xf1, 0xbc, 0x6, 0x46, 0xb1, 0xbd, 0x5e, 0x30, 0x5, 0x27, 0x19, 0x24, 0xb8, 0x61, 0x6e, 0xf8, 0xf5, 0xf7, 0xcd, 0x47, 0x16, 0xa0, 0x18, 0x13, 0x6a, 0x64, 0x7d, 0xff, 0x8f, 0x1e, 0x59, 0x84, 0xa2, 0x1b, 0x0, 0xe5, 0xe0, 0x4e, 0x46, 0x1d, 0x98, 0x92, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char option_button_pressed_mirrored_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x4a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2d, 0x34, 0x2b, 0x2b, 0x31, 0x46, 0x43, 0x4f, 0x31, 0x2f, 0x38, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x50, 0x22, 0x22, 0x27, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x29, 0x24, 0x24, 0x28, 0x56, 0x52, 0x60, 0x3c, 0x3a, 0x45, 0x2a, 0x2a, 0x30, 0x2c, 0x2c, 0x32, 0x2d, 0x2d, 0x34, 0x2e, 0x2e, 0x35, 0x2f, 0x2f, 0x36, 0x2a, 0x2a, 0x31, 0x4c, 0x49, 0x56, 0x42, 0x40, 0x4b, 0x43, 0x40, 0x4c, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2b, 0x27, 0x27, 0x2d, 0x28, 0x28, 0x2e, 0x29, 0x29, 0x2f, 0x24, 0x24, 0x28, 0x26, 0x26, 0x2b, 0x44, 0x41, 0x4c, 0x36, 0x34, 0x3d, 0x3a, 0x38, 0x41, 0x22, 0x22, 0x26, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x26, 0x26, 0x2c, 0x44, 0x41, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4e, 0x22, 0x22, 0x27, 0x2d, 0x2d, 0x33, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x27, 0x27, 0x2b, 0x29, 0x29, 0x2e, 0x2c, 0x2c, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x20, 0x20, 0x25, 0x24, 0x24, 0x29, 0x24, 0x24, 0x2a, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x20, 0x20, 0x23, 0x29, 0x29, 0x2d, 0x2b, 0x2b, 0x30, 0x28, 0x28, 0x2d, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x1e, 0x1e, 0x22, 0x27, 0x27, 0x2c, 0x22, 0x22, 0x28, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x1d, 0x1d, 0x21, 0x20, 0x20, 0x24, 0x23, 0x23, 0x27, 0x21, 0x21, 0x25, 0x21, 0x21, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x3f, 0x3d, 0x48, 0x50, 0x4d, 0x5a, 0x1e, 0x1e, 0x21, 0x1f, 0x1f, 0x23, 0x1f, 0x1f, 0x24, 0x50, 0x4e, 0x5a, 0x40, 0x3e, 0x48, 0x41, 0x3e, 0x49, 0x45, 0x42, 0x4d, 0x5d, 0x59, 0x69, 0x51, 0x4e, 0x5b, 0x52, 0x4e, 0x5c, 0x49, 0x7e, 0x80, 0x9, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2, 0x7, 0xd, 0x16, 0x1d, 0x22, 0x24, 0x1f, 0x19, 0x11, 0xa, 0x4, 0x1b, 0x2d, 0x3a, 0x43, 0x48, 0x47, 0x46, 0x3f, 0x34, 0x25, 0x15, 0x49, 0xe6, 0xef, 0x77, 0xe6, 0xef, 0xe7, 0xef, 0x4a, 0xe4, 0xef, 0x77, 0x7e, 0xb9, 0x59, 0x66, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x1, 0x14, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x40, 0x3, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x40, 0xc0, 0xc6, 0xc1, 0xc9, 0xc5, 0xcd, 0x83, 0x2e, 0xcf, 0xc0, 0xc3, 0xcc, 0xcb, 0xc7, 0x2f, 0x20, 0x28, 0x28, 0x28, 0x24, 0x2c, 0x22, 0x2a, 0x26, 0xce, 0xd, 0x14, 0x92, 0x90, 0x54, 0x51, 0x55, 0x53, 0xd7, 0x80, 0x2, 0x35, 0x15, 0x4d, 0x2d, 0x6d, 0x8, 0xd0, 0x91, 0x92, 0x16, 0xe3, 0x2, 0x2a, 0x90, 0xd1, 0xd5, 0xd5, 0xd3, 0x37, 0x30, 0x84, 0x2, 0x7d, 0x23, 0x63, 0x13, 0x53, 0x28, 0x30, 0x93, 0x15, 0xe5, 0x4, 0x2a, 0xd0, 0x37, 0xb7, 0xd0, 0xb7, 0xb4, 0x52, 0x85, 0x2, 0x4b, 0xb, 0x6b, 0x1b, 0x5b, 0x18, 0xb0, 0x13, 0xe1, 0x0, 0x29, 0xb0, 0x37, 0x36, 0xb4, 0x72, 0x50, 0x83, 0x2, 0x4d, 0x63, 0x6b, 0x47, 0x27, 0x18, 0x70, 0x14, 0x66, 0x3, 0x2a, 0x70, 0x36, 0x37, 0x76, 0x71, 0x75, 0x70, 0x83, 0x2, 0x2b, 0x63, 0x67, 0x77, 0xf, 0x18, 0x70, 0x17, 0x62, 0x7, 0x2a, 0x30, 0x6, 0x2a, 0xb0, 0x42, 0x56, 0xe0, 0xe9, 0x5, 0x3, 0x9e, 0x82, 0x20, 0x5, 0x16, 0xde, 0x3e, 0x48, 0x6e, 0x30, 0xf4, 0xd5, 0xf3, 0xf3, 0x87, 0x1, 0x3f, 0xb0, 0x2, 0xa3, 0x0, 0x5d, 0xe3, 0x40, 0xcb, 0x20, 0x28, 0x8, 0x36, 0x32, 0xa, 0x9, 0x85, 0x81, 0x10, 0xb0, 0x15, 0xf6, 0x61, 0xf6, 0xbe, 0xe1, 0x70, 0x6f, 0x86, 0xdb, 0x47, 0x44, 0x46, 0xc1, 0x40, 0x24, 0xd8, 0x91, 0xe6, 0xd1, 0x31, 0xb1, 0x16, 0xc6, 0xe1, 0x50, 0x60, 0x11, 0x17, 0x9f, 0x90, 0x8, 0x5, 0x49, 0xc9, 0x60, 0x6f, 0xca, 0xa5, 0xa4, 0xc6, 0xc5, 0xfa, 0x58, 0x40, 0x81, 0x6e, 0x5a, 0x7c, 0x7a, 0x6, 0x4, 0x64, 0x66, 0xc9, 0x83, 0x3, 0x4a, 0x41, 0xd1, 0xc8, 0xd9, 0x5, 0xee, 0x6, 0x17, 0x63, 0xe3, 0xec, 0x1c, 0x8, 0xc8, 0x55, 0x52, 0x6, 0x7, 0x35, 0xc1, 0xc8, 0xc2, 0x1f, 0xdd, 0x0, 0xa5, 0xe, 0x59, 0xe5, 0x7f, 0xe9, 0xa4, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char overbright_indicator_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x1, 0x85, 0x69, 0x43, 0x43, 0x50, 0x49, 0x43, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x0, 0x0, 0x78, 0x9c, 0x7d, 0x91, 0x3d, 0x48, 0xc3, 0x40, 0x1c, 0xc5, 0x5f, 0x53, 0xa5, 0x2a, 0x2d, 0xe, 0x16, 0x11, 0x75, 0xc8, 0x50, 0x9d, 0x2c, 0x8a, 0x8a, 0x38, 0x6a, 0x15, 0x8a, 0x50, 0x21, 0xd4, 0xa, 0xad, 0x3a, 0x98, 0x5c, 0xfa, 0x21, 0x34, 0x69, 0x48, 0x52, 0x5c, 0x1c, 0x5, 0xd7, 0x82, 0x83, 0x1f, 0x8b, 0x55, 0x7, 0x17, 0x67, 0x5d, 0x1d, 0x5c, 0x5, 0x41, 0xf0, 0x3, 0xc4, 0xc5, 0xd5, 0x49, 0xd1, 0x45, 0x4a, 0xfc, 0x5f, 0x5a, 0x68, 0x11, 0xe3, 0xc1, 0x71, 0x3f, 0xde, 0xdd, 0x7b, 0xdc, 0xbd, 0x3, 0x84, 0x6a, 0x91, 0x69, 0x56, 0xdb, 0x18, 0xa0, 0xe9, 0xb6, 0x99, 0x8c, 0xc7, 0xc4, 0x74, 0x66, 0x45, 0xc, 0xbc, 0xa2, 0x13, 0x3, 0x8, 0xa1, 0x17, 0xa3, 0x32, 0xb3, 0x8c, 0x59, 0x49, 0x4a, 0xc0, 0x73, 0x7c, 0xdd, 0xc3, 0xc7, 0xd7, 0xbb, 0x28, 0xcf, 0xf2, 0x3e, 0xf7, 0xe7, 0x8, 0xa9, 0x59, 0x8b, 0x1, 0x3e, 0x91, 0x78, 0x86, 0x19, 0xa6, 0x4d, 0xbc, 0x4e, 0x3c, 0xb5, 0x69, 0x1b, 0x9c, 0xf7, 0x89, 0xc3, 0xac, 0x20, 0xab, 0xc4, 0xe7, 0xc4, 0x23, 0x26, 0x5d, 0x90, 0xf8, 0x91, 0xeb, 0x4a, 0x9d, 0xdf, 0x38, 0xe7, 0x5d, 0x16, 0x78, 0x66, 0xd8, 0x4c, 0x25, 0xe7, 0x88, 0xc3, 0xc4, 0x62, 0xbe, 0x85, 0x95, 0x16, 0x66, 0x5, 0x53, 0x23, 0x9e, 0x24, 0x8e, 0xa8, 0x9a, 0x4e, 0xf9, 0x42, 0xba, 0xce, 0x2a, 0xe7, 0x2d, 0xce, 0x5a, 0xb1, 0xcc, 0x1a, 0xf7, 0xe4, 0x2f, 0xc, 0x66, 0xf5, 0xe5, 0x25, 0xae, 0xd3, 0x1c, 0x44, 0x1c, 0xb, 0x58, 0x84, 0x4, 0x11, 0xa, 0xca, 0xd8, 0x40, 0x11, 0x36, 0xa2, 0xb4, 0xea, 0xa4, 0x58, 0x48, 0xd2, 0x7e, 0xcc, 0xc3, 0xdf, 0xef, 0xfa, 0x25, 0x72, 0x29, 0xe4, 0xda, 0x0, 0x23, 0xc7, 0x3c, 0x4a, 0xd0, 0x20, 0xbb, 0x7e, 0xf0, 0x3f, 0xf8, 0xdd, 0xad, 0x95, 0x9b, 0x18, 0xaf, 0x27, 0x5, 0x63, 0x40, 0xfb, 0x8b, 0xe3, 0x7c, 0xc, 0x1, 0x81, 0x5d, 0xa0, 0x56, 0x71, 0x9c, 0xef, 0x63, 0xc7, 0xa9, 0x9d, 0x0, 0xfe, 0x67, 0xe0, 0x4a, 0x6f, 0xfa, 0x4b, 0x55, 0x60, 0xfa, 0x93, 0xf4, 0x4a, 0x53, 0x8b, 0x1c, 0x1, 0xdd, 0xdb, 0xc0, 0xc5, 0x75, 0x53, 0x53, 0xf6, 0x80, 0xcb, 0x1d, 0xa0, 0xef, 0xc9, 0x90, 0x4d, 0xd9, 0x95, 0xfc, 0x34, 0x85, 0x5c, 0xe, 0x78, 0x3f, 0xa3, 0x6f, 0xca, 0x0, 0x3d, 0xb7, 0x40, 0xd7, 0x6a, 0xbd, 0xb7, 0xc6, 0x3e, 0x4e, 0x1f, 0x80, 0x14, 0x75, 0x95, 0xb8, 0x1, 0xe, 0xe, 0x81, 0xe1, 0x3c, 0x65, 0xaf, 0x79, 0xbc, 0xbb, 0xa3, 0xb5, 0xb7, 0x7f, 0xcf, 0x34, 0xfa, 0xfb, 0x1, 0x8e, 0x80, 0x72, 0xb2, 0xed, 0x78, 0xfa, 0x7b, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x15, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x63, 0x63, 0x66, 0x0, 0x0, 0x3, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4c, 0x39, 0x3a, 0xe, 0x0, 0x0, 0x0, 0x6, 0x74, 0x52, 0x4e, 0x53, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x80, 0x2c, 0x16, 0xc1, 0x6d, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6, 0x61, 0x66, 0xb8, 0x7d, 0x0, 0x0, 0x0, 0x32, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x0, 0x1, 0x46, 0x65, 0x17, 0x17, 0x30, 0x43, 0xc8, 0x4, 0x50, 0x88, 0x1c, 0x52, 0x1, 0x0, 0x2, 0x40, 0x14, 0xbb, 0x70, 0x8b, 0x40, 0xff, 0x2c, 0x18, 0xbe, 0xc6, 0xed, 0x8d, 0x42, 0xa1, 0x50, 0x28, 0x14, 0xa, 0x85, 0xbd, 0xb0, 0x13, 0xfc, 0x71, 0x1, 0xca, 0xf, 0x19, 0x62, 0x24, 0xd6, 0x8, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -306,6 +338,10 @@ static const unsigned char submenu_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, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x78, 0xc0, 0xf0, 0xe0, 0x3f, 0x8, 0xde, 0x4f, 0x60, 0x0, 0x3, 0xb8, 0xc0, 0x83, 0x2f, 0xf, 0xb5, 0xe1, 0x2, 0x50, 0x78, 0xf5, 0x5, 0x37, 0xaa, 0xc0, 0xff, 0x87, 0xf3, 0x31, 0x4, 0x30, 0xb5, 0x60, 0x1a, 0x8a, 0x61, 0x2d, 0x0, 0xa6, 0x55, 0x4f, 0xb1, 0x91, 0xd6, 0xa7, 0xae, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char submenu_mirrored_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, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x55, 0xcb, 0xa1, 0x11, 0x83, 0x40, 0x14, 0x45, 0xd1, 0xb3, 0x6b, 0x10, 0x34, 0x10, 0x47, 0x34, 0xf4, 0x13, 0x9d, 0x2, 0x28, 0x87, 0x2a, 0xe8, 0x84, 0x2, 0x82, 0x65, 0x71, 0x69, 0x0, 0x11, 0xf5, 0x11, 0x4c, 0x66, 0xd8, 0xe7, 0xee, 0x99, 0x79, 0x80, 0xed, 0x5d, 0xa2, 0x44, 0x9, 0x12, 0xec, 0x43, 0x2c, 0x5a, 0x78, 0xa6, 0xcc, 0xb7, 0x8d, 0xf9, 0x4a, 0xc8, 0xfc, 0x26, 0x3d, 0x37, 0xa8, 0x97, 0x69, 0x46, 0x6b, 0x5, 0x8f, 0x23, 0xbd, 0x1c, 0xd5, 0xa5, 0xfb, 0xc4, 0xf8, 0x87, 0x13, 0xd2, 0x2f, 0x14, 0x49, 0x6f, 0xb1, 0x11, 0xe1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char tab_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, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x19, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x2, 0xfe, 0x47, 0xfe, 0x17, 0x1, 0xc2, 0x48, 0xd2, 0x84, 0x10, 0x2, 0x84, 0xb9, 0x98, 0x0, 0x0, 0xbf, 0x67, 0x1d, 0x5, 0x89, 0x9b, 0x48, 0x90, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -346,6 +382,14 @@ 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, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0xfc, 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, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x2b, 0x26, 0x2c, 0x40, 0x40, 0x44, 0x4e, 0x4e, 0x52, 0x1a, 0x1a, 0x1d, 0x32, 0x32, 0x37, 0x2c, 0x26, 0x2c, 0x26, 0x25, 0x2a, 0x27, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x2f, 0x26, 0x2d, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x5b, 0x5b, 0x5f, 0x84, 0x84, 0x87, 0x77, 0x77, 0x7a, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x69, 0x69, 0x6c, 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, 0x71, 0xb, 0x1b, 0xbb, 0x0, 0x0, 0x0, 0x54, 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, 0xff, 0xff, 0x8, 0x17, 0x35, 0x86, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x7, 0x3a, 0xb4, 0xff, 0xff, 0xff, 0xb9, 0xff, 0xff, 0xff, 0xff, 0xb, 0x28, 0x8a, 0xff, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x37, 0xf, 0xff, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xd4, 0x6d, 0x6c, 0xf9, 0x0, 0x0, 0x2, 0x3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x55, 0x85, 0x9a, 0xe2, 0x30, 0x18, 0xbc, 0x7a, 0x8b, 0xbb, 0x7b, 0x2, 0xbb, 0x4d, 0x36, 0xb8, 0x3b, 0xeb, 0xae, 0xef, 0xff, 0x2e, 0x47, 0x48, 0x3f, 0xa0, 0x7a, 0xae, 0x83, 0x56, 0xfe, 0xe9, 0xfc, 0xfe, 0xe9, 0x6f, 0x2, 0xc7, 0xb, 0x82, 0xf8, 0x45, 0x8, 0x2, 0xcf, 0x39, 0x9a, 0xf3, 0xa2, 0x24, 0x2b, 0xaa, 0xe6, 0xfb, 0x2, 0x34, 0x55, 0x91, 0x25, 0x91, 0xb7, 0x3f, 0x5d, 0xf4, 0xab, 0x81, 0x60, 0x28, 0x1c, 0x89, 0xc6, 0x3c, 0x11, 0x8d, 0x84, 0x43, 0xc1, 0x80, 0xea, 0x17, 0x2d, 0x2a, 0xf8, 0x78, 0x22, 0x99, 0x4a, 0x67, 0xb2, 0xb9, 0x7c, 0xe1, 0xb, 0xc8, 0xe7, 0xb2, 0x99, 0x74, 0x2a, 0x99, 0x88, 0xf3, 0x26, 0xfb, 0x62, 0xa9, 0x5c, 0xa9, 0xd6, 0x0, 0x80, 0x10, 0xb2, 0xfb, 0x20, 0x5, 0x80, 0x75, 0xe8, 0x48, 0x52, 0xad, 0x94, 0x4b, 0xc5, 0x23, 0x6, 0xae, 0xa1, 0x9d, 0x9c, 0xd6, 0x80, 0x8e, 0xf0, 0x1e, 0x48, 0xdf, 0xb1, 0xd4, 0x81, 0x8b, 0x8e, 0xd3, 0x13, 0xad, 0xc1, 0x1d, 0xfc, 0x57, 0x82, 0x67, 0x35, 0x48, 0x30, 0x6a, 0xb6, 0x76, 0x97, 0x5b, 0x3a, 0x41, 0x98, 0xb4, 0x77, 0x4a, 0xdc, 0x3c, 0x39, 0xb, 0x2a, 0xfb, 0x38, 0xf0, 0x9d, 0x6e, 0xaf, 0x6, 0x11, 0xea, 0x1f, 0xdf, 0x41, 0x10, 0x6a, 0x7b, 0xc6, 0x62, 0xd0, 0xed, 0xf0, 0x6, 0x81, 0x58, 0xa, 0xd, 0x1, 0xa1, 0xa2, 0x8f, 0xa1, 0x23, 0xd2, 0xf2, 0x62, 0x18, 0x8e, 0x4a, 0x63, 0x26, 0x81, 0x93, 0x2, 0x13, 0xa0, 0xe3, 0xbe, 0xf5, 0xe, 0x82, 0x3d, 0x25, 0x14, 0x26, 0x1, 0x89, 0x11, 0xf0, 0x72, 0x70, 0xba, 0x15, 0x60, 0xbf, 0x3, 0x11, 0xe3, 0xcf, 0x6c, 0xbe, 0x58, 0xa2, 0x42, 0x7f, 0xb1, 0xc5, 0xee, 0x8b, 0x9d, 0x5f, 0xad, 0x37, 0xcc, 0x7, 0x41, 0x9, 0x65, 0x21, 0xbd, 0xd9, 0x8a, 0x3d, 0xe9, 0xf9, 0x7c, 0x46, 0x16, 0xb3, 0x3e, 0x35, 0xa4, 0x5f, 0x6, 0x2e, 0x46, 0x8a, 0xc0, 0x8, 0xd4, 0xcb, 0x2b, 0x88, 0x75, 0x3b, 0x81, 0x8e, 0xd, 0x1, 0xd4, 0x68, 0x8e, 0xfa, 0xe7, 0x94, 0xe0, 0x7c, 0x4f, 0x90, 0xbf, 0x56, 0x45, 0x46, 0x50, 0xba, 0xa9, 0x41, 0xec, 0x10, 0xb0, 0x96, 0x41, 0xd0, 0x3f, 0xdf, 0x7e, 0xe1, 0x79, 0xff, 0xfc, 0xfc, 0x9c, 0x6c, 0xbf, 0xf6, 0x14, 0xb7, 0x25, 0x83, 0x40, 0xd, 0xd7, 0x3c, 0x15, 0x90, 0x9d, 0x2, 0xec, 0xae, 0x40, 0x9, 0xdd, 0x1, 0xef, 0x18, 0xa0, 0x2, 0x59, 0xda, 0x5c, 0xd8, 0xc7, 0x80, 0x97, 0xd7, 0x5f, 0xc8, 0x42, 0x7f, 0x79, 0xbe, 0x9c, 0x17, 0x2c, 0x4, 0xfb, 0x2c, 0xd0, 0x3a, 0xb8, 0xff, 0x42, 0x1d, 0x10, 0x5a, 0x95, 0x33, 0x44, 0xd8, 0x97, 0x81, 0xfb, 0xa4, 0xc4, 0xed, 0x2b, 0xf1, 0x1, 0xfe, 0x40, 0x25, 0xd2, 0x5e, 0x18, 0x7c, 0x7b, 0x2f, 0x3c, 0xd2, 0x5e, 0xf8, 0x72, 0x37, 0x16, 0xbe, 0xdc, 0x8d, 0x6c, 0x1e, 0x3c, 0x3d, 0xd7, 0x40, 0xdb, 0x32, 0xf, 0xbc, 0xec, 0x9f, 0x5f, 0xf6, 0xf3, 0x80, 0x4d, 0x24, 0x2d, 0xf8, 0xfa, 0x6, 0xea, 0x80, 0xd, 0x24, 0x68, 0x0, 0x6c, 0x5f, 0x8e, 0xf6, 0xd5, 0xd7, 0xa0, 0x56, 0x34, 0xcf, 0xb4, 0x86, 0x92, 0xc, 0xa5, 0x33, 0x17, 0xf9, 0xc2, 0x17, 0x91, 0xbf, 0xc8, 0xa4, 0x43, 0x49, 0xa5, 0xc1, 0x5b, 0xa7, 0x72, 0x47, 0xd, 0xac, 0x47, 0xd7, 0xef, 0xb1, 0x2f, 0xe0, 0xfd, 0x7a, 0xb4, 0xe, 0xa8, 0x1d, 0x91, 0xb3, 0x6f, 0x95, 0xb1, 0xb4, 0xf9, 0x28, 0x7d, 0x79, 0x2f, 0x94, 0x3e, 0x36, 0xd2, 0x98, 0xe7, 0x5c, 0x36, 0x93, 0xf8, 0x15, 0xa0, 0x9b, 0xe9, 0xff, 0xc2, 0x67, 0x14, 0xf4, 0xa5, 0xb3, 0x35, 0x5e, 0x63, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char toggle_off_disabled_mirrored_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, 0x0, 0x9c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x1d, 0x1d, 0x21, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x2e, 0x2e, 0x2e, 0x46, 0x46, 0x46, 0x57, 0x57, 0x57, 0x60, 0x60, 0x60, 0x62, 0x62, 0x62, 0x5e, 0x5e, 0x5e, 0x4a, 0x4a, 0x4a, 0x12, 0x12, 0x15, 0x25, 0x27, 0x2d, 0x42, 0x42, 0x42, 0x59, 0x59, 0x59, 0x32, 0x32, 0x32, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x39, 0x39, 0x39, 0x49, 0x49, 0x49, 0x5a, 0x5a, 0x5a, 0x48, 0x48, 0x48, 0x54, 0x54, 0x54, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x1e, 0x1e, 0x22, 0x25, 0x26, 0x2b, 0x3f, 0x3f, 0x3f, 0xe, 0xe, 0x10, 0x2c, 0x2c, 0x2c, 0x58, 0x58, 0x58, 0x5d, 0x5d, 0x5f, 0x80, 0x80, 0x80, 0x79, 0x79, 0x79, 0x40, 0x40, 0x44, 0x32, 0x32, 0x37, 0x41, 0x41, 0x41, 0x1a, 0x1a, 0x1d, 0x6a, 0x6a, 0x6d, 0x52, 0x52, 0x52, 0x3a, 0x3a, 0x3a, 0x5b, 0x5b, 0x5b, 0x2f, 0x2f, 0x2f, 0x50, 0x50, 0x51, 0x13, 0x13, 0x15, 0x2b, 0xcd, 0x4, 0x96, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x1, 0x29, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0x94, 0xdb, 0x76, 0x83, 0x20, 0x10, 0x45, 0x8d, 0xe8, 0x24, 0x98, 0xda, 0x1a, 0x93, 0xda, 0x5b, 0xac, 0xb9, 0x50, 0x14, 0x52, 0x72, 0xfd, 0xff, 0x7f, 0xab, 0x68, 0x49, 0x28, 0x5a, 0x35, 0xf5, 0xa5, 0xf, 0x39, 0xf, 0xb3, 0x96, 0xe3, 0xda, 0x7, 0x98, 0x81, 0xb1, 0xac, 0x9b, 0xfe, 0x97, 0x6, 0x36, 0x72, 0x5c, 0x68, 0x91, 0xeb, 0x20, 0x7b, 0x50, 0xcf, 0xf, 0x5b, 0xe1, 0xb3, 0xc9, 0xb0, 0x6, 0x1f, 0xe1, 0x46, 0xc6, 0x1b, 0xdf, 0xf9, 0xf7, 0xa5, 0x1e, 0x2, 0xf, 0xf0, 0xc8, 0xe4, 0x27, 0x8d, 0xcb, 0x87, 0xd3, 0xd9, 0xf8, 0x31, 0x7a, 0x92, 0x7a, 0xf6, 0x5e, 0x5e, 0xdf, 0xa6, 0xa1, 0x3b, 0x31, 0xc, 0x1a, 0xd7, 0xf, 0xe7, 0xf1, 0xbb, 0xfe, 0x9d, 0xc4, 0xf3, 0x10, 0xff, 0xe4, 0x17, 0x4d, 0xfc, 0x72, 0x15, 0x7b, 0xc6, 0x81, 0xe2, 0xd5, 0x72, 0xa1, 0xf3, 0xeb, 0xc6, 0xf3, 0x93, 0x8f, 0xc4, 0x4c, 0x25, 0x33, 0x2, 0x6b, 0xcd, 0xc0, 0x56, 0x3f, 0x10, 0x4d, 0x33, 0x6, 0x24, 0xcd, 0x55, 0x4, 0x2e, 0x93, 0x9b, 0xa0, 0x6a, 0x1a, 0x6c, 0xe0, 0x53, 0x33, 0x40, 0x2a, 0x2f, 0x28, 0xe2, 0x29, 0x22, 0x12, 0x24, 0x25, 0x9d, 0x6b, 0xbb, 0xab, 0x1a, 0xec, 0xb6, 0x80, 0x34, 0x3, 0x47, 0x6d, 0x40, 0x42, 0x94, 0x11, 0x21, 0xd, 0x84, 0x32, 0xd8, 0x1f, 0xaa, 0x6, 0x87, 0x3d, 0xe8, 0x65, 0x54, 0x3d, 0x24, 0x22, 0xf, 0x47, 0x4a, 0x84, 0x10, 0xbc, 0x8, 0x45, 0xd6, 0x8f, 0xaa, 0x6, 0x91, 0xf, 0x50, 0xd3, 0x44, 0x5e, 0xec, 0xe0, 0x78, 0xfd, 0xe, 0x2e, 0x35, 0x60, 0xc0, 0x33, 0xf3, 0x8, 0x1d, 0x6a, 0x70, 0xee, 0x2, 0xc9, 0x44, 0x46, 0xc1, 0x30, 0xe8, 0xd0, 0x85, 0xcb, 0x3d, 0xe0, 0x4c, 0xd6, 0x92, 0xf1, 0xef, 0xd0, 0xf5, 0x1e, 0xf4, 0xbe, 0x89, 0xfd, 0xdf, 0x42, 0xff, 0xd7, 0x68, 0x9d, 0xae, 0x9b, 0x7, 0xa7, 0xba, 0x89, 0x4, 0x9d, 0x55, 0x37, 0x91, 0xca, 0x99, 0x88, 0xdb, 0x61, 0xfc, 0xeb, 0x4c, 0xbc, 0xe9, 0xaf, 0xfa, 0x2, 0xdc, 0x1a, 0x30, 0x60, 0x4e, 0xef, 0xb8, 0xbb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + +static const unsigned char toggle_off_mirrored_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, 0xaa, 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, 0x24, 0x24, 0x28, 0x20, 0x20, 0x25, 0x14, 0x14, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x22, 0x22, 0x27, 0x10, 0x10, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x19, 0x19, 0x1c, 0x12, 0x12, 0x15, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0x11, 0x11, 0x14, 0x1e, 0x1e, 0x22, 0x23, 0x23, 0x27, 0xe, 0xe, 0x10, 0x15, 0x15, 0x18, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x25, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x20, 0x20, 0x24, 0x24, 0x24, 0x27, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0xb, 0xb, 0xd, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x1a, 0x1a, 0x1e, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x22, 0x22, 0x26, 0x11, 0x11, 0x13, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x24, 0x24, 0x28, 0x2d, 0x26, 0x2c, 0x51, 0x2c, 0x39, 0x6c, 0x31, 0x42, 0x71, 0x32, 0x44, 0x6e, 0x31, 0x43, 0x63, 0x2f, 0x3f, 0x4d, 0x2b, 0x37, 0x27, 0x25, 0x2a, 0x47, 0x2a, 0x35, 0x68, 0x30, 0x40, 0x52, 0x2c, 0x39, 0x3c, 0x28, 0x31, 0x2e, 0x25, 0x2c, 0x26, 0x25, 0x2a, 0x32, 0x26, 0x2e, 0x4d, 0x2b, 0x38, 0x66, 0x30, 0x40, 0x50, 0x2c, 0x38, 0x5e, 0x2e, 0x3d, 0x38, 0x27, 0x30, 0x35, 0x27, 0x2f, 0x5f, 0x2e, 0x3d, 0x44, 0x2a, 0x34, 0x5f, 0x2f, 0x3e, 0x2f, 0x25, 0x2c, 0x43, 0x2a, 0x34, 0x2c, 0x26, 0x2c, 0x66, 0x2f, 0x40, 0x37, 0x27, 0x30, 0x36, 0x27, 0x30, 0x64, 0x2f, 0x3f, 0x2b, 0x26, 0x2c, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x32, 0x32, 0x37, 0x46, 0x2a, 0x35, 0x53, 0x2c, 0x39, 0xc9, 0xc9, 0xca, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x5d, 0x2e, 0x3d, 0x3e, 0x29, 0x32, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x69, 0x30, 0x41, 0x2f, 0x26, 0x2d, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x4e, 0x4e, 0x52, 0x48, 0x2b, 0x36, 0x2c, 0x26, 0x2b, 0x25, 0x25, 0x27, 0xea, 0xac, 0x78, 0x5d, 0x0, 0x0, 0x0, 0x51, 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, 0xfa, 0xe5, 0x98, 0x8, 0x17, 0x35, 0x73, 0xd9, 0xf3, 0x86, 0x7, 0x3a, 0x96, 0xf9, 0xb4, 0x9a, 0xb9, 0xb, 0x28, 0x76, 0xfb, 0x8a, 0xde, 0xf6, 0x82, 0x9b, 0xc6, 0xe6, 0x4c, 0xfe, 0x4f, 0xe9, 0xfb, 0x37, 0x83, 0x9c, 0xf6, 0x77, 0x8b, 0x3b, 0x9c, 0xbb, 0x74, 0xda, 0xf3, 0x87, 0xfb, 0x45, 0x4e, 0x53, 0x5, 0xf, 0x14, 0xc7, 0x22, 0x44, 0x61, 0x0, 0x0, 0x2, 0x45, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0x55, 0xe7, 0x5f, 0xd3, 0x40, 0x18, 0x26, 0x3b, 0x91, 0x24, 0x65, 0x95, 0xd, 0xd, 0x8e, 0x22, 0x6a, 0x71, 0x2b, 0x82, 0x75, 0xe1, 0x66, 0xa6, 0x97, 0xa0, 0x56, 0x45, 0xa4, 0x2a, 0x2e, 0xdc, 0x76, 0x25, 0x18, 0x84, 0x6, 0x9c, 0xff, 0xb3, 0xb9, 0x26, 0x17, 0xda, 0xa4, 0x49, 0xd4, 0x4f, 0xfa, 0x7c, 0xb8, 0xdf, 0xe5, 0xcd, 0xef, 0x79, 0xee, 0xbd, 0xf7, 0xde, 0xd1, 0xd4, 0xf4, 0xf, 0x1, 0xc3, 0x9, 0x82, 0x8c, 0x4, 0x41, 0xe0, 0x58, 0x43, 0x3a, 0x4e, 0x52, 0x34, 0xc3, 0x72, 0xbb, 0x22, 0xc0, 0xb1, 0xc, 0x4d, 0x91, 0xb8, 0xff, 0x74, 0xb2, 0x99, 0xe5, 0x5, 0x31, 0xd6, 0xd2, 0xda, 0x16, 0x8a, 0xd6, 0x96, 0x98, 0x28, 0xf0, 0x6c, 0x33, 0xe9, 0xf1, 0x2, 0x6f, 0xef, 0x88, 0x77, 0x76, 0x75, 0xf7, 0xf4, 0xf6, 0xc9, 0x11, 0xc8, 0xf4, 0xf5, 0xf, 0xc, 0x76, 0xc6, 0x3b, 0xda, 0xeb, 0x9c, 0xc0, 0x13, 0xd2, 0xd0, 0xee, 0x3d, 0x99, 0x0, 0xe, 0x50, 0x20, 0xec, 0xbd, 0xb5, 0x1, 0x40, 0xdd, 0xbb, 0x6f, 0x48, 0x4a, 0xd4, 0x28, 0x60, 0x49, 0x6e, 0x78, 0xff, 0x48, 0xe0, 0xa1, 0x90, 0xbb, 0x70, 0xeb, 0xf6, 0x1d, 0x1b, 0xd9, 0xbb, 0xf7, 0x16, 0x80, 0x7a, 0x60, 0x98, 0x4b, 0x62, 0x3b, 0xf7, 0x67, 0x84, 0x83, 0xa1, 0xbe, 0xdf, 0x5f, 0x7c, 0xb0, 0xf4, 0x70, 0x39, 0x57, 0xdd, 0xe7, 0x1e, 0x3d, 0x7e, 0xb2, 0xa8, 0xa8, 0x87, 0x4, 0xc6, 0x8d, 0x3, 0x9e, 0x1a, 0x3d, 0x7c, 0x24, 0x94, 0xbf, 0xf2, 0xf4, 0x59, 0xed, 0xf7, 0xf3, 0x17, 0x2b, 0x8a, 0x7a, 0x74, 0x34, 0x85, 0x2e, 0x41, 0x4a, 0xe2, 0xb1, 0x30, 0x7e, 0xee, 0xe5, 0xea, 0xab, 0x7a, 0xcb, 0xf2, 0xea, 0x6b, 0x70, 0x5c, 0x94, 0x48, 0xe7, 0x6, 0x14, 0x7f, 0x22, 0x34, 0xf0, 0x6f, 0xde, 0xbe, 0xf3, 0x9a, 0xde, 0x7f, 0xf8, 0x8, 0x4e, 0xf2, 0x94, 0x73, 0x3, 0x5a, 0x38, 0x85, 0x7e, 0xe4, 0xb, 0xc5, 0x52, 0x59, 0xd6, 0x8a, 0x16, 0xaa, 0x8b, 0xe, 0x8d, 0x6b, 0x9f, 0xfc, 0xa2, 0x4b, 0x6b, 0xe0, 0xb4, 0x40, 0xdb, 0x2, 0x4, 0x23, 0xf6, 0x20, 0xbb, 0xb1, 0x9e, 0xff, 0x5c, 0xcc, 0x6b, 0x90, 0xa8, 0xd9, 0x6c, 0xb, 0x1b, 0x9b, 0x7e, 0x81, 0xcd, 0xd, 0xa5, 0x5f, 0x64, 0x1c, 0x1, 0x76, 0xac, 0x17, 0x39, 0x0, 0x49, 0xeb, 0x15, 0xcd, 0x84, 0x2, 0x26, 0x12, 0xd8, 0xda, 0xf6, 0xb, 0x6c, 0x6f, 0x29, 0x67, 0xc6, 0x58, 0x47, 0x40, 0x1a, 0x47, 0x6f, 0xa8, 0x99, 0xd6, 0xf2, 0xa5, 0xa0, 0x19, 0x86, 0xa1, 0x57, 0x97, 0xaa, 0x35, 0x9b, 0x6b, 0x10, 0xd8, 0xac, 0xa2, 0x8e, 0x4b, 0xc8, 0x83, 0x18, 0x4a, 0x22, 0x1d, 0x7a, 0x50, 0xf8, 0xaa, 0x41, 0xa6, 0x66, 0x44, 0x78, 0xa0, 0xc6, 0x58, 0x37, 0x6, 0x13, 0xc8, 0x6e, 0x56, 0x64, 0xbd, 0x54, 0xf6, 0x8, 0x34, 0x8e, 0x1, 0x38, 0x8b, 0x62, 0x80, 0xd3, 0x69, 0xf7, 0x15, 0xb4, 0x92, 0x59, 0x2a, 0xc8, 0x1e, 0x81, 0xa0, 0x57, 0x48, 0xd3, 0x6e, 0x1e, 0x9c, 0x73, 0x7f, 0xe8, 0x95, 0x6f, 0x56, 0x2c, 0xcb, 0xba, 0xb3, 0x84, 0xe5, 0xc1, 0x79, 0x94, 0x7, 0x7f, 0x97, 0x89, 0xca, 0x5, 0x37, 0x13, 0x61, 0x2d, 0x5c, 0xfc, 0xf3, 0x5a, 0xb8, 0xb4, 0x53, 0xb, 0xbf, 0x51, 0x8d, 0xdf, 0x43, 0xab, 0x11, 0xf6, 0x83, 0xc9, 0xcb, 0xa1, 0x3e, 0xd4, 0xf7, 0x83, 0x1f, 0x40, 0xbd, 0x32, 0x59, 0xd3, 0xf, 0x60, 0x47, 0xe2, 0x84, 0xab, 0xd7, 0x82, 0xc8, 0x76, 0x47, 0x72, 0x9a, 0x92, 0xd5, 0x91, 0x7e, 0x82, 0xeb, 0x37, 0x4, 0x2e, 0x51, 0xdf, 0xd3, 0x92, 0x4c, 0x5c, 0xec, 0xea, 0x9e, 0x18, 0x91, 0x23, 0x91, 0xb9, 0x39, 0x30, 0x28, 0xc6, 0x99, 0xa4, 0xa7, 0x31, 0x63, 0x64, 0x8a, 0xe5, 0xd3, 0x53, 0xd3, 0x33, 0x6d, 0x11, 0x98, 0x99, 0x9e, 0x4a, 0xf3, 0x6c, 0x8a, 0xf4, 0xcd, 0x6, 0xc, 0x9f, 0xa5, 0xe6, 0xe6, 0xa5, 0xe8, 0xb9, 0x20, 0xcd, 0xcf, 0x51, 0xb3, 0x8d, 0x67, 0x8b, 0x35, 0x99, 0xa2, 0x7, 0x93, 0x35, 0x9a, 0x2, 0x26, 0xd3, 0xff, 0x8b, 0x5f, 0x3d, 0xdc, 0x7c, 0xb4, 0x8c, 0xb2, 0xd8, 0x5f, 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 }; @@ -354,6 +398,14 @@ 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, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x53, 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, 0x25, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x2e, 0x2e, 0x2e, 0x46, 0x46, 0x46, 0x57, 0x57, 0x57, 0x60, 0x60, 0x60, 0x62, 0x62, 0x62, 0x5e, 0x5e, 0x5e, 0x4a, 0x4a, 0x4a, 0x12, 0x12, 0x15, 0x25, 0x27, 0x2d, 0x42, 0x42, 0x42, 0x59, 0x59, 0x59, 0x32, 0x32, 0x32, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x39, 0x39, 0x39, 0x49, 0x49, 0x49, 0x5a, 0x5a, 0x5a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0x48, 0x48, 0x48, 0x54, 0x54, 0x54, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x25, 0x26, 0x2b, 0x3f, 0x3f, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x2c, 0x2c, 0x2c, 0x58, 0x58, 0x58, 0x1a, 0x1a, 0x1e, 0x40, 0x40, 0x44, 0x56, 0x56, 0x58, 0x80, 0x80, 0x80, 0x79, 0x79, 0x79, 0x3c, 0x3c, 0x3d, 0x2e, 0x2e, 0x30, 0x27, 0x27, 0x29, 0x64, 0x64, 0x66, 0x41, 0x41, 0x41, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5d, 0x5d, 0x5f, 0x34, 0x34, 0x36, 0x52, 0x52, 0x52, 0x3a, 0x3a, 0x3a, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x32, 0x32, 0x37, 0x42, 0x42, 0x44, 0x6a, 0x6a, 0x6d, 0x5b, 0x5b, 0x5b, 0x2f, 0x2f, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x49, 0x4a, 0x0, 0x0, 0x0, 0x50, 0x50, 0x51, 0x70, 0x70, 0x74, 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, 0xbd, 0xb, 0x85, 0x35, 0x0, 0x0, 0x0, 0x71, 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, 0xff, 0x8, 0x17, 0x35, 0x73, 0xd9, 0xff, 0x7, 0x3a, 0x96, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb, 0x28, 0x76, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x77, 0xde, 0xff, 0xff, 0x45, 0x5, 0x82, 0xff, 0xff, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x37, 0xf, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x4c, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4e, 0x4f, 0xff, 0x50, 0xff, 0xff, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x49, 0x96, 0x6e, 0xf, 0x0, 0x0, 0x1, 0xfa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x18, 0x5e, 0x0, 0xd0, 0x5c, 0x39, 0x28, 0x49, 0x12, 0xc0, 0x60, 0xb8, 0xda, 0xdd, 0xcb, 0x31, 0x33, 0xb6, 0x6d, 0xdb, 0x5e, 0xdb, 0xd6, 0xfb, 0x17, 0x4e, 0x7d, 0x37, 0xe6, 0xf9, 0x2b, 0x23, 0x7f, 0x9c, 0x20, 0x28, 0x86, 0xe1, 0xb, 0xc1, 0x30, 0x14, 0x99, 0x6a, 0x8e, 0xe2, 0x4, 0x49, 0xd1, 0xcc, 0xda, 0x2, 0x18, 0x9a, 0x22, 0x9, 0x1c, 0x9d, 0xf4, 0x8e, 0xaf, 0xd3, 0x1b, 0x9b, 0x5b, 0xdb, 0x1c, 0x2e, 0x6f, 0x2e, 0x5c, 0xce, 0xf6, 0xd6, 0xe6, 0x6, 0xbd, 0x8e, 0x8f, 0x45, 0x81, 0xf2, 0x5, 0x42, 0x91, 0x58, 0x22, 0x95, 0xc9, 0x61, 0x1, 0x72, 0x99, 0x54, 0x22, 0x16, 0x9, 0x5, 0x7c, 0x74, 0xc4, 0x5e, 0xa1, 0x54, 0xa9, 0x35, 0x5a, 0x58, 0x12, 0xad, 0x46, 0xad, 0x52, 0x2a, 0x86, 0x14, 0x10, 0x1d, 0xa3, 0x37, 0x18, 0x61, 0x1e, 0x26, 0xb3, 0xc5, 0x6a, 0x63, 0xb1, 0x3b, 0x4c, 0x60, 0x34, 0xe8, 0x19, 0x1d, 0x32, 0xc8, 0x9f, 0xda, 0x74, 0xce, 0x8d, 0xdd, 0xe5, 0xf6, 0x98, 0xbd, 0x3e, 0xff, 0x57, 0x2, 0xa6, 0x60, 0x28, 0xec, 0x76, 0xc9, 0x9d, 0x9b, 0x54, 0xbf, 0xe, 0x68, 0x24, 0x1a, 0x8b, 0xcf, 0xb5, 0x4f, 0x24, 0x53, 0x30, 0x44, 0x3a, 0x99, 0x70, 0xc5, 0x33, 0xd1, 0xc8, 0x8f, 0x24, 0x70, 0xe5, 0x56, 0x16, 0xe6, 0x90, 0xcb, 0x27, 0x4d, 0x63, 0x9, 0x25, 0xf3, 0xb9, 0x6c, 0x41, 0x59, 0x64, 0x43, 0x40, 0x88, 0x8d, 0x12, 0xcc, 0xa3, 0x5c, 0x49, 0xc3, 0x18, 0x69, 0x4f, 0x19, 0x4a, 0x1b, 0x4, 0x2b, 0x80, 0x92, 0x9b, 0x55, 0xe8, 0x53, 0xab, 0x37, 0x9a, 0x2d, 0x68, 0x37, 0x3a, 0xd0, 0xee, 0x2, 0x4b, 0xcf, 0x1, 0x13, 0x38, 0x7a, 0xb0, 0xb3, 0xbb, 0xc7, 0xe6, 0x80, 0x51, 0x5b, 0x52, 0xe8, 0xd3, 0xdd, 0xaf, 0x1d, 0x34, 0x6a, 0xed, 0x46, 0x77, 0x20, 0x70, 0x78, 0x4, 0x13, 0x1c, 0x1d, 0xc2, 0x71, 0x81, 0xc2, 0x58, 0x1, 0xfa, 0x44, 0x36, 0x8, 0xa0, 0x71, 0xa, 0xb0, 0x7f, 0xd6, 0x3e, 0x6f, 0xb6, 0xfb, 0x2, 0x17, 0x97, 0x30, 0xc1, 0xe5, 0x5, 0x18, 0xaf, 0x68, 0x9c, 0x15, 0x50, 0x5e, 0xf, 0x7a, 0xd8, 0x3e, 0x7, 0x80, 0x9b, 0x7a, 0xbb, 0x7b, 0x73, 0xde, 0x17, 0xb0, 0xfa, 0x60, 0x2, 0x9f, 0x15, 0xe0, 0x56, 0xf9, 0x5d, 0x80, 0xde, 0x1e, 0xc, 0xd1, 0xe9, 0xd7, 0x8, 0xea, 0x77, 0xed, 0x2e, 0xdc, 0xd7, 0x97, 0x8e, 0x80, 0xda, 0x3a, 0x86, 0x3e, 0xe7, 0x67, 0x70, 0xda, 0x6c, 0xb5, 0xbb, 0xd0, 0x6a, 0x2c, 0x5b, 0x3, 0x94, 0xdc, 0xad, 0x42, 0x9f, 0x76, 0xf3, 0xbc, 0x59, 0x87, 0xaf, 0xe1, 0x9f, 0x2f, 0xd5, 0x5, 0x76, 0xe, 0x1e, 0x60, 0xc0, 0xe9, 0x59, 0x7, 0xa0, 0xd6, 0x2, 0xe8, 0xb4, 0xe6, 0xcf, 0xc1, 0x83, 0x90, 0x40, 0x7e, 0x79, 0x12, 0xfb, 0xbb, 0x90, 0x59, 0x7d, 0x17, 0x1e, 0xd9, 0x5d, 0xf8, 0xd5, 0x6d, 0xec, 0xdf, 0x83, 0xa7, 0xe7, 0xf8, 0x2a, 0xf7, 0x20, 0xfe, 0xfc, 0xc2, 0xde, 0x83, 0xfe, 0x45, 0x62, 0x36, 0x5f, 0xdf, 0x60, 0x69, 0xde, 0x5e, 0x37, 0x19, 0xc5, 0xe8, 0x4d, 0xd3, 0x51, 0xc2, 0x2d, 0xb1, 0xe4, 0xd8, 0x8, 0xb, 0x31, 0x1e, 0x4b, 0xc4, 0x5b, 0x42, 0x4a, 0x87, 0x8e, 0x5f, 0xe5, 0x8, 0xbd, 0xb1, 0x5b, 0xb8, 0x7a, 0xe7, 0x2d, 0xe0, 0xfd, 0xaa, 0xb0, 0xbb, 0x41, 0x47, 0x70, 0x64, 0xf2, 0xab, 0x14, 0x89, 0xbd, 0xf, 0xe5, 0xe2, 0xbf, 0xa0, 0xfc, 0xd8, 0x23, 0x8a, 0x28, 0x32, 0xe3, 0x33, 0xe1, 0x4b, 0xc0, 0x7e, 0xa6, 0xff, 0x87, 0xcf, 0xb, 0x94, 0xb9, 0x37, 0x3c, 0xc6, 0xd8, 0xcd, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char toggle_on_disabled_mirrored_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, 0x0, 0x69, 0x50, 0x4c, 0x54, 0x45, 0x93, 0x7f, 0x2b, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x19, 0x19, 0x1c, 0x2b, 0x26, 0x2c, 0x40, 0x40, 0x44, 0x4e, 0x4e, 0x52, 0x1a, 0x1a, 0x1d, 0x32, 0x32, 0x37, 0x2c, 0x26, 0x2c, 0x26, 0x25, 0x2a, 0x27, 0x25, 0x2a, 0x11, 0x11, 0x14, 0x2f, 0x26, 0x2d, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x15, 0x15, 0x18, 0x5b, 0x5b, 0x5f, 0x84, 0x84, 0x87, 0x77, 0x77, 0x7a, 0x69, 0x69, 0x6c, 0x20, 0x20, 0x24, 0x24, 0x24, 0x27, 0x23, 0x23, 0x28, 0x1a, 0x1a, 0x1e, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0xd7, 0x77, 0xc6, 0x92, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x1, 0x35, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0x94, 0xd1, 0x72, 0x83, 0x20, 0x10, 0x45, 0x4d, 0x90, 0xb8, 0x18, 0x96, 0x6c, 0xb5, 0x24, 0x41, 0x68, 0x9b, 0xf4, 0xff, 0x3f, 0xb2, 0x84, 0xb4, 0x8a, 0xa, 0x3a, 0x9d, 0x74, 0xa6, 0x2f, 0xb9, 0xbe, 0x38, 0xca, 0x3d, 0x5c, 0x16, 0xd8, 0xa2, 0x78, 0xea, 0x2f, 0xb5, 0xd9, 0xb2, 0xb2, 0xe4, 0x2b, 0x2a, 0x4b, 0xb6, 0xdd, 0x24, 0xed, 0xbb, 0x8a, 0x1, 0x8, 0x21, 0xee, 0xe3, 0xc4, 0x4d, 0x20, 0x6a, 0x91, 0x84, 0x54, 0xbb, 0xb9, 0x7f, 0xcf, 0x40, 0xa2, 0xea, 0x85, 0x32, 0x50, 0x6a, 0xc8, 0xe4, 0xd8, 0x4f, 0xfd, 0x7, 0x26, 0x48, 0xe1, 0x4b, 0x13, 0x7e, 0x37, 0x92, 0x50, 0x51, 0x1b, 0x92, 0xe4, 0x56, 0x72, 0x18, 0xfb, 0x5f, 0x99, 0x40, 0xd4, 0xf1, 0x8, 0x42, 0x6c, 0x17, 0x6b, 0x71, 0x1c, 0x1, 0x4e, 0x40, 0x21, 0x74, 0x24, 0x89, 0xd4, 0x2c, 0x11, 0x4e, 0xb1, 0xff, 0xc, 0x52, 0xe9, 0xe9, 0x8, 0x52, 0x8b, 0x11, 0xf8, 0x39, 0x2, 0x6c, 0x7d, 0x80, 0xf9, 0x8, 0xa4, 0xe1, 0xd5, 0x74, 0x16, 0xb9, 0xee, 0x5a, 0xae, 0xdd, 0xcf, 0xb7, 0xb7, 0x8, 0xe0, 0x2b, 0x40, 0x73, 0x40, 0x4, 0x75, 0x6, 0xa9, 0x43, 0xdd, 0xb9, 0x8, 0xc0, 0x46, 0x0, 0x25, 0xe7, 0x0, 0xa9, 0xfa, 0x0, 0x9d, 0xe7, 0x1b, 0xd4, 0xce, 0xea, 0x1, 0x50, 0x8e, 0x1, 0x89, 0x82, 0x35, 0x3d, 0x20, 0xb8, 0x94, 0xd1, 0x4e, 0xb9, 0x1, 0xc0, 0x7f, 0x91, 0x80, 0x42, 0x2, 0xe5, 0xcd, 0xd6, 0x24, 0x13, 0xbc, 0xc3, 0x5a, 0xd, 0x90, 0x93, 0xf5, 0x4b, 0xf0, 0x8b, 0x49, 0xd6, 0x60, 0x75, 0x17, 0xb4, 0x75, 0xd6, 0x84, 0x95, 0xb8, 0xe4, 0x2e, 0xac, 0x9f, 0x3, 0xba, 0x9d, 0x4b, 0xf4, 0xb3, 0xb4, 0xfd, 0x4c, 0xf1, 0x39, 0x28, 0x3e, 0xc4, 0x63, 0x27, 0xb1, 0x38, 0x3e, 0x7a, 0x17, 0xb2, 0xb7, 0x31, 0xeb, 0x9f, 0xdc, 0xc6, 0xa2, 0xb8, 0x30, 0x68, 0xa7, 0xfd, 0x60, 0xc1, 0x7f, 0x99, 0x77, 0x94, 0xeb, 0x27, 0xd4, 0x70, 0x6f, 0x48, 0xe2, 0x5b, 0xe0, 0x9f, 0xa4, 0xbf, 0xba, 0x66, 0x7b, 0x22, 0x5f, 0x55, 0xb6, 0x27, 0x3e, 0xf5, 0x8f, 0xfa, 0x2, 0xa0, 0x14, 0x20, 0xeb, 0xde, 0xb1, 0x8c, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + +static const unsigned char toggle_on_mirrored_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, 0x9b, 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, 0x24, 0x24, 0x28, 0x20, 0x20, 0x25, 0x14, 0x14, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x22, 0x22, 0x27, 0x10, 0x10, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x19, 0x19, 0x1c, 0x12, 0x12, 0x15, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x1e, 0x22, 0x23, 0x23, 0x27, 0xe, 0xe, 0x10, 0x15, 0x15, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1d, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x15, 0x15, 0x18, 0xb, 0xb, 0xd, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x1a, 0x1a, 0x1e, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x11, 0x11, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x25, 0x2c, 0x36, 0x28, 0x4c, 0x6b, 0x29, 0x64, 0x92, 0x2a, 0x68, 0x99, 0x2a, 0x66, 0x95, 0x29, 0x5d, 0x85, 0x27, 0x49, 0x65, 0x25, 0x25, 0x28, 0x25, 0x27, 0x2d, 0x27, 0x44, 0x5c, 0x29, 0x60, 0x8c, 0x27, 0x4d, 0x6b, 0x25, 0x3a, 0x4c, 0x25, 0x2d, 0x38, 0x25, 0x26, 0x2c, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2d, 0x25, 0x30, 0x3e, 0x27, 0x49, 0x66, 0x29, 0x5f, 0x89, 0x27, 0x43, 0x5c, 0x27, 0x4b, 0x69, 0x28, 0x58, 0x7f, 0x25, 0x35, 0x45, 0x25, 0x34, 0x43, 0x28, 0x59, 0x7f, 0x25, 0x26, 0x2b, 0x27, 0x41, 0x57, 0x27, 0x40, 0x57, 0x25, 0x2b, 0x34, 0x25, 0x34, 0x44, 0x29, 0x5d, 0x87, 0x25, 0x2a, 0x33, 0x27, 0x43, 0x5b, 0x27, 0x4e, 0x6d, 0x27, 0x4d, 0x6c, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x4e, 0x4e, 0x52, 0xc9, 0xc9, 0xca, 0x28, 0x56, 0x7b, 0x26, 0x3a, 0x4e, 0x26, 0x3b, 0x4e, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x29, 0x61, 0x8d, 0x25, 0x2e, 0x39, 0x32, 0x32, 0x37, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x27, 0x44, 0x5d, 0xa6, 0xa2, 0x25, 0x5b, 0x0, 0x0, 0x0, 0x4c, 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, 0xfa, 0xe5, 0x98, 0x8, 0x17, 0x35, 0x73, 0xd9, 0xf3, 0x86, 0x7, 0x3a, 0x96, 0xf9, 0xb4, 0x9a, 0xb9, 0xb, 0x28, 0x77, 0xfb, 0x8b, 0x5, 0x45, 0xde, 0xf6, 0x82, 0x9b, 0xf, 0x37, 0xc6, 0xe6, 0xe9, 0xfb, 0x4e, 0x50, 0x83, 0x9c, 0x78, 0x8c, 0x3c, 0x9c, 0xbb, 0x74, 0xda, 0x87, 0x53, 0x14, 0xd0, 0x92, 0x4e, 0x2c, 0x0, 0x0, 0x2, 0x35, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0x63, 0x60, 0x18, 0x44, 0x80, 0x91, 0x89, 0x99, 0x99, 0x85, 0x20, 0x60, 0x66, 0x66, 0x62, 0xc4, 0xaa, 0x9d, 0x89, 0x85, 0x95, 0x8d, 0x9d, 0x83, 0x93, 0x8b, 0x0, 0xe0, 0xe4, 0x60, 0x67, 0x63, 0x65, 0x61, 0xc2, 0xb4, 0x9d, 0x85, 0x9b, 0x83, 0x87, 0x97, 0x8f, 0x5f, 0x40, 0x50, 0x8, 0x2f, 0x10, 0x14, 0xe0, 0xe7, 0xe3, 0xe5, 0xe1, 0xe0, 0x66, 0x41, 0x73, 0x5, 0x93, 0xb0, 0x88, 0xa8, 0x98, 0xb8, 0x84, 0xa4, 0x94, 0xb4, 0xf, 0x1, 0xe0, 0x2b, 0x2d, 0x23, 0x2b, 0x27, 0x26, 0x2a, 0x22, 0x8c, 0xe2, 0x8, 0x26, 0x79, 0x5, 0x45, 0x25, 0x65, 0x5f, 0xc, 0xd5, 0x7e, 0xfe, 0x7e, 0x58, 0xd, 0x51, 0x51, 0x55, 0x54, 0x90, 0x47, 0x32, 0x81, 0x51, 0x8d, 0x53, 0x5d, 0x43, 0xd3, 0x27, 0x20, 0x30, 0x28, 0x18, 0x2, 0x42, 0x42, 0xc3, 0x2, 0x20, 0x6, 0x84, 0xe3, 0x70, 0x87, 0x96, 0x3a, 0xa7, 0x1a, 0x23, 0xc2, 0xff, 0xec, 0xbc, 0xda, 0xd2, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x20, 0x90, 0x90, 0x98, 0x94, 0x9c, 0x12, 0x1, 0x36, 0x2, 0x97, 0x4f, 0x74, 0x78, 0xd9, 0xe1, 0xe1, 0xc0, 0xa4, 0xab, 0xa7, 0x6f, 0x10, 0x91, 0x9a, 0x96, 0x8e, 0xac, 0x22, 0x23, 0x33, 0x35, 0x2, 0x6f, 0x58, 0x18, 0xea, 0xe9, 0x42, 0x3d, 0xc1, 0x68, 0xa4, 0x60, 0x6c, 0x92, 0x95, 0x9d, 0x19, 0x8b, 0xaa, 0x22, 0x36, 0x33, 0x27, 0xb, 0x9f, 0x9, 0xa6, 0xc6, 0xa, 0x46, 0x10, 0x27, 0x30, 0xb1, 0xf2, 0x98, 0xf9, 0xe4, 0x26, 0xa7, 0xa3, 0xab, 0xc8, 0xcb, 0x2f, 0xc0, 0x1b, 0x1f, 0xe6, 0x3c, 0xac, 0x10, 0x3, 0x58, 0x2c, 0x2c, 0xad, 0x7c, 0xa, 0x8b, 0x30, 0x55, 0x14, 0x17, 0xc2, 0x99, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x3e, 0x95, 0x65, 0x55, 0x3e, 0x95, 0xd5, 0x30, 0x31, 0x6b, 0x4b, 0xb, 0x88, 0x1f, 0x84, 0xd9, 0x8d, 0x6d, 0x7c, 0x6a, 0x6a, 0x31, 0xd, 0xa8, 0xab, 0x81, 0x33, 0xab, 0xeb, 0x4b, 0x1a, 0xca, 0x4a, 0x2a, 0xcb, 0xaa, 0x91, 0xc, 0xb0, 0x35, 0x66, 0x67, 0x6, 0x1b, 0xa0, 0xc6, 0x61, 0xa7, 0xe9, 0xd3, 0xd8, 0x84, 0x69, 0x40, 0x53, 0x23, 0xdc, 0x1, 0x65, 0xcd, 0x3e, 0x3e, 0xf5, 0x2d, 0x95, 0xad, 0xe5, 0x95, 0x8, 0x3, 0x7c, 0xed, 0x38, 0x58, 0x20, 0x6, 0x28, 0xd8, 0xfb, 0xf8, 0x84, 0x24, 0x60, 0x1a, 0x90, 0x10, 0x2, 0x63, 0x55, 0xb6, 0x2, 0x89, 0xb6, 0xd2, 0xca, 0xea, 0xb6, 0x56, 0x84, 0x1, 0x3e, 0xf6, 0xa, 0x2c, 0xc4, 0xba, 0xa0, 0x19, 0xe4, 0x82, 0xd2, 0x76, 0xa0, 0xe6, 0xf2, 0x52, 0x4c, 0x17, 0x10, 0x13, 0x6, 0xad, 0x2d, 0x3e, 0xcd, 0xe5, 0x15, 0x40, 0x3, 0x2a, 0xca, 0x30, 0xc3, 0x80, 0x98, 0x58, 0xa8, 0x2c, 0x6f, 0x2d, 0x2f, 0x5, 0x7, 0x60, 0x2b, 0x66, 0x2c, 0x30, 0xb1, 0x8a, 0x3a, 0x10, 0x4c, 0x7, 0xcd, 0x2d, 0x55, 0xc0, 0xb0, 0xac, 0xf0, 0xf1, 0xa9, 0xaa, 0x80, 0x9, 0x39, 0x8a, 0x42, 0xd3, 0x1, 0xc5, 0x29, 0x11, 0x94, 0x17, 0x9c, 0x48, 0xcf, 0xb, 0xce, 0xf0, 0xbc, 0x0, 0xcb, 0x8d, 0x1d, 0xa8, 0xb9, 0x31, 0x12, 0xbf, 0x7e, 0xe4, 0xdc, 0x8, 0x2a, 0xf, 0x5c, 0x5c, 0xd, 0xb0, 0x94, 0x7, 0xb8, 0xf5, 0xbb, 0xb9, 0x20, 0x95, 0x7, 0xa0, 0x12, 0x89, 0x93, 0xd7, 0xdd, 0x3, 0x53, 0x9d, 0x5f, 0x38, 0xf6, 0xf2, 0x40, 0xc5, 0x93, 0x97, 0x53, 0x1e, 0xb5, 0x4c, 0x53, 0x63, 0x17, 0xe5, 0x13, 0x97, 0xb0, 0xd1, 0xf4, 0x21, 0x8, 0x7c, 0x6d, 0x65, 0xe5, 0xf8, 0x44, 0xd9, 0xd5, 0xd0, 0xa, 0x66, 0x46, 0x16, 0x5d, 0xe, 0x1e, 0x4b, 0x63, 0x3b, 0x2f, 0x21, 0x2, 0xc0, 0xcb, 0xce, 0xd8, 0x92, 0x87, 0x43, 0x97, 0x5, 0xa3, 0x6e, 0x60, 0x64, 0x32, 0x62, 0xb5, 0xf0, 0x56, 0x20, 0x5c, 0x2f, 0x28, 0x78, 0x5b, 0xb0, 0x1a, 0x61, 0xaf, 0x5b, 0x80, 0x35, 0x13, 0xe1, 0x8a, 0x9, 0x58, 0x35, 0xe1, 0xa8, 0x99, 0x86, 0x2e, 0x0, 0x0, 0x69, 0x2c, 0x6b, 0xc2, 0xf1, 0x2f, 0x53, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char tooltip_bg_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, 0x30, 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, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0xdd, 0xdd, 0xdd, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0xbc, 0x3, 0x4f, 0xe9, 0x0, 0x0, 0x0, 0xd, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xcc, 0xff, 0xb7, 0x4a, 0xbe, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x54, 0x76, 0x1, 0x2, 0x23, 0x1, 0x6, 0xd1, 0xf4, 0xe, 0x20, 0x28, 0xb, 0x64, 0xd0, 0x5c, 0x7d, 0x17, 0x8, 0x76, 0x4d, 0x62, 0x70, 0x7f, 0x7f, 0x6, 0x8, 0xfe, 0x95, 0x30, 0x78, 0xdc, 0x1, 0x31, 0xce, 0xb6, 0x50, 0xc8, 0x80, 0x1b, 0x8, 0xb7, 0x2, 0x6e, 0x29, 0xdc, 0x19, 0x0, 0xcf, 0x24, 0x4d, 0xb3, 0xd0, 0x4d, 0xb9, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -418,4 +470,8 @@ static const unsigned char window_resizer_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, 0x18, 0xbc, 0xe0, 0x45, 0x3f, 0x1, 0xe9, 0xec, 0xfe, 0x81, 0x94, 0x86, 0xb1, 0x70, 0x48, 0x23, 0x58, 0x84, 0xa4, 0x7, 0x15, 0x0, 0x0, 0xed, 0x9f, 0x18, 0xe8, 0xcd, 0x91, 0xd8, 0xe, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char window_resizer_mirrored_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, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x0, 0x27, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x44, 0xe0, 0x45, 0x3f, 0x76, 0x71, 0x26, 0x18, 0xa3, 0x19, 0xa7, 0x12, 0x38, 0xc8, 0xee, 0xa7, 0xb1, 0x12, 0x98, 0x4, 0x4e, 0x25, 0x8, 0x9, 0x4a, 0x94, 0xc, 0x10, 0x0, 0x0, 0x9d, 0x84, 0x18, 0x73, 0x33, 0x1c, 0x96, 0xd6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + // shaders block diff --git a/scene/resources/default_theme/toggle_off_disabled_mirrored.png b/scene/resources/default_theme/toggle_off_disabled_mirrored.png Binary files differnew file mode 100644 index 0000000000..799b63c098 --- /dev/null +++ b/scene/resources/default_theme/toggle_off_disabled_mirrored.png diff --git a/scene/resources/default_theme/toggle_off_mirrored.png b/scene/resources/default_theme/toggle_off_mirrored.png Binary files differnew file mode 100644 index 0000000000..3487605d58 --- /dev/null +++ b/scene/resources/default_theme/toggle_off_mirrored.png diff --git a/scene/resources/default_theme/toggle_on_disabled_mirrored.png b/scene/resources/default_theme/toggle_on_disabled_mirrored.png Binary files differnew file mode 100644 index 0000000000..0758babd4f --- /dev/null +++ b/scene/resources/default_theme/toggle_on_disabled_mirrored.png diff --git a/scene/resources/default_theme/toggle_on_mirrored.png b/scene/resources/default_theme/toggle_on_mirrored.png Binary files differnew file mode 100644 index 0000000000..3fd953c8e2 --- /dev/null +++ b/scene/resources/default_theme/toggle_on_mirrored.png diff --git a/scene/resources/default_theme/window_resizer_mirrored.png b/scene/resources/default_theme/window_resizer_mirrored.png Binary files differnew file mode 100644 index 0000000000..bbce5f1406 --- /dev/null +++ b/scene/resources/default_theme/window_resizer_mirrored.png diff --git a/scene/resources/default_theme/xpmfix.sh b/scene/resources/default_theme/xpmfix.sh deleted file mode 100755 index a24dede3c9..0000000000 --- a/scene/resources/default_theme/xpmfix.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -sed -i 's/static char/static const char/g' *.xpm diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp deleted file mode 100644 index 3b4e4b73f8..0000000000 --- a/scene/resources/dynamic_font.cpp +++ /dev/null @@ -1,1107 +0,0 @@ -/*************************************************************************/ -/* dynamic_font.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (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 "modules/modules_enabled.gen.h" -#ifdef MODULE_FREETYPE_ENABLED - -#include "dynamic_font.h" - -#include "core/os/file_access.h" -#include "core/os/os.h" - -#include FT_STROKER_H - -#define __STDC_LIMIT_MACROS -#include <stdint.h> - -bool DynamicFontData::CacheID::operator<(CacheID right) const { - return key < right.key; -} - -Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(CacheID p_cache_id) { - if (size_cache.has(p_cache_id)) { - return Ref<DynamicFontAtSize>(size_cache[p_cache_id]); - } - - Ref<DynamicFontAtSize> dfas; - - dfas.instance(); - - dfas->font = Ref<DynamicFontData>(this); - - size_cache[p_cache_id] = dfas.ptr(); - dfas->id = p_cache_id; - dfas->_load(); - - return dfas; -} - -void DynamicFontData::set_font_ptr(const uint8_t *p_font_mem, int p_font_mem_size) { - font_mem = p_font_mem; - font_mem_size = p_font_mem_size; -} - -void DynamicFontData::set_font_path(const String &p_path) { - font_path = p_path; -} - -String DynamicFontData::get_font_path() const { - return font_path; -} - -void DynamicFontData::set_force_autohinter(bool p_force) { - force_autohinter = p_force; -} - -void DynamicFontData::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &DynamicFontData::set_antialiased); - ClassDB::bind_method(D_METHOD("is_antialiased"), &DynamicFontData::is_antialiased); - ClassDB::bind_method(D_METHOD("set_font_path", "path"), &DynamicFontData::set_font_path); - ClassDB::bind_method(D_METHOD("get_font_path"), &DynamicFontData::get_font_path); - ClassDB::bind_method(D_METHOD("set_hinting", "mode"), &DynamicFontData::set_hinting); - ClassDB::bind_method(D_METHOD("get_hinting"), &DynamicFontData::get_hinting); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "is_antialiased"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting"); - - BIND_ENUM_CONSTANT(HINTING_NONE); - BIND_ENUM_CONSTANT(HINTING_LIGHT); - BIND_ENUM_CONSTANT(HINTING_NORMAL); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_path", PROPERTY_HINT_FILE, "*.ttf,*.otf"), "set_font_path", "get_font_path"); -} - -DynamicFontData::DynamicFontData() { - antialiased = true; - force_autohinter = false; - hinting = DynamicFontData::HINTING_NORMAL; - font_mem = nullptr; - font_mem_size = 0; -} - -DynamicFontData::~DynamicFontData() { -} - -//////////////////// -HashMap<String, Vector<uint8_t>> DynamicFontAtSize::_fontdata; - -Error DynamicFontAtSize::_load() { - int error = FT_Init_FreeType(&library); - - ERR_FAIL_COND_V_MSG(error != 0, ERR_CANT_CREATE, "Error initializing FreeType."); - - // FT_OPEN_STREAM is extremely slow only on Android. - if (OS::get_singleton()->get_name() == "Android" && font->font_mem == nullptr && font->font_path != String()) { - // cache font only once for each font->font_path - if (_fontdata.has(font->font_path)) { - font->set_font_ptr(_fontdata[font->font_path].ptr(), _fontdata[font->font_path].size()); - - } else { - FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ); - if (!f) { - FT_Done_FreeType(library); - ERR_FAIL_V_MSG(ERR_CANT_OPEN, "Cannot open font file '" + font->font_path + "'."); - } - - size_t len = f->get_len(); - _fontdata[font->font_path] = Vector<uint8_t>(); - Vector<uint8_t> &fontdata = _fontdata[font->font_path]; - fontdata.resize(len); - f->get_buffer(fontdata.ptrw(), len); - font->set_font_ptr(fontdata.ptr(), len); - f->close(); - } - } - - if (font->font_mem == nullptr && font->font_path != String()) { - FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ); - if (!f) { - FT_Done_FreeType(library); - ERR_FAIL_V_MSG(ERR_CANT_OPEN, "Cannot open font file '" + font->font_path + "'."); - } - - memset(&stream, 0, sizeof(FT_StreamRec)); - stream.base = nullptr; - stream.size = f->get_len(); - stream.pos = 0; - stream.descriptor.pointer = f; - stream.read = _ft_stream_io; - stream.close = _ft_stream_close; - - FT_Open_Args fargs; - memset(&fargs, 0, sizeof(FT_Open_Args)); - fargs.flags = FT_OPEN_STREAM; - fargs.stream = &stream; - error = FT_Open_Face(library, &fargs, 0, &face); - } else if (font->font_mem) { - memset(&stream, 0, sizeof(FT_StreamRec)); - stream.base = (unsigned char *)font->font_mem; - stream.size = font->font_mem_size; - stream.pos = 0; - - FT_Open_Args fargs; - memset(&fargs, 0, sizeof(FT_Open_Args)); - fargs.memory_base = (unsigned char *)font->font_mem; - fargs.memory_size = font->font_mem_size; - fargs.flags = FT_OPEN_MEMORY; - fargs.stream = &stream; - error = FT_Open_Face(library, &fargs, 0, &face); - - } else { - FT_Done_FreeType(library); - ERR_FAIL_V_MSG(ERR_UNCONFIGURED, "DynamicFont uninitialized."); - } - - //error = FT_New_Face( library, src_path.utf8().get_data(),0,&face ); - - if (error == FT_Err_Unknown_File_Format) { - FT_Done_FreeType(library); - ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, "Unknown font format."); - - } else if (error) { - FT_Done_FreeType(library); - ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, "Error loading font."); - } - - if (FT_HAS_COLOR(face) && face->num_fixed_sizes > 0) { - int best_match = 0; - int diff = ABS(id.size - ((int64_t)face->available_sizes[0].width)); - scale_color_font = float(id.size * oversampling) / face->available_sizes[0].width; - for (int i = 1; i < face->num_fixed_sizes; i++) { - int ndiff = ABS(id.size - ((int64_t)face->available_sizes[i].width)); - if (ndiff < diff) { - best_match = i; - diff = ndiff; - scale_color_font = float(id.size * oversampling) / face->available_sizes[i].width; - } - } - FT_Select_Size(face, best_match); - } else { - FT_Set_Pixel_Sizes(face, 0, id.size * oversampling); - } - - ascent = (face->size->metrics.ascender / 64.0) / oversampling * scale_color_font; - descent = (-face->size->metrics.descender / 64.0) / oversampling * scale_color_font; - underline_position = -face->underline_position / 64.0 / oversampling * scale_color_font; - underline_thickness = face->underline_thickness / 64.0 / oversampling * scale_color_font; - linegap = 0; - - valid = true; - return OK; -} - -float DynamicFontAtSize::font_oversampling = 1.0; - -float DynamicFontAtSize::get_height() const { - return ascent + descent; -} - -float DynamicFontAtSize::get_ascent() const { - return ascent; -} - -float DynamicFontAtSize::get_descent() const { - return descent; -} - -float DynamicFontAtSize::get_underline_position() const { - return underline_position; -} - -float DynamicFontAtSize::get_underline_thickness() const { - return underline_thickness; -} - -const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const { - const Character *chr = char_map.getptr(p_char); - ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(nullptr, nullptr))); - - if (!chr->found) { - //not found, try in fallbacks - for (int i = 0; i < p_fallbacks.size(); i++) { - DynamicFontAtSize *fb = const_cast<DynamicFontAtSize *>(p_fallbacks[i].ptr()); - if (!fb->valid) { - continue; - } - - fb->_update_char(p_char); - const Character *fallback_chr = fb->char_map.getptr(p_char); - ERR_CONTINUE(!fallback_chr); - - if (!fallback_chr->found) { - continue; - } - - return Pair<const Character *, DynamicFontAtSize *>(fallback_chr, fb); - } - - //not found, try 0xFFFD to display 'not found'. - const_cast<DynamicFontAtSize *>(this)->_update_char(0xFFFD); - chr = char_map.getptr(0xFFFD); - ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(nullptr, nullptr))); - } - - return Pair<const Character *, DynamicFontAtSize *>(chr, const_cast<DynamicFontAtSize *>(this)); -} - -Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const { - if (!valid) { - return Size2(1, 1); - } - const_cast<DynamicFontAtSize *>(this)->_update_char(p_char); - - Pair<const Character *, DynamicFontAtSize *> char_pair_with_font = _find_char_with_font(p_char, p_fallbacks); - const Character *ch = char_pair_with_font.first; - ERR_FAIL_COND_V(!ch, Size2()); - - Size2 ret(0, get_height()); - - if (ch->found) { - ret.x = ch->advance; - } - - return ret; -} - -float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only, bool p_outline) const { - if (!valid) { - return 0; - } - - const_cast<DynamicFontAtSize *>(this)->_update_char(p_char); - - 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, 0.0); - - float advance = 0.0; - - // use normal character size if there's no outline character - if (p_outline && !ch->found) { - FT_GlyphSlot slot = face->glyph; - int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT); - if (!error) { - error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); - if (!error) { - Character character = Character::not_found(); - character = const_cast<DynamicFontAtSize *>(this)->_bitmap_to_character(slot->bitmap, slot->bitmap_top, slot->bitmap_left, slot->advance.x / 64.0); - advance = character.advance; - } - } - } - - if (ch->found) { - ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= font->textures.size(), 0); - - if (!p_advance_only && ch->texture_idx != -1) { - Point2 cpos = p_pos; - cpos.x += ch->h_align; - cpos.y -= font->get_ascent(); - cpos.y += ch->v_align; - Color modulate = p_modulate; - if (FT_HAS_COLOR(face)) { - modulate.r = modulate.g = modulate.b = 1.0; - } - RID texture = font->textures[ch->texture_idx].texture->get_rid(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), texture, ch->rect_uv, modulate, false, RID(), RID(), Color(1, 1, 1, 1), false); - } - - advance = ch->advance; - } - - return advance; -} - -unsigned long DynamicFontAtSize::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - - if (f->get_position() != offset) { - f->seek(offset); - } - - if (count == 0) { - return 0; - } - - return f->get_buffer(buffer, count); -} - -void DynamicFontAtSize::_ft_stream_close(FT_Stream stream) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - f->close(); - memdelete(f); -} - -DynamicFontAtSize::Character DynamicFontAtSize::Character::not_found() { - Character ch; - ch.texture_idx = -1; - ch.advance = 0; - ch.h_align = 0; - ch.v_align = 0; - ch.found = false; - return ch; -} - -DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyph(int p_color_size, Image::Format p_image_format, int p_width, int p_height) { - TexturePosition ret; - ret.index = -1; - ret.x = 0; - ret.y = 0; - - int mw = p_width; - int mh = p_height; - - for (int i = 0; i < textures.size(); i++) { - const CharTexture &ct = textures[i]; - - if (ct.texture->get_format() != p_image_format) { - continue; - } - - if (mw > ct.texture_size || mh > ct.texture_size) { //too big for this texture - continue; - } - - ret.y = 0x7FFFFFFF; - ret.x = 0; - - for (int j = 0; j < ct.texture_size - mw; j++) { - int max_y = 0; - - for (int k = j; k < j + mw; k++) { - int y = ct.offsets[k]; - if (y > max_y) { - max_y = y; - } - } - - if (max_y < ret.y) { - ret.y = max_y; - ret.x = j; - } - } - - if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_size) { - continue; //fail, could not fit it here - } - - ret.index = i; - break; - } - - if (ret.index == -1) { - //could not find texture to fit, create one - ret.x = 0; - ret.y = 0; - - int texsize = MAX(id.size * oversampling * 8, 256); - if (mw > texsize) { - texsize = mw; //special case, adapt to it? - } - if (mh > texsize) { - texsize = mh; //special case, adapt to it? - } - - texsize = next_power_of_2(texsize); - - texsize = MIN(texsize, 4096); - - CharTexture tex; - tex.texture_size = texsize; - tex.imgdata.resize(texsize * texsize * p_color_size); //grayscale alpha - - { - //zero texture - uint8_t *w = tex.imgdata.ptrw(); - ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret); - for (int i = 0; i < texsize * texsize * p_color_size; i++) { - w[i] = 0; - } - } - tex.offsets.resize(texsize); - for (int i = 0; i < texsize; i++) { //zero offsets - tex.offsets.write[i] = 0; - } - - textures.push_back(tex); - ret.index = textures.size() - 1; - } - - return ret; -} - -DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap bitmap, int yofs, int xofs, float advance) { - int w = bitmap.width; - int h = bitmap.rows; - - int mw = w + rect_margin * 2; - int mh = h + rect_margin * 2; - - ERR_FAIL_COND_V(mw > 4096, Character::not_found()); - ERR_FAIL_COND_V(mh > 4096, Character::not_found()); - - int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2; - Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8; - - TexturePosition tex_pos = _find_texture_pos_for_glyph(color_size, require_format, mw, mh); - ERR_FAIL_COND_V(tex_pos.index < 0, Character::not_found()); - - //fit character in char texture - - CharTexture &tex = textures.write[tex_pos.index]; - - { - uint8_t *wr = tex.imgdata.ptrw(); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - int ofs = ((i + tex_pos.y + rect_margin) * tex.texture_size + j + tex_pos.x + rect_margin) * color_size; - ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), Character::not_found()); - switch (bitmap.pixel_mode) { - case FT_PIXEL_MODE_MONO: { - int byte = i * bitmap.pitch + (j >> 3); - int bit = 1 << (7 - (j % 8)); - wr[ofs + 0] = 255; //grayscale as 1 - wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0; - } break; - case FT_PIXEL_MODE_GRAY: - wr[ofs + 0] = 255; //grayscale as 1 - wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j]; - break; - case FT_PIXEL_MODE_BGRA: { - int ofs_color = i * bitmap.pitch + (j << 2); - wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; - wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; - wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; - wr[ofs + 3] = bitmap.buffer[ofs_color + 3]; - } break; - // TODO: FT_PIXEL_MODE_LCD - default: - ERR_FAIL_V_MSG(Character::not_found(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + "."); - break; - } - } - } - } - - //blit to image and texture - { - Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata)); - - if (tex.texture.is_null()) { - tex.texture.instance(); - tex.texture->create_from_image(img); - } else { - tex.texture->update(img); //update - } - } - - // update height array - - for (int k = tex_pos.x; k < tex_pos.x + mw; k++) { - tex.offsets.write[k] = tex_pos.y + mh; - } - - Character chr; - chr.h_align = xofs * scale_color_font / oversampling; - chr.v_align = ascent - (yofs * scale_color_font / oversampling); // + ascent - descent; - chr.advance = advance * scale_color_font / oversampling; - chr.texture_idx = tex_pos.index; - chr.found = true; - - chr.rect_uv = Rect2(tex_pos.x + rect_margin, tex_pos.y + rect_margin, w, h); - chr.rect = chr.rect_uv; - chr.rect.position /= oversampling; - chr.rect.size = chr.rect.size * scale_color_font / oversampling; - return chr; -} - -DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(CharType p_char) { - Character ret = Character::not_found(); - - if (FT_Load_Char(face, p_char, FT_LOAD_NO_BITMAP | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)) != 0) { - return ret; - } - - FT_Stroker stroker; - if (FT_Stroker_New(library, &stroker) != 0) { - return ret; - } - - FT_Stroker_Set(stroker, (int)(id.outline_size * oversampling * 64.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0); - FT_Glyph glyph; - FT_BitmapGlyph glyph_bitmap; - - if (FT_Get_Glyph(face->glyph, &glyph) != 0) { - goto cleanup_stroker; - } - if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) { - goto cleanup_glyph; - } - if (FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, nullptr, 1) != 0) { - goto cleanup_glyph; - } - - glyph_bitmap = (FT_BitmapGlyph)glyph; - ret = _bitmap_to_character(glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, glyph->advance.x / 65536.0); - -cleanup_glyph: - FT_Done_Glyph(glyph); -cleanup_stroker: - FT_Stroker_Done(stroker); - return ret; -} - -void DynamicFontAtSize::_update_char(CharType p_char) { - if (char_map.has(p_char)) { - return; - } - - _THREAD_SAFE_METHOD_ - - Character character = Character::not_found(); - - FT_GlyphSlot slot = face->glyph; - - if (FT_Get_Char_Index(face, p_char) == 0) { - char_map[p_char] = character; - return; - } - - int ft_hinting; - - switch (font->hinting) { - case DynamicFontData::HINTING_NONE: - ft_hinting = FT_LOAD_NO_HINTING; - break; - case DynamicFontData::HINTING_LIGHT: - ft_hinting = FT_LOAD_TARGET_LIGHT; - break; - default: - ft_hinting = FT_LOAD_TARGET_NORMAL; - break; - } - - int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting); - if (error) { - char_map[p_char] = character; - return; - } - - if (id.outline_size > 0) { - character = _make_outline_char(p_char); - } else { - error = FT_Render_Glyph(face->glyph, font->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); - if (!error) { - character = _bitmap_to_character(slot->bitmap, slot->bitmap_top, slot->bitmap_left, slot->advance.x / 64.0); - } - } - - char_map[p_char] = character; -} - -void DynamicFontAtSize::update_oversampling() { - if (oversampling == font_oversampling || !valid) { - return; - } - - FT_Done_FreeType(library); - textures.clear(); - char_map.clear(); - oversampling = font_oversampling; - valid = false; - _load(); -} - -DynamicFontAtSize::DynamicFontAtSize() { - valid = false; - rect_margin = 1; - ascent = 1; - descent = 1; - linegap = 1; - oversampling = font_oversampling; - scale_color_font = 1; -} - -DynamicFontAtSize::~DynamicFontAtSize() { - if (valid) { - FT_Done_FreeType(library); - } - font->size_cache.erase(id); - font.unref(); -} - -///////////////////////// - -void DynamicFont::_reload_cache() { - ERR_FAIL_COND(cache_id.size < 1); - if (!data.is_valid()) { - data_at_size.unref(); - outline_data_at_size.unref(); - fallbacks.resize(0); - fallback_data_at_size.resize(0); - fallback_outline_data_at_size.resize(0); - return; - } - - data_at_size = data->_get_dynamic_font_at_size(cache_id); - if (outline_cache_id.outline_size > 0) { - outline_data_at_size = data->_get_dynamic_font_at_size(outline_cache_id); - fallback_outline_data_at_size.resize(fallback_data_at_size.size()); - } else { - outline_data_at_size.unref(); - fallback_outline_data_at_size.resize(0); - } - - for (int i = 0; i < fallbacks.size(); i++) { - fallback_data_at_size.write[i] = fallbacks.write[i]->_get_dynamic_font_at_size(cache_id); - if (outline_cache_id.outline_size > 0) { - fallback_outline_data_at_size.write[i] = fallbacks.write[i]->_get_dynamic_font_at_size(outline_cache_id); - } - } - - emit_changed(); - _change_notify(); -} - -void DynamicFont::set_font_data(const Ref<DynamicFontData> &p_data) { - data = p_data; - _reload_cache(); - - emit_changed(); - _change_notify(); -} - -Ref<DynamicFontData> DynamicFont::get_font_data() const { - return data; -} - -void DynamicFont::set_size(int p_size) { - if (cache_id.size == p_size) { - return; - } - cache_id.size = p_size; - outline_cache_id.size = p_size; - _reload_cache(); -} - -int DynamicFont::get_size() const { - return cache_id.size; -} - -void DynamicFont::set_outline_size(int p_size) { - if (outline_cache_id.outline_size == p_size) { - return; - } - ERR_FAIL_COND(p_size < 0 || p_size > UINT8_MAX); - outline_cache_id.outline_size = p_size; - _reload_cache(); -} - -int DynamicFont::get_outline_size() const { - return outline_cache_id.outline_size; -} - -void DynamicFont::set_outline_color(Color p_color) { - if (p_color != outline_color) { - outline_color = p_color; - emit_changed(); - _change_notify(); - } -} - -Color DynamicFont::get_outline_color() const { - return outline_color; -} - -bool DynamicFontData::is_antialiased() const { - return antialiased; -} - -void DynamicFontData::set_antialiased(bool p_antialiased) { - if (antialiased == p_antialiased) { - return; - } - antialiased = p_antialiased; -} - -DynamicFontData::Hinting DynamicFontData::get_hinting() const { - return hinting; -} - -void DynamicFontData::set_hinting(Hinting p_hinting) { - if (hinting == p_hinting) { - return; - } - hinting = p_hinting; -} - -int DynamicFont::get_spacing(int p_type) const { - if (p_type == SPACING_TOP) { - return spacing_top; - } else if (p_type == SPACING_BOTTOM) { - return spacing_bottom; - } else if (p_type == SPACING_CHAR) { - return spacing_char; - } else if (p_type == SPACING_SPACE) { - return spacing_space; - } - - return 0; -} - -void DynamicFont::set_spacing(int p_type, int p_value) { - if (p_type == SPACING_TOP) { - spacing_top = p_value; - } else if (p_type == SPACING_BOTTOM) { - spacing_bottom = p_value; - } else if (p_type == SPACING_CHAR) { - spacing_char = p_value; - } else if (p_type == SPACING_SPACE) { - spacing_space = p_value; - } - - emit_changed(); - _change_notify(); -} - -float DynamicFont::get_height() const { - if (!data_at_size.is_valid()) { - return 1; - } - - return data_at_size->get_height() + spacing_top + spacing_bottom; -} - -float DynamicFont::get_ascent() const { - if (!data_at_size.is_valid()) { - return 1; - } - - return data_at_size->get_ascent() + spacing_top; -} - -float DynamicFont::get_descent() const { - if (!data_at_size.is_valid()) { - return 1; - } - - return data_at_size->get_descent() + spacing_bottom; -} - -float DynamicFont::get_underline_position() const { - if (!data_at_size.is_valid()) { - return 2; - } - - return data_at_size->get_underline_position(); -} - -float DynamicFont::get_underline_thickness() const { - if (!data_at_size.is_valid()) { - return 1; - } - - return data_at_size->get_underline_thickness(); -} - -Size2 DynamicFont::get_char_size(CharType p_char, CharType p_next) const { - if (!data_at_size.is_valid()) { - return Size2(1, 1); - } - - Size2 ret = data_at_size->get_char_size(p_char, p_next, fallback_data_at_size); - if (p_char == ' ') { - ret.width += spacing_space + spacing_char; - } else if (p_next) { - ret.width += spacing_char; - } - - return ret; -} - -bool DynamicFont::is_distance_field_hint() const { - return false; -} - -bool DynamicFont::has_outline() const { - return outline_cache_id.outline_size > 0; -} - -float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const { - const Ref<DynamicFontAtSize> &font_at_size = p_outline && outline_cache_id.outline_size > 0 ? outline_data_at_size : data_at_size; - - if (!font_at_size.is_valid()) { - return 0; - } - - const Vector<Ref<DynamicFontAtSize>> &fallbacks = p_outline && outline_cache_id.outline_size > 0 ? fallback_outline_data_at_size : fallback_data_at_size; - Color color = p_outline && outline_cache_id.outline_size > 0 ? p_modulate * outline_color : p_modulate; - - // If requested outline draw, but no outline is present, simply return advance without drawing anything - bool advance_only = p_outline && outline_cache_id.outline_size == 0; - return font_at_size->draw_char(p_canvas_item, p_pos, p_char, p_next, color, fallbacks, advance_only, p_outline) + spacing_char; -} - -void DynamicFont::set_fallback(int p_idx, const Ref<DynamicFontData> &p_data) { - ERR_FAIL_COND(p_data.is_null()); - ERR_FAIL_INDEX(p_idx, fallbacks.size()); - fallbacks.write[p_idx] = p_data; - fallback_data_at_size.write[p_idx] = fallbacks.write[p_idx]->_get_dynamic_font_at_size(cache_id); -} - -void DynamicFont::add_fallback(const Ref<DynamicFontData> &p_data) { - ERR_FAIL_COND(p_data.is_null()); - fallbacks.push_back(p_data); - fallback_data_at_size.push_back(fallbacks.write[fallbacks.size() - 1]->_get_dynamic_font_at_size(cache_id)); //const.. - if (outline_cache_id.outline_size > 0) { - fallback_outline_data_at_size.push_back(fallbacks.write[fallbacks.size() - 1]->_get_dynamic_font_at_size(outline_cache_id)); - } - - _change_notify(); - emit_changed(); - _change_notify(); -} - -int DynamicFont::get_fallback_count() const { - return fallbacks.size(); -} - -Ref<DynamicFontData> DynamicFont::get_fallback(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, fallbacks.size(), Ref<DynamicFontData>()); - - return fallbacks[p_idx]; -} - -void DynamicFont::remove_fallback(int p_idx) { - ERR_FAIL_INDEX(p_idx, fallbacks.size()); - fallbacks.remove(p_idx); - fallback_data_at_size.remove(p_idx); - emit_changed(); - _change_notify(); -} - -bool DynamicFont::_set(const StringName &p_name, const Variant &p_value) { - String str = p_name; - if (str.begins_with("fallback/")) { - int idx = str.get_slicec('/', 1).to_int(); - Ref<DynamicFontData> fd = p_value; - - if (fd.is_valid()) { - if (idx == fallbacks.size()) { - add_fallback(fd); - return true; - } else if (idx >= 0 && idx < fallbacks.size()) { - set_fallback(idx, fd); - return true; - } else { - return false; - } - } else if (idx >= 0 && idx < fallbacks.size()) { - remove_fallback(idx); - return true; - } - } - - return false; -} - -bool DynamicFont::_get(const StringName &p_name, Variant &r_ret) const { - String str = p_name; - if (str.begins_with("fallback/")) { - int idx = str.get_slicec('/', 1).to_int(); - - if (idx == fallbacks.size()) { - r_ret = Ref<DynamicFontData>(); - return true; - } else if (idx >= 0 && idx < fallbacks.size()) { - r_ret = get_fallback(idx); - return true; - } - } - - return false; -} - -void DynamicFont::_get_property_list(List<PropertyInfo> *p_list) const { - for (int i = 0; i < fallbacks.size(); i++) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "fallback/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData")); - } - - p_list->push_back(PropertyInfo(Variant::OBJECT, "fallback/" + itos(fallbacks.size()), PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData")); -} - -void DynamicFont::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_font_data", "data"), &DynamicFont::set_font_data); - ClassDB::bind_method(D_METHOD("get_font_data"), &DynamicFont::get_font_data); - - ClassDB::bind_method(D_METHOD("set_size", "data"), &DynamicFont::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &DynamicFont::get_size); - - ClassDB::bind_method(D_METHOD("set_outline_size", "size"), &DynamicFont::set_outline_size); - ClassDB::bind_method(D_METHOD("get_outline_size"), &DynamicFont::get_outline_size); - - ClassDB::bind_method(D_METHOD("set_outline_color", "color"), &DynamicFont::set_outline_color); - ClassDB::bind_method(D_METHOD("get_outline_color"), &DynamicFont::get_outline_color); - - ClassDB::bind_method(D_METHOD("set_spacing", "type", "value"), &DynamicFont::set_spacing); - ClassDB::bind_method(D_METHOD("get_spacing", "type"), &DynamicFont::get_spacing); - - ClassDB::bind_method(D_METHOD("add_fallback", "data"), &DynamicFont::add_fallback); - ClassDB::bind_method(D_METHOD("set_fallback", "idx", "data"), &DynamicFont::set_fallback); - ClassDB::bind_method(D_METHOD("get_fallback", "idx"), &DynamicFont::get_fallback); - ClassDB::bind_method(D_METHOD("remove_fallback", "idx"), &DynamicFont::remove_fallback); - ClassDB::bind_method(D_METHOD("get_fallback_count"), &DynamicFont::get_fallback_count); - - ADD_GROUP("Settings", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,1024,1"), "set_outline_size", "get_outline_size"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_color"), "set_outline_color", "get_outline_color"); - ADD_GROUP("Extra Spacing", "extra_spacing"); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_top"), "set_spacing", "get_spacing", SPACING_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_bottom"), "set_spacing", "get_spacing", SPACING_BOTTOM); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_char"), "set_spacing", "get_spacing", SPACING_CHAR); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_space"), "set_spacing", "get_spacing", SPACING_SPACE); - ADD_GROUP("Font", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font_data", PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData"), "set_font_data", "get_font_data"); - - BIND_ENUM_CONSTANT(SPACING_TOP); - BIND_ENUM_CONSTANT(SPACING_BOTTOM); - BIND_ENUM_CONSTANT(SPACING_CHAR); - BIND_ENUM_CONSTANT(SPACING_SPACE); -} - -Mutex DynamicFont::dynamic_font_mutex; - -SelfList<DynamicFont>::List *DynamicFont::dynamic_fonts = nullptr; - -DynamicFont::DynamicFont() : - font_list(this) { - valid = false; - cache_id.size = 16; - outline_cache_id.size = 16; - spacing_top = 0; - spacing_bottom = 0; - spacing_char = 0; - spacing_space = 0; - outline_color = Color(1, 1, 1); - - MutexLock lock(dynamic_font_mutex); - dynamic_fonts->add(&font_list); -} - -DynamicFont::~DynamicFont() { - MutexLock lock(dynamic_font_mutex); - dynamic_fonts->remove(&font_list); -} - -void DynamicFont::initialize_dynamic_fonts() { - dynamic_fonts = memnew(SelfList<DynamicFont>::List()); -} - -void DynamicFont::finish_dynamic_fonts() { - memdelete(dynamic_fonts); - dynamic_fonts = nullptr; -} - -void DynamicFont::update_oversampling() { - Vector<Ref<DynamicFont>> changed; - { - MutexLock lock(dynamic_font_mutex); - - SelfList<DynamicFont> *E = dynamic_fonts->first(); - while (E) { - if (E->self()->data_at_size.is_valid()) { - E->self()->data_at_size->update_oversampling(); - - if (E->self()->outline_data_at_size.is_valid()) { - E->self()->outline_data_at_size->update_oversampling(); - } - - for (int i = 0; i < E->self()->fallback_data_at_size.size(); i++) { - if (E->self()->fallback_data_at_size[i].is_valid()) { - E->self()->fallback_data_at_size.write[i]->update_oversampling(); - - if (E->self()->has_outline() && E->self()->fallback_outline_data_at_size[i].is_valid()) { - E->self()->fallback_outline_data_at_size.write[i]->update_oversampling(); - } - } - } - - changed.push_back(Ref<DynamicFont>(E->self())); - } - - E = E->next(); - } - } - - for (int i = 0; i < changed.size(); i++) { - changed.write[i]->emit_changed(); - } -} - -///////////////////////// - -RES ResourceFormatLoaderDynamicFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { - if (r_error) { - *r_error = ERR_FILE_CANT_OPEN; - } - - Ref<DynamicFontData> dfont; - dfont.instance(); - dfont->set_font_path(p_path); - - if (r_error) { - *r_error = OK; - } - - return dfont; -} - -void ResourceFormatLoaderDynamicFont::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("ttf"); - p_extensions->push_back("otf"); -} - -bool ResourceFormatLoaderDynamicFont::handles_type(const String &p_type) const { - return (p_type == "DynamicFontData"); -} - -String ResourceFormatLoaderDynamicFont::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "ttf" || el == "otf") { - return "DynamicFontData"; - } - return ""; -} - -#endif diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h deleted file mode 100644 index 08ad20a92d..0000000000 --- a/scene/resources/dynamic_font.h +++ /dev/null @@ -1,314 +0,0 @@ -/*************************************************************************/ -/* dynamic_font.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef DYNAMIC_FONT_H -#define DYNAMIC_FONT_H - -#include "modules/modules_enabled.gen.h" -#ifdef MODULE_FREETYPE_ENABLED - -#include "core/io/resource_loader.h" -#include "core/os/mutex.h" -#include "core/os/thread_safe.h" -#include "core/pair.h" -#include "scene/resources/font.h" - -#include <ft2build.h> -#include FT_FREETYPE_H - -class DynamicFontAtSize; -class DynamicFont; - -class DynamicFontData : public Resource { - GDCLASS(DynamicFontData, Resource); - -public: - struct CacheID { - union { - struct { - uint32_t size : 16; - uint32_t outline_size : 8; - uint32_t unused : 8; - }; - uint32_t key; - }; - bool operator<(CacheID right) const; - CacheID() { - key = 0; - } - }; - - enum Hinting { - HINTING_NONE, - HINTING_LIGHT, - HINTING_NORMAL - }; - - bool is_antialiased() const; - void set_antialiased(bool p_antialiased); - Hinting get_hinting() const; - void set_hinting(Hinting p_hinting); - -private: - const uint8_t *font_mem; - int font_mem_size; - bool antialiased; - bool force_autohinter; - Hinting hinting; - - String font_path; - Map<CacheID, DynamicFontAtSize *> size_cache; - - friend class DynamicFontAtSize; - - friend class DynamicFont; - - Ref<DynamicFontAtSize> _get_dynamic_font_at_size(CacheID p_cache_id); - -protected: - static void _bind_methods(); - -public: - void set_font_ptr(const uint8_t *p_font_mem, int p_font_mem_size); - void set_font_path(const String &p_path); - String get_font_path() const; - void set_force_autohinter(bool p_force); - - DynamicFontData(); - ~DynamicFontData(); -}; - -VARIANT_ENUM_CAST(DynamicFontData::Hinting); - -class DynamicFontAtSize : public Reference { - GDCLASS(DynamicFontAtSize, Reference); - - _THREAD_SAFE_CLASS_ - - FT_Library library; /* handle to library */ - FT_Face face; /* handle to face object */ - FT_StreamRec stream; - - float ascent; - float descent; - float linegap; - float rect_margin; - float oversampling; - float scale_color_font; - float underline_position; - float underline_thickness; - - bool valid; - - struct CharTexture { - Vector<uint8_t> imgdata; - int texture_size; - Vector<int> offsets; - Ref<ImageTexture> texture; - }; - - Vector<CharTexture> textures; - - struct Character { - bool found; - int texture_idx; - Rect2 rect; - Rect2 rect_uv; - float v_align; - float h_align; - float advance; - - Character() { - texture_idx = 0; - v_align = 0; - } - - static Character not_found(); - }; - - struct TexturePosition { - int index; - int x; - int y; - }; - - 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); - 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); - - static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); - static void _ft_stream_close(FT_Stream stream); - - HashMap<CharType, Character> char_map; - - _FORCE_INLINE_ void _update_char(CharType p_char); - - friend class DynamicFontData; - Ref<DynamicFontData> font; - DynamicFontData::CacheID id; - - static HashMap<String, Vector<uint8_t>> _fontdata; - Error _load(); - -public: - static float font_oversampling; - - float get_height() const; - - float get_ascent() const; - float get_descent() const; - float get_underline_position() const; - float get_underline_thickness() const; - - Size2 get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const; - - float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only = false, bool p_outline = false) const; - - void set_texture_flags(uint32_t p_flags); - void update_oversampling(); - - DynamicFontAtSize(); - ~DynamicFontAtSize(); -}; - -/////////////// - -class DynamicFont : public Font { - GDCLASS(DynamicFont, Font); - -public: - enum SpacingType { - SPACING_TOP, - SPACING_BOTTOM, - SPACING_CHAR, - SPACING_SPACE - }; - -private: - Ref<DynamicFontData> data; - Ref<DynamicFontAtSize> data_at_size; - Ref<DynamicFontAtSize> outline_data_at_size; - - Vector<Ref<DynamicFontData>> fallbacks; - Vector<Ref<DynamicFontAtSize>> fallback_data_at_size; - Vector<Ref<DynamicFontAtSize>> fallback_outline_data_at_size; - - DynamicFontData::CacheID cache_id; - DynamicFontData::CacheID outline_cache_id; - - bool valid; - int spacing_top; - int spacing_bottom; - int spacing_char; - int spacing_space; - - Color outline_color; - -protected: - void _reload_cache(); - - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - - static void _bind_methods(); - -public: - void set_font_data(const Ref<DynamicFontData> &p_data); - Ref<DynamicFontData> get_font_data() const; - - void set_size(int p_size); - int get_size() const; - - void set_outline_size(int p_size); - int get_outline_size() const; - - void set_outline_color(Color p_color); - Color get_outline_color() const; - - bool get_use_mipmaps() const; - void set_use_mipmaps(bool p_enable); - - bool get_use_filter() const; - void set_use_filter(bool p_enable); - - int get_spacing(int p_type) const; - void set_spacing(int p_type, int p_value); - - void add_fallback(const Ref<DynamicFontData> &p_data); - void set_fallback(int p_idx, const Ref<DynamicFontData> &p_data); - int get_fallback_count() const; - Ref<DynamicFontData> get_fallback(int p_idx) const; - void remove_fallback(int p_idx); - - virtual float get_height() const; - - virtual float get_ascent() const; - virtual float get_descent() const; - virtual float get_underline_position() const; - virtual float get_underline_thickness() const; - - virtual Size2 get_char_size(CharType p_char, CharType p_next = 0) const; - - virtual bool is_distance_field_hint() const; - - virtual bool has_outline() const; - - virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const; - - SelfList<DynamicFont> font_list; - - static Mutex dynamic_font_mutex; - static SelfList<DynamicFont>::List *dynamic_fonts; - - static void initialize_dynamic_fonts(); - static void finish_dynamic_fonts(); - static void update_oversampling(); - - DynamicFont(); - ~DynamicFont(); -}; - -VARIANT_ENUM_CAST(DynamicFont::SpacingType); - -///////////// - -class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader { -public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; -}; - -#endif - -#endif diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 80ee0c148d..6f6af93848 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,9 @@ /*************************************************************************/ #include "environment.h" -#include "core/project_settings.h" + +#include "core/config/project_settings.h" +#include "core/core_string_names.h" #include "servers/rendering_server.h" #include "texture.h" @@ -37,136 +39,164 @@ RID Environment::get_rid() const { return environment; } +// Background + void Environment::set_background(BGMode p_bg) { bg_mode = p_bg; RS::get_singleton()->environment_set_background(environment, RS::EnvironmentBG(p_bg)); - _change_notify(); + notify_property_list_changed(); + if (bg_mode != BG_SKY) { + set_fog_aerial_perspective(0.0); + } +} + +Environment::BGMode Environment::get_background() const { + return bg_mode; } void Environment::set_sky(const Ref<Sky> &p_sky) { bg_sky = p_sky; - RID sb_rid; if (bg_sky.is_valid()) { sb_rid = bg_sky->get_rid(); } - RS::get_singleton()->environment_set_sky(environment, sb_rid); } +Ref<Sky> Environment::get_sky() const { + return bg_sky; +} + void Environment::set_sky_custom_fov(float p_scale) { bg_sky_custom_fov = p_scale; RS::get_singleton()->environment_set_sky_custom_fov(environment, p_scale); } +float Environment::get_sky_custom_fov() const { + return bg_sky_custom_fov; +} + +void Environment::set_sky_rotation(const Vector3 &p_rotation) { + bg_sky_rotation = p_rotation; + RS::get_singleton()->environment_set_sky_orientation(environment, Basis(p_rotation)); +} + +Vector3 Environment::get_sky_rotation() const { + return bg_sky_rotation; +} + void Environment::set_bg_color(const Color &p_color) { bg_color = p_color; RS::get_singleton()->environment_set_bg_color(environment, p_color); } +Color Environment::get_bg_color() const { + return bg_color; +} + void Environment::set_bg_energy(float p_energy) { bg_energy = p_energy; RS::get_singleton()->environment_set_bg_energy(environment, p_energy); } +float Environment::get_bg_energy() const { + return bg_energy; +} + void Environment::set_canvas_max_layer(int p_max_layer) { bg_canvas_max_layer = p_max_layer; RS::get_singleton()->environment_set_canvas_max_layer(environment, p_max_layer); } -void Environment::set_ambient_light_color(const Color &p_color) { - ambient_color = p_color; - RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color); -} - -void Environment::set_ambient_light_energy(float p_energy) { - ambient_energy = p_energy; - RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color); -} - -void Environment::set_ambient_light_sky_contribution(float p_energy) { - ambient_sky_contribution = p_energy; - RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color); +int Environment::get_canvas_max_layer() const { + return bg_canvas_max_layer; } -void Environment::set_camera_feed_id(int p_camera_feed_id) { - camera_feed_id = p_camera_feed_id; +void Environment::set_camera_feed_id(int p_id) { + bg_camera_feed_id = p_id; // FIXME: Disabled during Vulkan refactoring, should be ported. #if 0 RS::get_singleton()->environment_set_camera_feed_id(environment, camera_feed_id); #endif -}; - -void Environment::set_ambient_source(AmbientSource p_source) { - ambient_source = p_source; - RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color); } -Environment::AmbientSource Environment::get_ambient_source() const { - return ambient_source; +int Environment::get_camera_feed_id() const { + return bg_camera_feed_id; } -void Environment::set_reflection_source(ReflectionSource p_source) { - reflection_source = p_source; - RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color); -} +// Ambient light -Environment::ReflectionSource Environment::get_reflection_source() const { - return reflection_source; +void Environment::set_ambient_light_color(const Color &p_color) { + ambient_color = p_color; + _update_ambient_light(); } -Environment::BGMode Environment::get_background() const { - return bg_mode; +Color Environment::get_ambient_light_color() const { + return ambient_color; } -Ref<Sky> Environment::get_sky() const { - return bg_sky; +void Environment::set_ambient_source(AmbientSource p_source) { + ambient_source = p_source; + _update_ambient_light(); + notify_property_list_changed(); } -float Environment::get_sky_custom_fov() const { - return bg_sky_custom_fov; +Environment::AmbientSource Environment::get_ambient_source() const { + return ambient_source; } -void Environment::set_sky_rotation(const Vector3 &p_rotation) { - sky_rotation = p_rotation; - RS::get_singleton()->environment_set_sky_orientation(environment, Basis(p_rotation)); +void Environment::set_ambient_light_energy(float p_energy) { + ambient_energy = p_energy; + _update_ambient_light(); } -Vector3 Environment::get_sky_rotation() const { - return sky_rotation; +float Environment::get_ambient_light_energy() const { + return ambient_energy; } -Color Environment::get_bg_color() const { - return bg_color; +void Environment::set_ambient_light_sky_contribution(float p_ratio) { + ambient_sky_contribution = p_ratio; + _update_ambient_light(); } -float Environment::get_bg_energy() const { - return bg_energy; +float Environment::get_ambient_light_sky_contribution() const { + return ambient_sky_contribution; } -int Environment::get_canvas_max_layer() const { - return bg_canvas_max_layer; +void Environment::set_reflection_source(ReflectionSource p_source) { + reflection_source = p_source; + _update_ambient_light(); + notify_property_list_changed(); } -Color Environment::get_ambient_light_color() const { - return ambient_color; +Environment::ReflectionSource Environment::get_reflection_source() const { + return reflection_source; } -float Environment::get_ambient_light_energy() const { - return ambient_energy; +void Environment::set_ao_color(const Color &p_color) { + ao_color = p_color; + _update_ambient_light(); } -float Environment::get_ambient_light_sky_contribution() const { - return ambient_sky_contribution; +Color Environment::get_ao_color() const { + return ao_color; } -int Environment::get_camera_feed_id() const { - return camera_feed_id; +void Environment::_update_ambient_light() { + RS::get_singleton()->environment_set_ambient_light( + environment, + ambient_color, + RS::EnvironmentAmbientSource(ambient_source), + ambient_energy, + ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), + ao_color); } +// Tonemap + void Environment::set_tonemapper(ToneMapper p_tone_mapper) { tone_mapper = p_tone_mapper; - RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); + _update_tonemap(); } Environment::ToneMapper Environment::get_tonemapper() const { @@ -175,7 +205,7 @@ Environment::ToneMapper Environment::get_tonemapper() const { void Environment::set_tonemap_exposure(float p_exposure) { tonemap_exposure = p_exposure; - RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); + _update_tonemap(); } float Environment::get_tonemap_exposure() const { @@ -184,44 +214,44 @@ float Environment::get_tonemap_exposure() const { void Environment::set_tonemap_white(float p_white) { tonemap_white = p_white; - RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); + _update_tonemap(); } float Environment::get_tonemap_white() const { return tonemap_white; } -void Environment::set_tonemap_auto_exposure(bool p_enabled) { - tonemap_auto_exposure = p_enabled; - RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); - _change_notify(); -} - -bool Environment::get_tonemap_auto_exposure() const { - return tonemap_auto_exposure; +void Environment::set_tonemap_auto_exposure_enabled(bool p_enabled) { + tonemap_auto_exposure_enabled = p_enabled; + _update_tonemap(); + notify_property_list_changed(); } -void Environment::set_tonemap_auto_exposure_max(float p_auto_exposure_max) { - tonemap_auto_exposure_max = p_auto_exposure_max; - RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); -} - -float Environment::get_tonemap_auto_exposure_max() const { - return tonemap_auto_exposure_max; +bool Environment::is_tonemap_auto_exposure_enabled() const { + return tonemap_auto_exposure_enabled; } void Environment::set_tonemap_auto_exposure_min(float p_auto_exposure_min) { tonemap_auto_exposure_min = p_auto_exposure_min; - RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); + _update_tonemap(); } float Environment::get_tonemap_auto_exposure_min() const { return tonemap_auto_exposure_min; } +void Environment::set_tonemap_auto_exposure_max(float p_auto_exposure_max) { + tonemap_auto_exposure_max = p_auto_exposure_max; + _update_tonemap(); +} + +float Environment::get_tonemap_auto_exposure_max() const { + return tonemap_auto_exposure_max; +} + void Environment::set_tonemap_auto_exposure_speed(float p_auto_exposure_speed) { tonemap_auto_exposure_speed = p_auto_exposure_speed; - RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); + _update_tonemap(); } float Environment::get_tonemap_auto_exposure_speed() const { @@ -230,144 +260,32 @@ float Environment::get_tonemap_auto_exposure_speed() const { void Environment::set_tonemap_auto_exposure_grey(float p_auto_exposure_grey) { tonemap_auto_exposure_grey = p_auto_exposure_grey; - RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); + _update_tonemap(); } float Environment::get_tonemap_auto_exposure_grey() const { return tonemap_auto_exposure_grey; } -void Environment::set_adjustment_enable(bool p_enable) { - adjustment_enabled = p_enable; - RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID()); - _change_notify(); +void Environment::_update_tonemap() { + RS::get_singleton()->environment_set_tonemap( + environment, + RS::EnvironmentToneMapper(tone_mapper), + tonemap_exposure, + tonemap_white, + tonemap_auto_exposure_enabled, + tonemap_auto_exposure_min, + tonemap_auto_exposure_max, + tonemap_auto_exposure_speed, + tonemap_auto_exposure_grey); } -bool Environment::is_adjustment_enabled() const { - return adjustment_enabled; -} +// SSR -void Environment::set_adjustment_brightness(float p_brightness) { - adjustment_brightness = p_brightness; - RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID()); -} - -float Environment::get_adjustment_brightness() const { - return adjustment_brightness; -} - -void Environment::set_adjustment_contrast(float p_contrast) { - adjustment_contrast = p_contrast; - RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID()); -} - -float Environment::get_adjustment_contrast() const { - return adjustment_contrast; -} - -void Environment::set_adjustment_saturation(float p_saturation) { - adjustment_saturation = p_saturation; - RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID()); -} - -float Environment::get_adjustment_saturation() const { - return adjustment_saturation; -} - -void Environment::set_adjustment_color_correction(const Ref<Texture2D> &p_ramp) { - adjustment_color_correction = p_ramp; - RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID()); -} - -Ref<Texture2D> Environment::get_adjustment_color_correction() const { - return adjustment_color_correction; -} - -void Environment::_validate_property(PropertyInfo &property) const { - if (property.name == "sky" || property.name == "sky_custom_fov" || property.name == "sky_rotation" || property.name == "ambient_light/sky_contribution") { - if (bg_mode != BG_SKY && ambient_source != AMBIENT_SOURCE_SKY && reflection_source != REFLECTION_SOURCE_SKY) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; - } - } - - if (property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; - } - - if (property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; - } - - if (property.name == "background_color") { - if (bg_mode != BG_COLOR && ambient_source != AMBIENT_SOURCE_COLOR) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; - } - } - - if (property.name == "background_canvas_max_layer") { - if (bg_mode != BG_CANVAS) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; - } - } - - 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_", - "ss_reflections_", - "ssao_", - "glow_", - "adjustment_", - nullptr - - }; - - static const char *high_end_prefixes[] = { - "auto_exposure_", - "tonemap_", - "ss_reflections_", - "ssao_", - nullptr - - }; - - const char **prefixes = hide_prefixes; - while (*prefixes) { - String prefix = String(*prefixes); - - String enabled = prefix + "enabled"; - if (property.name.begins_with(prefix) && property.name != enabled && !bool(get(enabled))) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; - return; - } - - prefixes++; - } - - if (RenderingServer::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) { - ssr_enabled = p_enable; - RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance); - _change_notify(); +void Environment::set_ssr_enabled(bool p_enabled) { + ssr_enabled = p_enabled; + _update_ssr(); + notify_property_list_changed(); } bool Environment::is_ssr_enabled() const { @@ -376,7 +294,7 @@ bool Environment::is_ssr_enabled() const { void Environment::set_ssr_max_steps(int p_steps) { ssr_max_steps = p_steps; - RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance); + _update_ssr(); } int Environment::get_ssr_max_steps() const { @@ -385,7 +303,7 @@ int Environment::get_ssr_max_steps() const { void Environment::set_ssr_fade_in(float p_fade_in) { ssr_fade_in = p_fade_in; - RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance); + _update_ssr(); } float Environment::get_ssr_fade_in() const { @@ -394,7 +312,7 @@ float Environment::get_ssr_fade_in() const { void Environment::set_ssr_fade_out(float p_fade_out) { ssr_fade_out = p_fade_out; - RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance); + _update_ssr(); } float Environment::get_ssr_fade_out() const { @@ -403,17 +321,29 @@ float Environment::get_ssr_fade_out() const { void Environment::set_ssr_depth_tolerance(float p_depth_tolerance) { ssr_depth_tolerance = p_depth_tolerance; - RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance); + _update_ssr(); } float Environment::get_ssr_depth_tolerance() const { return ssr_depth_tolerance; } -void Environment::set_ssao_enabled(bool p_enable) { - ssao_enabled = p_enable; - RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); - _change_notify(); +void Environment::_update_ssr() { + RS::get_singleton()->environment_set_ssr( + environment, + ssr_enabled, + ssr_max_steps, + ssr_fade_in, + ssr_fade_out, + ssr_depth_tolerance); +} + +// SSAO + +void Environment::set_ssao_enabled(bool p_enabled) { + ssao_enabled = p_enabled; + _update_ssao(); + notify_property_list_changed(); } bool Environment::is_ssao_enabled() const { @@ -422,7 +352,7 @@ bool Environment::is_ssao_enabled() const { void Environment::set_ssao_radius(float p_radius) { ssao_radius = p_radius; - RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + _update_ssao(); } float Environment::get_ssao_radius() const { @@ -431,25 +361,52 @@ float Environment::get_ssao_radius() const { void Environment::set_ssao_intensity(float p_intensity) { ssao_intensity = p_intensity; - RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + _update_ssao(); } float Environment::get_ssao_intensity() const { return ssao_intensity; } -void Environment::set_ssao_bias(float p_bias) { - ssao_bias = p_bias; - RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); +void Environment::set_ssao_power(float p_power) { + ssao_power = p_power; + _update_ssao(); +} + +float Environment::get_ssao_power() const { + return ssao_power; +} + +void Environment::set_ssao_detail(float p_detail) { + ssao_detail = p_detail; + _update_ssao(); +} + +float Environment::get_ssao_detail() const { + return ssao_detail; +} + +void Environment::set_ssao_horizon(float p_horizon) { + ssao_horizon = p_horizon; + _update_ssao(); } -float Environment::get_ssao_bias() const { - return ssao_bias; +float Environment::get_ssao_horizon() const { + return ssao_horizon; +} + +void Environment::set_ssao_sharpness(float p_sharpness) { + ssao_sharpness = p_sharpness; + _update_ssao(); +} + +float Environment::get_ssao_sharpness() const { + return ssao_sharpness; } void Environment::set_ssao_direct_light_affect(float p_direct_light_affect) { ssao_direct_light_affect = p_direct_light_affect; - RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + _update_ssao(); } float Environment::get_ssao_direct_light_affect() const { @@ -458,72 +415,203 @@ float Environment::get_ssao_direct_light_affect() const { void Environment::set_ssao_ao_channel_affect(float p_ao_channel_affect) { ssao_ao_channel_affect = p_ao_channel_affect; - RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); + _update_ssao(); } float Environment::get_ssao_ao_channel_affect() const { return ssao_ao_channel_affect; } -void Environment::set_ao_color(const Color &p_color) { - ao_color = p_color; - RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color); +void Environment::_update_ssao() { + RS::get_singleton()->environment_set_ssao( + environment, + ssao_enabled, + ssao_radius, + ssao_intensity, + ssao_power, + ssao_detail, + ssao_horizon, + ssao_sharpness, + ssao_direct_light_affect, + ssao_ao_channel_affect); } -Color Environment::get_ao_color() const { - return ao_color; +// SDFGI + +void Environment::set_sdfgi_enabled(bool p_enabled) { + sdfgi_enabled = p_enabled; + _update_sdfgi(); +} + +bool Environment::is_sdfgi_enabled() const { + return sdfgi_enabled; +} + +void Environment::set_sdfgi_cascades(SDFGICascades p_cascades) { + sdfgi_cascades = p_cascades; + _update_sdfgi(); +} + +Environment::SDFGICascades Environment::get_sdfgi_cascades() const { + return sdfgi_cascades; +} + +void Environment::set_sdfgi_min_cell_size(float p_size) { + sdfgi_min_cell_size = p_size; + _update_sdfgi(); +} + +float Environment::get_sdfgi_min_cell_size() const { + return sdfgi_min_cell_size; +} + +void Environment::set_sdfgi_max_distance(float p_distance) { + p_distance /= 64.0; + int cc[3] = { 4, 6, 8 }; + int cascades = cc[sdfgi_cascades]; + for (int i = 0; i < cascades; i++) { + p_distance *= 0.5; //halve for each cascade + } + sdfgi_min_cell_size = p_distance; + _update_sdfgi(); +} + +float Environment::get_sdfgi_max_distance() const { + float md = sdfgi_min_cell_size; + md *= 64.0; + int cc[3] = { 4, 6, 8 }; + int cascades = cc[sdfgi_cascades]; + for (int i = 0; i < cascades; i++) { + md *= 2.0; + } + return md; +} + +void Environment::set_sdfgi_cascade0_distance(float p_distance) { + sdfgi_min_cell_size = p_distance / 64.0; + _update_sdfgi(); +} + +float Environment::get_sdfgi_cascade0_distance() const { + return sdfgi_min_cell_size * 64.0; +} + +void Environment::set_sdfgi_y_scale(SDFGIYScale p_y_scale) { + sdfgi_y_scale = p_y_scale; + _update_sdfgi(); +} + +Environment::SDFGIYScale Environment::get_sdfgi_y_scale() const { + return sdfgi_y_scale; +} + +void Environment::set_sdfgi_use_occlusion(bool p_enabled) { + sdfgi_use_occlusion = p_enabled; + _update_sdfgi(); +} + +bool Environment::is_sdfgi_using_occlusion() const { + return sdfgi_use_occlusion; +} + +void Environment::set_sdfgi_bounce_feedback(float p_amount) { + sdfgi_bounce_feedback = p_amount; + _update_sdfgi(); +} +float Environment::get_sdfgi_bounce_feedback() const { + return sdfgi_bounce_feedback; } -void Environment::set_ssao_blur(SSAOBlur p_blur) { - ssao_blur = p_blur; - RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); +void Environment::set_sdfgi_read_sky_light(bool p_enabled) { + sdfgi_read_sky_light = p_enabled; + _update_sdfgi(); } -Environment::SSAOBlur Environment::get_ssao_blur() const { - return ssao_blur; +bool Environment::is_sdfgi_reading_sky_light() const { + return sdfgi_read_sky_light; } -void Environment::set_ssao_edge_sharpness(float p_edge_sharpness) { - ssao_edge_sharpness = p_edge_sharpness; - RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness); +void Environment::set_sdfgi_energy(float p_energy) { + sdfgi_energy = p_energy; + _update_sdfgi(); } -float Environment::get_ssao_edge_sharpness() const { - return ssao_edge_sharpness; +float Environment::get_sdfgi_energy() const { + return sdfgi_energy; } +void Environment::set_sdfgi_normal_bias(float p_bias) { + sdfgi_normal_bias = p_bias; + _update_sdfgi(); +} + +float Environment::get_sdfgi_normal_bias() const { + return sdfgi_normal_bias; +} + +void Environment::set_sdfgi_probe_bias(float p_bias) { + sdfgi_probe_bias = p_bias; + _update_sdfgi(); +} + +float Environment::get_sdfgi_probe_bias() const { + return sdfgi_probe_bias; +} + +void Environment::_update_sdfgi() { + RS::get_singleton()->environment_set_sdfgi( + environment, + sdfgi_enabled, + RS::EnvironmentSDFGICascades(sdfgi_cascades), + sdfgi_min_cell_size, + RS::EnvironmentSDFGIYScale(sdfgi_y_scale), + sdfgi_use_occlusion, + sdfgi_bounce_feedback, + sdfgi_read_sky_light, + sdfgi_energy, + sdfgi_normal_bias, + sdfgi_probe_bias); +} + +// Glow + void Environment::set_glow_enabled(bool p_enabled) { glow_enabled = p_enabled; - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); - _change_notify(); + _update_glow(); + notify_property_list_changed(); } bool Environment::is_glow_enabled() const { return glow_enabled; } -void Environment::set_glow_level(int p_level, bool p_enabled) { +void Environment::set_glow_level(int p_level, float p_intensity) { ERR_FAIL_INDEX(p_level, RS::MAX_GLOW_LEVELS); - if (p_enabled) { - glow_levels |= (1 << p_level); - } else { - glow_levels &= ~(1 << p_level); - } + glow_levels.write[p_level] = p_intensity; + + _update_glow(); +} - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); +float Environment::get_glow_level(int p_level) const { + ERR_FAIL_INDEX_V(p_level, RS::MAX_GLOW_LEVELS, 0.0); + + return glow_levels[p_level]; } -bool Environment::is_glow_level_enabled(int p_level) const { - ERR_FAIL_INDEX_V(p_level, RS::MAX_GLOW_LEVELS, false); +void Environment::set_glow_normalized(bool p_normalized) { + glow_normalize_levels = p_normalized; + + _update_glow(); +} - return glow_levels & (1 << p_level); +bool Environment::is_glow_normalized() const { + return glow_normalize_levels; } void Environment::set_glow_intensity(float p_intensity) { glow_intensity = p_intensity; - - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); + _update_glow(); } float Environment::get_glow_intensity() const { @@ -532,7 +620,7 @@ float Environment::get_glow_intensity() const { void Environment::set_glow_strength(float p_strength) { glow_strength = p_strength; - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); + _update_glow(); } float Environment::get_glow_strength() const { @@ -541,7 +629,7 @@ float Environment::get_glow_strength() const { void Environment::set_glow_mix(float p_mix) { glow_mix = p_mix; - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); + _update_glow(); } float Environment::get_glow_mix() const { @@ -550,8 +638,7 @@ float Environment::get_glow_mix() const { void Environment::set_glow_bloom(float p_threshold) { glow_bloom = p_threshold; - - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); + _update_glow(); } float Environment::get_glow_bloom() const { @@ -560,9 +647,8 @@ float Environment::get_glow_bloom() const { void Environment::set_glow_blend_mode(GlowBlendMode p_mode) { glow_blend_mode = p_mode; - - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); - _change_notify(); + _update_glow(); + notify_property_list_changed(); } Environment::GlowBlendMode Environment::get_glow_blend_mode() const { @@ -571,159 +657,373 @@ Environment::GlowBlendMode Environment::get_glow_blend_mode() const { void Environment::set_glow_hdr_bleed_threshold(float p_threshold) { glow_hdr_bleed_threshold = p_threshold; - - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); + _update_glow(); } float Environment::get_glow_hdr_bleed_threshold() const { return glow_hdr_bleed_threshold; } +void Environment::set_glow_hdr_bleed_scale(float p_scale) { + glow_hdr_bleed_scale = p_scale; + _update_glow(); +} + +float Environment::get_glow_hdr_bleed_scale() const { + return glow_hdr_bleed_scale; +} + void Environment::set_glow_hdr_luminance_cap(float p_amount) { glow_hdr_luminance_cap = p_amount; - - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); + _update_glow(); } float Environment::get_glow_hdr_luminance_cap() const { return glow_hdr_luminance_cap; } -void Environment::set_glow_hdr_bleed_scale(float p_scale) { - glow_hdr_bleed_scale = p_scale; +void Environment::_update_glow() { + Vector<float> normalized_levels; + if (glow_normalize_levels) { + normalized_levels.resize(7); + float size = 0.0; + for (int i = 0; i < glow_levels.size(); i++) { + size += glow_levels[i]; + } + for (int i = 0; i < glow_levels.size(); i++) { + normalized_levels.write[i] = glow_levels[i] / size; + } + } else { + normalized_levels = glow_levels; + } - RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap); + RS::get_singleton()->environment_set_glow( + environment, + glow_enabled, + normalized_levels, + glow_intensity, + glow_strength, + glow_mix, + glow_bloom, + RS::EnvironmentGlowBlendMode(glow_blend_mode), + glow_hdr_bleed_threshold, + glow_hdr_bleed_scale, + glow_hdr_luminance_cap); } -float Environment::get_glow_hdr_bleed_scale() const { - return glow_hdr_bleed_scale; -} +// Fog void Environment::set_fog_enabled(bool p_enabled) { fog_enabled = p_enabled; - RS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount); - _change_notify(); + _update_fog(); + notify_property_list_changed(); } bool Environment::is_fog_enabled() const { return fog_enabled; } -void Environment::set_fog_color(const Color &p_color) { - fog_color = p_color; - RS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount); +void Environment::set_fog_light_color(const Color &p_light_color) { + fog_light_color = p_light_color; + _update_fog(); } - -Color Environment::get_fog_color() const { - return fog_color; +Color Environment::get_fog_light_color() const { + return fog_light_color; } - -void Environment::set_fog_sun_color(const Color &p_color) { - fog_sun_color = p_color; - RS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount); +void Environment::set_fog_light_energy(float p_amount) { + fog_light_energy = p_amount; + _update_fog(); } - -Color Environment::get_fog_sun_color() const { - return fog_sun_color; +float Environment::get_fog_light_energy() const { + return fog_light_energy; } - -void Environment::set_fog_sun_amount(float p_amount) { - fog_sun_amount = p_amount; - RS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount); +void Environment::set_fog_sun_scatter(float p_amount) { + fog_sun_scatter = p_amount; + _update_fog(); } - -float Environment::get_fog_sun_amount() const { - return fog_sun_amount; +float Environment::get_fog_sun_scatter() const { + return fog_sun_scatter; +} +void Environment::set_fog_density(float p_amount) { + fog_density = p_amount; + _update_fog(); +} +float Environment::get_fog_density() const { + return fog_density; +} +void Environment::set_fog_height(float p_amount) { + fog_height = p_amount; + _update_fog(); +} +float Environment::get_fog_height() const { + return fog_height; +} +void Environment::set_fog_height_density(float p_amount) { + fog_height_density = p_amount; + _update_fog(); +} +float Environment::get_fog_height_density() const { + return fog_height_density; } -void Environment::set_fog_depth_enabled(bool p_enabled) { - fog_depth_enabled = p_enabled; - RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve); +void Environment::set_fog_aerial_perspective(float p_aerial_perspective) { + fog_aerial_perspective = p_aerial_perspective; + _update_fog(); +} +float Environment::get_fog_aerial_perspective() const { + return fog_aerial_perspective; } -bool Environment::is_fog_depth_enabled() const { - return fog_depth_enabled; +void Environment::_update_fog() { + RS::get_singleton()->environment_set_fog( + environment, + fog_enabled, + fog_light_color, + fog_light_energy, + fog_sun_scatter, + fog_density, + fog_height, + fog_height_density, + fog_aerial_perspective); } -void Environment::set_fog_depth_begin(float p_distance) { - fog_depth_begin = p_distance; - RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve); +// Volumetric Fog + +void Environment::_update_volumetric_fog() { + RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_light, volumetric_fog_light_energy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, volumetric_fog_temporal_reproject, volumetric_fog_temporal_reproject_amount); } -float Environment::get_fog_depth_begin() const { - return fog_depth_begin; +void Environment::set_volumetric_fog_enabled(bool p_enable) { + volumetric_fog_enabled = p_enable; + _update_volumetric_fog(); + notify_property_list_changed(); } -void Environment::set_fog_depth_end(float p_distance) { - fog_depth_end = p_distance; - RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve); +bool Environment::is_volumetric_fog_enabled() const { + return volumetric_fog_enabled; +} +void Environment::set_volumetric_fog_density(float p_density) { + p_density = CLAMP(p_density, 0.0000001, 1.0); + volumetric_fog_density = p_density; + _update_volumetric_fog(); +} +float Environment::get_volumetric_fog_density() const { + return volumetric_fog_density; +} +void Environment::set_volumetric_fog_light(Color p_color) { + volumetric_fog_light = p_color; + _update_volumetric_fog(); +} +Color Environment::get_volumetric_fog_light() const { + return volumetric_fog_light; +} +void Environment::set_volumetric_fog_light_energy(float p_begin) { + volumetric_fog_light_energy = p_begin; + _update_volumetric_fog(); +} +float Environment::get_volumetric_fog_light_energy() const { + return volumetric_fog_light_energy; +} +void Environment::set_volumetric_fog_length(float p_length) { + volumetric_fog_length = p_length; + _update_volumetric_fog(); +} +float Environment::get_volumetric_fog_length() const { + return volumetric_fog_length; +} +void Environment::set_volumetric_fog_detail_spread(float p_detail_spread) { + volumetric_fog_detail_spread = p_detail_spread; + _update_volumetric_fog(); +} +float Environment::get_volumetric_fog_detail_spread() const { + return volumetric_fog_detail_spread; } -float Environment::get_fog_depth_end() const { - return fog_depth_end; +void Environment::set_volumetric_fog_gi_inject(float p_gi_inject) { + volumetric_fog_gi_inject = p_gi_inject; + _update_volumetric_fog(); +} +float Environment::get_volumetric_fog_gi_inject() const { + return volumetric_fog_gi_inject; } -void Environment::set_fog_depth_curve(float p_curve) { - fog_depth_curve = p_curve; - RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve); +void Environment::set_volumetric_fog_temporal_reprojection_enabled(bool p_enable) { + volumetric_fog_temporal_reproject = p_enable; + _update_volumetric_fog(); +} +bool Environment::is_volumetric_fog_temporal_reprojection_enabled() const { + return volumetric_fog_temporal_reproject; +} +void Environment::set_volumetric_fog_temporal_reprojection_amount(float p_amount) { + volumetric_fog_temporal_reproject_amount = p_amount; + _update_volumetric_fog(); } -float Environment::get_fog_depth_curve() const { - return fog_depth_curve; +float Environment::get_volumetric_fog_temporal_reprojection_amount() const { + return volumetric_fog_temporal_reproject_amount; } -void Environment::set_fog_transmit_enabled(bool p_enabled) { - fog_transmit_enabled = p_enabled; - RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve); +// Adjustment + +void Environment::set_adjustment_enabled(bool p_enabled) { + adjustment_enabled = p_enabled; + _update_adjustment(); + notify_property_list_changed(); } -bool Environment::is_fog_transmit_enabled() const { - return fog_transmit_enabled; +bool Environment::is_adjustment_enabled() const { + return adjustment_enabled; } -void Environment::set_fog_transmit_curve(float p_curve) { - fog_transmit_curve = p_curve; - RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve); +void Environment::set_adjustment_brightness(float p_brightness) { + adjustment_brightness = p_brightness; + _update_adjustment(); } -float Environment::get_fog_transmit_curve() const { - return fog_transmit_curve; +float Environment::get_adjustment_brightness() const { + return adjustment_brightness; } -void Environment::set_fog_height_enabled(bool p_enabled) { - fog_height_enabled = p_enabled; - RS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve); +void Environment::set_adjustment_contrast(float p_contrast) { + adjustment_contrast = p_contrast; + _update_adjustment(); } -bool Environment::is_fog_height_enabled() const { - return fog_height_enabled; +float Environment::get_adjustment_contrast() const { + return adjustment_contrast; } -void Environment::set_fog_height_min(float p_distance) { - fog_height_min = p_distance; - RS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve); +void Environment::set_adjustment_saturation(float p_saturation) { + adjustment_saturation = p_saturation; + _update_adjustment(); } -float Environment::get_fog_height_min() const { - return fog_height_min; +float Environment::get_adjustment_saturation() const { + return adjustment_saturation; } -void Environment::set_fog_height_max(float p_distance) { - fog_height_max = p_distance; - RS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve); +void Environment::set_adjustment_color_correction(Ref<Texture> p_color_correction) { + adjustment_color_correction = p_color_correction; + Ref<GradientTexture> grad_tex = p_color_correction; + if (grad_tex.is_valid()) { + if (!grad_tex->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &Environment::_update_adjustment))) { + grad_tex->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Environment::_update_adjustment)); + } + } + Ref<Texture2D> adjustment_texture_2d = adjustment_color_correction; + if (adjustment_texture_2d.is_valid()) { + use_1d_color_correction = true; + } else { + use_1d_color_correction = false; + } + _update_adjustment(); } -float Environment::get_fog_height_max() const { - return fog_height_max; +Ref<Texture> Environment::get_adjustment_color_correction() const { + return adjustment_color_correction; } -void Environment::set_fog_height_curve(float p_distance) { - fog_height_curve = p_distance; - RS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve); +void Environment::_update_adjustment() { + RID color_correction = adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID(); + + RS::get_singleton()->environment_set_adjustment( + environment, + adjustment_enabled, + adjustment_brightness, + adjustment_contrast, + adjustment_saturation, + use_1d_color_correction, + color_correction); } -float Environment::get_fog_height_curve() const { - return fog_height_curve; +// Private methods, constructor and destructor + +void Environment::_validate_property(PropertyInfo &property) const { + if (property.name == "sky" || property.name == "sky_custom_fov" || property.name == "sky_rotation" || property.name == "ambient_light/sky_contribution") { + if (bg_mode != BG_SKY && ambient_source != AMBIENT_SOURCE_SKY && reflection_source != REFLECTION_SOURCE_SKY) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } + + if (property.name == "fog_aerial_perspective") { + if (bg_mode != BG_SKY) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } + + if (property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + + if (property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + + if (property.name == "background_color") { + if (bg_mode != BG_COLOR && ambient_source != AMBIENT_SOURCE_COLOR) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } + + if (property.name == "background_canvas_max_layer") { + if (bg_mode != BG_CANVAS) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } + + if (property.name == "background_camera_feed_id") { + if (bg_mode != BG_CAMERA_FEED) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } + } + + static const char *hide_prefixes[] = { + "fog_", + "volumetric_fog_", + "auto_exposure_", + "ss_reflections_", + "ssao_", + "glow_", + "adjustment_", + nullptr + + }; + + static const char *high_end_prefixes[] = { + "auto_exposure_", + "tonemap_", + "ss_reflections_", + "ssao_", + nullptr + + }; + + const char **prefixes = hide_prefixes; + while (*prefixes) { + String prefix = String(*prefixes); + + String enabled = prefix + "enabled"; + if (property.name.begins_with(prefix) && property.name != enabled && !bool(get(enabled))) { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + return; + } + + prefixes++; + } + + if (RenderingServer::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++; + } + } } #ifndef DISABLE_DEPRECATED @@ -746,160 +1046,102 @@ bool Environment::_set(const StringName &p_name, const Variant &p_value) { #endif void Environment::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_background", "mode"), &Environment::set_background); - ClassDB::bind_method(D_METHOD("set_sky", "sky"), &Environment::set_sky); - ClassDB::bind_method(D_METHOD("set_sky_custom_fov", "scale"), &Environment::set_sky_custom_fov); - ClassDB::bind_method(D_METHOD("set_sky_rotation", "euler_radians"), &Environment::set_sky_rotation); - ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &Environment::set_bg_color); - ClassDB::bind_method(D_METHOD("set_bg_energy", "energy"), &Environment::set_bg_energy); - ClassDB::bind_method(D_METHOD("set_canvas_max_layer", "layer"), &Environment::set_canvas_max_layer); - 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("set_ambient_source", "source"), &Environment::set_ambient_source); - ClassDB::bind_method(D_METHOD("set_reflection_source", "source"), &Environment::set_reflection_source); + // Background + ClassDB::bind_method(D_METHOD("set_background", "mode"), &Environment::set_background); ClassDB::bind_method(D_METHOD("get_background"), &Environment::get_background); + ClassDB::bind_method(D_METHOD("set_sky", "sky"), &Environment::set_sky); ClassDB::bind_method(D_METHOD("get_sky"), &Environment::get_sky); + ClassDB::bind_method(D_METHOD("set_sky_custom_fov", "scale"), &Environment::set_sky_custom_fov); ClassDB::bind_method(D_METHOD("get_sky_custom_fov"), &Environment::get_sky_custom_fov); + ClassDB::bind_method(D_METHOD("set_sky_rotation", "euler_radians"), &Environment::set_sky_rotation); ClassDB::bind_method(D_METHOD("get_sky_rotation"), &Environment::get_sky_rotation); + ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &Environment::set_bg_color); ClassDB::bind_method(D_METHOD("get_bg_color"), &Environment::get_bg_color); + ClassDB::bind_method(D_METHOD("set_bg_energy", "energy"), &Environment::set_bg_energy); ClassDB::bind_method(D_METHOD("get_bg_energy"), &Environment::get_bg_energy); + ClassDB::bind_method(D_METHOD("set_canvas_max_layer", "layer"), &Environment::set_canvas_max_layer); ClassDB::bind_method(D_METHOD("get_canvas_max_layer"), &Environment::get_canvas_max_layer); - 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("set_camera_feed_id", "id"), &Environment::set_camera_feed_id); ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &Environment::get_camera_feed_id); - ClassDB::bind_method(D_METHOD("get_ambient_source"), &Environment::get_ambient_source); - ClassDB::bind_method(D_METHOD("get_reflection_source"), &Environment::get_reflection_source); - ClassDB::bind_method(D_METHOD("set_ao_color", "color"), &Environment::set_ao_color); - ClassDB::bind_method(D_METHOD("get_ao_color"), &Environment::get_ao_color); ADD_GROUP("Background", "background_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "background_mode", PROPERTY_HINT_ENUM, "Clear Color,Custom Color,Sky,Canvas,Keep,Camera Feed"), "set_background", "get_background"); - 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_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_bg_color", "get_bg_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "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("Sky", "sky_"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_sky_custom_fov", "get_sky_custom_fov"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation"), "set_sky_rotation", "get_sky_rotation"); + + // Ambient light + + ClassDB::bind_method(D_METHOD("set_ambient_light_color", "color"), &Environment::set_ambient_light_color); + ClassDB::bind_method(D_METHOD("get_ambient_light_color"), &Environment::get_ambient_light_color); + ClassDB::bind_method(D_METHOD("set_ambient_source", "source"), &Environment::set_ambient_source); + ClassDB::bind_method(D_METHOD("get_ambient_source"), &Environment::get_ambient_source); + ClassDB::bind_method(D_METHOD("set_ambient_light_energy", "energy"), &Environment::set_ambient_light_energy); + ClassDB::bind_method(D_METHOD("get_ambient_light_energy"), &Environment::get_ambient_light_energy); + ClassDB::bind_method(D_METHOD("set_ambient_light_sky_contribution", "ratio"), &Environment::set_ambient_light_sky_contribution); + ClassDB::bind_method(D_METHOD("get_ambient_light_sky_contribution"), &Environment::get_ambient_light_sky_contribution); + ClassDB::bind_method(D_METHOD("set_reflection_source", "source"), &Environment::set_reflection_source); + ClassDB::bind_method(D_METHOD("get_reflection_source"), &Environment::get_reflection_source); + ClassDB::bind_method(D_METHOD("set_ao_color", "color"), &Environment::set_ao_color); + ClassDB::bind_method(D_METHOD("get_ao_color"), &Environment::get_ao_color); + ADD_GROUP("Ambient Light", "ambient_light_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ambient_light_source", PROPERTY_HINT_ENUM, "Background,Disabled,Color,Sky"), "set_ambient_source", "get_ambient_source"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ambient_light_color"), "set_ambient_light_color", "get_ambient_light_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ambient_light_sky_contribution", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ambient_light_sky_contribution", "get_ambient_light_sky_contribution"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ambient_light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_ambient_light_energy", "get_ambient_light_energy"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ambient_light_occlusion_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ao_color", "get_ao_color"); + ADD_GROUP("Reflected Light", "reflected_light_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "reflected_light_source", PROPERTY_HINT_ENUM, "Background,Disabled,Sky"), "set_reflection_source", "get_reflection_source"); - ClassDB::bind_method(D_METHOD("set_fog_enabled", "enabled"), &Environment::set_fog_enabled); - ClassDB::bind_method(D_METHOD("is_fog_enabled"), &Environment::is_fog_enabled); - - ClassDB::bind_method(D_METHOD("set_fog_color", "color"), &Environment::set_fog_color); - ClassDB::bind_method(D_METHOD("get_fog_color"), &Environment::get_fog_color); - - ClassDB::bind_method(D_METHOD("set_fog_sun_color", "color"), &Environment::set_fog_sun_color); - ClassDB::bind_method(D_METHOD("get_fog_sun_color"), &Environment::get_fog_sun_color); - - ClassDB::bind_method(D_METHOD("set_fog_sun_amount", "amount"), &Environment::set_fog_sun_amount); - ClassDB::bind_method(D_METHOD("get_fog_sun_amount"), &Environment::get_fog_sun_amount); - - ClassDB::bind_method(D_METHOD("set_fog_depth_enabled", "enabled"), &Environment::set_fog_depth_enabled); - ClassDB::bind_method(D_METHOD("is_fog_depth_enabled"), &Environment::is_fog_depth_enabled); - - ClassDB::bind_method(D_METHOD("set_fog_depth_begin", "distance"), &Environment::set_fog_depth_begin); - ClassDB::bind_method(D_METHOD("get_fog_depth_begin"), &Environment::get_fog_depth_begin); - - ClassDB::bind_method(D_METHOD("set_fog_depth_end", "distance"), &Environment::set_fog_depth_end); - ClassDB::bind_method(D_METHOD("get_fog_depth_end"), &Environment::get_fog_depth_end); - - ClassDB::bind_method(D_METHOD("set_fog_depth_curve", "curve"), &Environment::set_fog_depth_curve); - ClassDB::bind_method(D_METHOD("get_fog_depth_curve"), &Environment::get_fog_depth_curve); - - ClassDB::bind_method(D_METHOD("set_fog_transmit_enabled", "enabled"), &Environment::set_fog_transmit_enabled); - ClassDB::bind_method(D_METHOD("is_fog_transmit_enabled"), &Environment::is_fog_transmit_enabled); - - ClassDB::bind_method(D_METHOD("set_fog_transmit_curve", "curve"), &Environment::set_fog_transmit_curve); - ClassDB::bind_method(D_METHOD("get_fog_transmit_curve"), &Environment::get_fog_transmit_curve); - - ClassDB::bind_method(D_METHOD("set_fog_height_enabled", "enabled"), &Environment::set_fog_height_enabled); - ClassDB::bind_method(D_METHOD("is_fog_height_enabled"), &Environment::is_fog_height_enabled); - - ClassDB::bind_method(D_METHOD("set_fog_height_min", "height"), &Environment::set_fog_height_min); - ClassDB::bind_method(D_METHOD("get_fog_height_min"), &Environment::get_fog_height_min); - - ClassDB::bind_method(D_METHOD("set_fog_height_max", "height"), &Environment::set_fog_height_max); - ClassDB::bind_method(D_METHOD("get_fog_height_max"), &Environment::get_fog_height_max); - - ClassDB::bind_method(D_METHOD("set_fog_height_curve", "curve"), &Environment::set_fog_height_curve); - ClassDB::bind_method(D_METHOD("get_fog_height_curve"), &Environment::get_fog_height_curve); - - ADD_GROUP("Fog", "fog_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_color"), "set_fog_color", "get_fog_color"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_sun_color"), "set_fog_sun_color", "get_fog_sun_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sun_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fog_sun_amount", "get_fog_sun_amount"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_depth_enabled"), "set_fog_depth_enabled", "is_fog_depth_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_begin", PROPERTY_HINT_RANGE, "0,4000,0.1"), "set_fog_depth_begin", "get_fog_depth_begin"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_end", PROPERTY_HINT_RANGE, "0,4000,0.1,or_greater"), "set_fog_depth_end", "get_fog_depth_end"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_curve", PROPERTY_HINT_EXP_EASING), "set_fog_depth_curve", "get_fog_depth_curve"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_transmit_enabled"), "set_fog_transmit_enabled", "is_fog_transmit_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_transmit_curve", PROPERTY_HINT_EXP_EASING), "set_fog_transmit_curve", "get_fog_transmit_curve"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_height_enabled"), "set_fog_height_enabled", "is_fog_height_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_min", PROPERTY_HINT_RANGE, "-4000,4000,0.1,or_lesser,or_greater"), "set_fog_height_min", "get_fog_height_min"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_max", PROPERTY_HINT_RANGE, "-4000,4000,0.1,or_lesser,or_greater"), "set_fog_height_max", "get_fog_height_max"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_curve", PROPERTY_HINT_EXP_EASING), "set_fog_height_curve", "get_fog_height_curve"); + // Tonemap ClassDB::bind_method(D_METHOD("set_tonemapper", "mode"), &Environment::set_tonemapper); ClassDB::bind_method(D_METHOD("get_tonemapper"), &Environment::get_tonemapper); - ClassDB::bind_method(D_METHOD("set_tonemap_exposure", "exposure"), &Environment::set_tonemap_exposure); ClassDB::bind_method(D_METHOD("get_tonemap_exposure"), &Environment::get_tonemap_exposure); - ClassDB::bind_method(D_METHOD("set_tonemap_white", "white"), &Environment::set_tonemap_white); ClassDB::bind_method(D_METHOD("get_tonemap_white"), &Environment::get_tonemap_white); - - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure", "auto_exposure"), &Environment::set_tonemap_auto_exposure); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure"), &Environment::get_tonemap_auto_exposure); - + ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_enabled", "enabled"), &Environment::set_tonemap_auto_exposure_enabled); + ClassDB::bind_method(D_METHOD("is_tonemap_auto_exposure_enabled"), &Environment::is_tonemap_auto_exposure_enabled); ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_max", "exposure_max"), &Environment::set_tonemap_auto_exposure_max); ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_max"), &Environment::get_tonemap_auto_exposure_max); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_min", "exposure_min"), &Environment::set_tonemap_auto_exposure_min); ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_min"), &Environment::get_tonemap_auto_exposure_min); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_speed", "exposure_speed"), &Environment::set_tonemap_auto_exposure_speed); ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_speed"), &Environment::get_tonemap_auto_exposure_speed); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_grey", "exposure_grey"), &Environment::set_tonemap_auto_exposure_grey); ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_grey"), &Environment::get_tonemap_auto_exposure_grey); ADD_GROUP("Tonemap", "tonemap_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,Aces"), "set_tonemapper", "get_tonemapper"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES"), "set_tonemapper", "get_tonemapper"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white"); ADD_GROUP("Auto Exposure", "auto_exposure_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_tonemap_auto_exposure", "get_tonemap_auto_exposure"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_tonemap_auto_exposure_enabled", "is_tonemap_auto_exposure_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_grey", "get_tonemap_auto_exposure_grey"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_min", "get_tonemap_auto_exposure_min"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_max", "get_tonemap_auto_exposure_max"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_speed", "get_tonemap_auto_exposure_speed"); + // SSR + ClassDB::bind_method(D_METHOD("set_ssr_enabled", "enabled"), &Environment::set_ssr_enabled); ClassDB::bind_method(D_METHOD("is_ssr_enabled"), &Environment::is_ssr_enabled); - ClassDB::bind_method(D_METHOD("set_ssr_max_steps", "max_steps"), &Environment::set_ssr_max_steps); ClassDB::bind_method(D_METHOD("get_ssr_max_steps"), &Environment::get_ssr_max_steps); - ClassDB::bind_method(D_METHOD("set_ssr_fade_in", "fade_in"), &Environment::set_ssr_fade_in); ClassDB::bind_method(D_METHOD("get_ssr_fade_in"), &Environment::get_ssr_fade_in); - ClassDB::bind_method(D_METHOD("set_ssr_fade_out", "fade_out"), &Environment::set_ssr_fade_out); ClassDB::bind_method(D_METHOD("get_ssr_fade_out"), &Environment::get_ssr_fade_out); - ClassDB::bind_method(D_METHOD("set_ssr_depth_tolerance", "depth_tolerance"), &Environment::set_ssr_depth_tolerance); ClassDB::bind_method(D_METHOD("get_ssr_depth_tolerance"), &Environment::get_ssr_depth_tolerance); @@ -910,110 +1152,209 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ss_reflections_fade_out", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_out", "get_ssr_fade_out"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ss_reflections_depth_tolerance", PROPERTY_HINT_RANGE, "0.01,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance"); + // SSAO + ClassDB::bind_method(D_METHOD("set_ssao_enabled", "enabled"), &Environment::set_ssao_enabled); ClassDB::bind_method(D_METHOD("is_ssao_enabled"), &Environment::is_ssao_enabled); - ClassDB::bind_method(D_METHOD("set_ssao_radius", "radius"), &Environment::set_ssao_radius); ClassDB::bind_method(D_METHOD("get_ssao_radius"), &Environment::get_ssao_radius); - ClassDB::bind_method(D_METHOD("set_ssao_intensity", "intensity"), &Environment::set_ssao_intensity); ClassDB::bind_method(D_METHOD("get_ssao_intensity"), &Environment::get_ssao_intensity); - - ClassDB::bind_method(D_METHOD("set_ssao_bias", "bias"), &Environment::set_ssao_bias); - ClassDB::bind_method(D_METHOD("get_ssao_bias"), &Environment::get_ssao_bias); - + ClassDB::bind_method(D_METHOD("set_ssao_power", "power"), &Environment::set_ssao_power); + ClassDB::bind_method(D_METHOD("get_ssao_power"), &Environment::get_ssao_power); + ClassDB::bind_method(D_METHOD("set_ssao_detail", "detail"), &Environment::set_ssao_detail); + ClassDB::bind_method(D_METHOD("get_ssao_detail"), &Environment::get_ssao_detail); + ClassDB::bind_method(D_METHOD("set_ssao_horizon", "horizon"), &Environment::set_ssao_horizon); + ClassDB::bind_method(D_METHOD("get_ssao_horizon"), &Environment::get_ssao_horizon); + ClassDB::bind_method(D_METHOD("set_ssao_sharpness", "sharpness"), &Environment::set_ssao_sharpness); + ClassDB::bind_method(D_METHOD("get_ssao_sharpness"), &Environment::get_ssao_sharpness); ClassDB::bind_method(D_METHOD("set_ssao_direct_light_affect", "amount"), &Environment::set_ssao_direct_light_affect); ClassDB::bind_method(D_METHOD("get_ssao_direct_light_affect"), &Environment::get_ssao_direct_light_affect); - ClassDB::bind_method(D_METHOD("set_ssao_ao_channel_affect", "amount"), &Environment::set_ssao_ao_channel_affect); ClassDB::bind_method(D_METHOD("get_ssao_ao_channel_affect"), &Environment::get_ssao_ao_channel_affect); - ClassDB::bind_method(D_METHOD("set_ssao_blur", "mode"), &Environment::set_ssao_blur); - ClassDB::bind_method(D_METHOD("get_ssao_blur"), &Environment::get_ssao_blur); - - ClassDB::bind_method(D_METHOD("set_ssao_edge_sharpness", "edge_sharpness"), &Environment::set_ssao_edge_sharpness); - ClassDB::bind_method(D_METHOD("get_ssao_edge_sharpness"), &Environment::get_ssao_edge_sharpness); - ADD_GROUP("SSAO", "ssao_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssao_enabled"), "set_ssao_enabled", "is_ssao_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_radius", PROPERTY_HINT_RANGE, "0.1,128,0.01"), "set_ssao_radius", "get_ssao_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_intensity", PROPERTY_HINT_RANGE, "0.0,128,0.01"), "set_ssao_intensity", "get_ssao_intensity"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_bias", PROPERTY_HINT_RANGE, "0.001,8,0.001"), "set_ssao_bias", "get_ssao_bias"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_radius", PROPERTY_HINT_RANGE, "0.01,16,0.01,or_greater"), "set_ssao_radius", "get_ssao_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_intensity", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_ssao_intensity", "get_ssao_intensity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_power", PROPERTY_HINT_EXP_EASING), "set_ssao_power", "get_ssao_power"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_detail", PROPERTY_HINT_RANGE, "0,5,0.01"), "set_ssao_detail", "get_ssao_detail"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_horizon", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_horizon", "get_ssao_horizon"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_sharpness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_sharpness", "get_ssao_sharpness"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_light_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_direct_light_affect", "get_ssao_direct_light_affect"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_ao_channel_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_ao_channel_affect", "get_ssao_ao_channel_affect"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "ssao_blur", PROPERTY_HINT_ENUM, "Disabled,1x1,2x2,3x3"), "set_ssao_blur", "get_ssao_blur"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_edge_sharpness", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_ssao_edge_sharpness", "get_ssao_edge_sharpness"); + + // SDFGI + + ClassDB::bind_method(D_METHOD("set_sdfgi_enabled", "enabled"), &Environment::set_sdfgi_enabled); + ClassDB::bind_method(D_METHOD("is_sdfgi_enabled"), &Environment::is_sdfgi_enabled); + ClassDB::bind_method(D_METHOD("set_sdfgi_cascades", "amount"), &Environment::set_sdfgi_cascades); + ClassDB::bind_method(D_METHOD("get_sdfgi_cascades"), &Environment::get_sdfgi_cascades); + ClassDB::bind_method(D_METHOD("set_sdfgi_min_cell_size", "size"), &Environment::set_sdfgi_min_cell_size); + ClassDB::bind_method(D_METHOD("get_sdfgi_min_cell_size"), &Environment::get_sdfgi_min_cell_size); + ClassDB::bind_method(D_METHOD("set_sdfgi_max_distance", "distance"), &Environment::set_sdfgi_max_distance); + ClassDB::bind_method(D_METHOD("get_sdfgi_max_distance"), &Environment::get_sdfgi_max_distance); + ClassDB::bind_method(D_METHOD("set_sdfgi_cascade0_distance", "distance"), &Environment::set_sdfgi_cascade0_distance); + ClassDB::bind_method(D_METHOD("get_sdfgi_cascade0_distance"), &Environment::get_sdfgi_cascade0_distance); + ClassDB::bind_method(D_METHOD("set_sdfgi_y_scale", "scale"), &Environment::set_sdfgi_y_scale); + ClassDB::bind_method(D_METHOD("get_sdfgi_y_scale"), &Environment::get_sdfgi_y_scale); + ClassDB::bind_method(D_METHOD("set_sdfgi_use_occlusion", "enable"), &Environment::set_sdfgi_use_occlusion); + ClassDB::bind_method(D_METHOD("is_sdfgi_using_occlusion"), &Environment::is_sdfgi_using_occlusion); + ClassDB::bind_method(D_METHOD("set_sdfgi_bounce_feedback", "amount"), &Environment::set_sdfgi_bounce_feedback); + ClassDB::bind_method(D_METHOD("get_sdfgi_bounce_feedback"), &Environment::get_sdfgi_bounce_feedback); + ClassDB::bind_method(D_METHOD("set_sdfgi_read_sky_light", "enable"), &Environment::set_sdfgi_read_sky_light); + ClassDB::bind_method(D_METHOD("is_sdfgi_reading_sky_light"), &Environment::is_sdfgi_reading_sky_light); + ClassDB::bind_method(D_METHOD("set_sdfgi_energy", "amount"), &Environment::set_sdfgi_energy); + ClassDB::bind_method(D_METHOD("get_sdfgi_energy"), &Environment::get_sdfgi_energy); + ClassDB::bind_method(D_METHOD("set_sdfgi_normal_bias", "bias"), &Environment::set_sdfgi_normal_bias); + ClassDB::bind_method(D_METHOD("get_sdfgi_normal_bias"), &Environment::get_sdfgi_normal_bias); + ClassDB::bind_method(D_METHOD("set_sdfgi_probe_bias", "bias"), &Environment::set_sdfgi_probe_bias); + ClassDB::bind_method(D_METHOD("get_sdfgi_probe_bias"), &Environment::get_sdfgi_probe_bias); + + ADD_GROUP("SDFGI", "sdfgi_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_enabled"), "set_sdfgi_enabled", "is_sdfgi_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_use_occlusion"), "set_sdfgi_use_occlusion", "is_sdfgi_using_occlusion"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_read_sky_light"), "set_sdfgi_read_sky_light", "is_sdfgi_reading_sky_light"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_bounce_feedback", PROPERTY_HINT_RANGE, "0,1.99,0.01"), "set_sdfgi_bounce_feedback", "get_sdfgi_bounce_feedback"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_cascades", PROPERTY_HINT_ENUM, "4 Cascades,6 Cascades,8 Cascades"), "set_sdfgi_cascades", "get_sdfgi_cascades"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_min_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_sdfgi_min_cell_size", "get_sdfgi_min_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_max_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_max_distance", "get_sdfgi_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_y_scale", PROPERTY_HINT_ENUM, "Disable,75%,50%"), "set_sdfgi_y_scale", "get_sdfgi_y_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_energy"), "set_sdfgi_energy", "get_sdfgi_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_normal_bias"), "set_sdfgi_normal_bias", "get_sdfgi_normal_bias"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_probe_bias"), "set_sdfgi_probe_bias", "get_sdfgi_probe_bias"); + + // Glow ClassDB::bind_method(D_METHOD("set_glow_enabled", "enabled"), &Environment::set_glow_enabled); ClassDB::bind_method(D_METHOD("is_glow_enabled"), &Environment::is_glow_enabled); - - ClassDB::bind_method(D_METHOD("set_glow_level", "idx", "enabled"), &Environment::set_glow_level); - ClassDB::bind_method(D_METHOD("is_glow_level_enabled", "idx"), &Environment::is_glow_level_enabled); - + ClassDB::bind_method(D_METHOD("set_glow_level", "idx", "intensity"), &Environment::set_glow_level); + ClassDB::bind_method(D_METHOD("get_glow_level", "idx"), &Environment::get_glow_level); + ClassDB::bind_method(D_METHOD("set_glow_normalized", "normalize"), &Environment::set_glow_normalized); + ClassDB::bind_method(D_METHOD("is_glow_normalized"), &Environment::is_glow_normalized); ClassDB::bind_method(D_METHOD("set_glow_intensity", "intensity"), &Environment::set_glow_intensity); ClassDB::bind_method(D_METHOD("get_glow_intensity"), &Environment::get_glow_intensity); - ClassDB::bind_method(D_METHOD("set_glow_strength", "strength"), &Environment::set_glow_strength); ClassDB::bind_method(D_METHOD("get_glow_strength"), &Environment::get_glow_strength); - ClassDB::bind_method(D_METHOD("set_glow_mix", "mix"), &Environment::set_glow_mix); ClassDB::bind_method(D_METHOD("get_glow_mix"), &Environment::get_glow_mix); - ClassDB::bind_method(D_METHOD("set_glow_bloom", "amount"), &Environment::set_glow_bloom); ClassDB::bind_method(D_METHOD("get_glow_bloom"), &Environment::get_glow_bloom); - ClassDB::bind_method(D_METHOD("set_glow_blend_mode", "mode"), &Environment::set_glow_blend_mode); ClassDB::bind_method(D_METHOD("get_glow_blend_mode"), &Environment::get_glow_blend_mode); - ClassDB::bind_method(D_METHOD("set_glow_hdr_bleed_threshold", "threshold"), &Environment::set_glow_hdr_bleed_threshold); ClassDB::bind_method(D_METHOD("get_glow_hdr_bleed_threshold"), &Environment::get_glow_hdr_bleed_threshold); - - ClassDB::bind_method(D_METHOD("set_glow_hdr_luminance_cap", "amount"), &Environment::set_glow_hdr_luminance_cap); - ClassDB::bind_method(D_METHOD("get_glow_hdr_luminance_cap"), &Environment::get_glow_hdr_luminance_cap); - ClassDB::bind_method(D_METHOD("set_glow_hdr_bleed_scale", "scale"), &Environment::set_glow_hdr_bleed_scale); ClassDB::bind_method(D_METHOD("get_glow_hdr_bleed_scale"), &Environment::get_glow_hdr_bleed_scale); + ClassDB::bind_method(D_METHOD("set_glow_hdr_luminance_cap", "amount"), &Environment::set_glow_hdr_luminance_cap); + ClassDB::bind_method(D_METHOD("get_glow_hdr_luminance_cap"), &Environment::get_glow_hdr_luminance_cap); ADD_GROUP("Glow", "glow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_enabled"), "set_glow_enabled", "is_glow_enabled"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/1"), "set_glow_level", "is_glow_level_enabled", 0); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/2"), "set_glow_level", "is_glow_level_enabled", 1); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/3"), "set_glow_level", "is_glow_level_enabled", 2); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/4"), "set_glow_level", "is_glow_level_enabled", 3); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/5"), "set_glow_level", "is_glow_level_enabled", 4); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/6"), "set_glow_level", "is_glow_level_enabled", 5); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/7"), "set_glow_level", "is_glow_level_enabled", 6); - + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/1", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 0); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/2", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 1); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/3", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 2); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/4", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 3); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/5", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 4); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/6", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 5); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "glow_levels/7", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_glow_level", "get_glow_level", 6); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_normalized"), "set_glow_normalized", "is_glow_normalized"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_intensity", PROPERTY_HINT_RANGE, "0.0,8.0,0.01"), "set_glow_intensity", "get_glow_intensity"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_mix", PROPERTY_HINT_RANGE, "0.0,1.0,0.001"), "set_glow_mix", "get_glow_mix"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_strength", PROPERTY_HINT_RANGE, "0.0,2.0,0.01"), "set_glow_strength", "get_glow_strength"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_mix", PROPERTY_HINT_RANGE, "0.0,1.0,0.001"), "set_glow_mix", "get_glow_mix"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_bloom", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_glow_bloom", "get_glow_bloom"); ADD_PROPERTY(PropertyInfo(Variant::INT, "glow_blend_mode", PROPERTY_HINT_ENUM, "Additive,Screen,Softlight,Replace,Mix"), "set_glow_blend_mode", "get_glow_blend_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_threshold", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_threshold", "get_glow_hdr_bleed_threshold"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_luminance_cap", PROPERTY_HINT_RANGE, "0.0,256.0,0.01"), "set_glow_hdr_luminance_cap", "get_glow_hdr_luminance_cap"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_scale", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_scale", "get_glow_hdr_bleed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_luminance_cap", PROPERTY_HINT_RANGE, "0.0,256.0,0.01"), "set_glow_hdr_luminance_cap", "get_glow_hdr_luminance_cap"); - ClassDB::bind_method(D_METHOD("set_adjustment_enable", "enabled"), &Environment::set_adjustment_enable); - ClassDB::bind_method(D_METHOD("is_adjustment_enabled"), &Environment::is_adjustment_enabled); + // Fog + + ClassDB::bind_method(D_METHOD("set_fog_enabled", "enabled"), &Environment::set_fog_enabled); + ClassDB::bind_method(D_METHOD("is_fog_enabled"), &Environment::is_fog_enabled); + ClassDB::bind_method(D_METHOD("set_fog_light_color", "light_color"), &Environment::set_fog_light_color); + ClassDB::bind_method(D_METHOD("get_fog_light_color"), &Environment::get_fog_light_color); + ClassDB::bind_method(D_METHOD("set_fog_light_energy", "light_energy"), &Environment::set_fog_light_energy); + ClassDB::bind_method(D_METHOD("get_fog_light_energy"), &Environment::get_fog_light_energy); + ClassDB::bind_method(D_METHOD("set_fog_sun_scatter", "sun_scatter"), &Environment::set_fog_sun_scatter); + ClassDB::bind_method(D_METHOD("get_fog_sun_scatter"), &Environment::get_fog_sun_scatter); + ClassDB::bind_method(D_METHOD("set_fog_density", "density"), &Environment::set_fog_density); + ClassDB::bind_method(D_METHOD("get_fog_density"), &Environment::get_fog_density); + + ClassDB::bind_method(D_METHOD("set_fog_height", "height"), &Environment::set_fog_height); + ClassDB::bind_method(D_METHOD("get_fog_height"), &Environment::get_fog_height); + + ClassDB::bind_method(D_METHOD("set_fog_height_density", "height_density"), &Environment::set_fog_height_density); + ClassDB::bind_method(D_METHOD("get_fog_height_density"), &Environment::get_fog_height_density); + + ClassDB::bind_method(D_METHOD("set_fog_aerial_perspective", "aerial_perspective"), &Environment::set_fog_aerial_perspective); + ClassDB::bind_method(D_METHOD("get_fog_aerial_perspective"), &Environment::get_fog_aerial_perspective); + + ADD_GROUP("Fog", "fog_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_fog_light_color", "get_fog_light_color"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_fog_light_energy", "get_fog_light_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sun_scatter", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_fog_sun_scatter", "get_fog_sun_scatter"); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,16,0.0001"), "set_fog_density", "get_fog_density"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater"), "set_fog_height", "get_fog_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "0,128,0.001,or_greater"), "set_fog_height_density", "get_fog_height_density"); + + ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled); + ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_light", "color"), &Environment::set_volumetric_fog_light); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_light"), &Environment::get_volumetric_fog_light); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_density", "density"), &Environment::set_volumetric_fog_density); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_density"), &Environment::get_volumetric_fog_density); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_light_energy", "begin"), &Environment::set_volumetric_fog_light_energy); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_light_energy"), &Environment::get_volumetric_fog_light_energy); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_length", "length"), &Environment::set_volumetric_fog_length); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_length"), &Environment::get_volumetric_fog_length); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_detail_spread", "detail_spread"), &Environment::set_volumetric_fog_detail_spread); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_detail_spread"), &Environment::get_volumetric_fog_detail_spread); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_gi_inject", "gi_inject"), &Environment::set_volumetric_fog_gi_inject); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_gi_inject"), &Environment::get_volumetric_fog_gi_inject); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_enabled", "enabled"), &Environment::set_volumetric_fog_temporal_reprojection_enabled); + ClassDB::bind_method(D_METHOD("is_volumetric_fog_temporal_reprojection_enabled"), &Environment::is_volumetric_fog_temporal_reprojection_enabled); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_amount", "temporal_reprojection_amount"), &Environment::set_volumetric_fog_temporal_reprojection_amount); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_temporal_reprojection_amount"), &Environment::get_volumetric_fog_temporal_reprojection_amount); + + ADD_GROUP("Volumetric Fog", "volumetric_fog_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_enabled"), "set_volumetric_fog_enabled", "is_volumetric_fog_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_volumetric_fog_density", "get_volumetric_fog_density"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_light", "get_volumetric_fog_light"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_light_energy", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_light_energy", "get_volumetric_fog_light_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_EXP_RANGE, "0.00,16,0.01"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread"); + ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.0,0.999,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount"); + + // Adjustment + + ClassDB::bind_method(D_METHOD("set_adjustment_enabled", "enabled"), &Environment::set_adjustment_enabled); + ClassDB::bind_method(D_METHOD("is_adjustment_enabled"), &Environment::is_adjustment_enabled); ClassDB::bind_method(D_METHOD("set_adjustment_brightness", "brightness"), &Environment::set_adjustment_brightness); ClassDB::bind_method(D_METHOD("get_adjustment_brightness"), &Environment::get_adjustment_brightness); - ClassDB::bind_method(D_METHOD("set_adjustment_contrast", "contrast"), &Environment::set_adjustment_contrast); ClassDB::bind_method(D_METHOD("get_adjustment_contrast"), &Environment::get_adjustment_contrast); - ClassDB::bind_method(D_METHOD("set_adjustment_saturation", "saturation"), &Environment::set_adjustment_saturation); ClassDB::bind_method(D_METHOD("get_adjustment_saturation"), &Environment::get_adjustment_saturation); - ClassDB::bind_method(D_METHOD("set_adjustment_color_correction", "color_correction"), &Environment::set_adjustment_color_correction); ClassDB::bind_method(D_METHOD("get_adjustment_color_correction"), &Environment::get_adjustment_color_correction); ADD_GROUP("Adjustments", "adjustment_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "adjustment_enabled"), "set_adjustment_enable", "is_adjustment_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "adjustment_enabled"), "set_adjustment_enabled", "is_adjustment_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_brightness", PROPERTY_HINT_RANGE, "0.01,8,0.01"), "set_adjustment_brightness", "get_adjustment_brightness"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_contrast", PROPERTY_HINT_RANGE, "0.01,8,0.01"), "set_adjustment_contrast", "get_adjustment_contrast"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_saturation", PROPERTY_HINT_RANGE, "0.01,8,0.01"), "set_adjustment_saturation", "get_adjustment_saturation"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "adjustment_color_correction", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_adjustment_color_correction", "get_adjustment_color_correction"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "adjustment_color_correction", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D,Texture3D"), "set_adjustment_color_correction", "get_adjustment_color_correction"); + + // Constants BIND_ENUM_CONSTANT(BG_CLEAR_COLOR); BIND_ENUM_CONSTANT(BG_COLOR); @@ -1032,254 +1373,57 @@ void Environment::_bind_methods() { BIND_ENUM_CONSTANT(REFLECTION_SOURCE_DISABLED); BIND_ENUM_CONSTANT(REFLECTION_SOURCE_SKY); + BIND_ENUM_CONSTANT(TONE_MAPPER_LINEAR); + BIND_ENUM_CONSTANT(TONE_MAPPER_REINHARDT); + BIND_ENUM_CONSTANT(TONE_MAPPER_FILMIC); + BIND_ENUM_CONSTANT(TONE_MAPPER_ACES); + BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_ADDITIVE); BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_SCREEN); BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_SOFTLIGHT); BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_REPLACE); BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_MIX); - BIND_ENUM_CONSTANT(TONE_MAPPER_LINEAR); - BIND_ENUM_CONSTANT(TONE_MAPPER_REINHARDT); - BIND_ENUM_CONSTANT(TONE_MAPPER_FILMIC); - BIND_ENUM_CONSTANT(TONE_MAPPER_ACES); + BIND_ENUM_CONSTANT(SDFGI_CASCADES_4); + BIND_ENUM_CONSTANT(SDFGI_CASCADES_6); + BIND_ENUM_CONSTANT(SDFGI_CASCADES_8); - BIND_ENUM_CONSTANT(SSAO_BLUR_DISABLED); - BIND_ENUM_CONSTANT(SSAO_BLUR_1x1); - BIND_ENUM_CONSTANT(SSAO_BLUR_2x2); - BIND_ENUM_CONSTANT(SSAO_BLUR_3x3); + BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_DISABLED); + BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_75_PERCENT); + BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_50_PERCENT); + + BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED); + BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_LOW); + BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM); + BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_HIGH); } Environment::Environment() { environment = RS::get_singleton()->environment_create(); - bg_mode = BG_CLEAR_COLOR; - bg_sky_custom_fov = 0; - bg_energy = 1.0; - bg_canvas_max_layer = 0; - ambient_energy = 1.0; - //ambient_sky_contribution = 1.0; - ambient_source = AMBIENT_SOURCE_BG; - reflection_source = REFLECTION_SOURCE_BG; - set_ambient_light_sky_contribution(1.0); - set_camera_feed_id(1); - - tone_mapper = TONE_MAPPER_LINEAR; - tonemap_exposure = 1.0; - tonemap_white = 1.0; - tonemap_auto_exposure = false; - tonemap_auto_exposure_max = 8; - tonemap_auto_exposure_min = 0.05; - tonemap_auto_exposure_speed = 0.5; - tonemap_auto_exposure_grey = 0.4; - - set_tonemapper(tone_mapper); //update - - adjustment_enabled = false; - adjustment_contrast = 1.0; - adjustment_saturation = 1.0; - adjustment_brightness = 1.0; - - set_adjustment_enable(adjustment_enabled); //update - - ssr_enabled = false; - ssr_max_steps = 64; - ssr_fade_in = 0.15; - ssr_fade_out = 2.0; - ssr_depth_tolerance = 0.2; - - ssao_enabled = false; - ssao_radius = 1; - ssao_intensity = 1; - ssao_bias = 0.01; - ssao_direct_light_affect = 0.0; - ssao_ao_channel_affect = 0.0; - ssao_blur = SSAO_BLUR_3x3; - set_ssao_edge_sharpness(4); - - glow_enabled = false; - glow_levels = (1 << 2) | (1 << 4); - glow_intensity = 0.8; - glow_strength = 1.0; - glow_mix = 0.05; - glow_bloom = 0.0; - glow_blend_mode = GLOW_BLEND_MODE_SOFTLIGHT; - glow_hdr_bleed_threshold = 1.0; - glow_hdr_luminance_cap = 12.0; - glow_hdr_bleed_scale = 2.0; - - fog_enabled = false; - fog_color = Color(0.5, 0.5, 0.5); - fog_sun_color = Color(0.8, 0.8, 0.0); - fog_sun_amount = 0; - - fog_depth_enabled = true; - - fog_depth_begin = 10; - fog_depth_end = 100; - fog_depth_curve = 1; - - fog_transmit_enabled = false; - fog_transmit_curve = 1; - - fog_height_enabled = false; - fog_height_min = 10; - fog_height_max = 0; - fog_height_curve = 1; - - set_fog_color(Color(0.5, 0.6, 0.7)); - set_fog_sun_color(Color(1.0, 0.9, 0.7)); + set_camera_feed_id(bg_camera_feed_id); + + glow_levels.resize(7); + glow_levels.write[0] = 0.0; + glow_levels.write[1] = 0.0; + glow_levels.write[2] = 1.0; + glow_levels.write[3] = 0.0; + glow_levels.write[4] = 1.0; + glow_levels.write[5] = 0.0; + glow_levels.write[6] = 0.0; + + _update_ambient_light(); + _update_tonemap(); + _update_ssr(); + _update_ssao(); + _update_sdfgi(); + _update_glow(); + _update_fog(); + _update_adjustment(); + _update_volumetric_fog(); + notify_property_list_changed(); } Environment::~Environment() { RS::get_singleton()->free(environment); } - -////////////////////// - -void CameraEffects::set_dof_blur_far_enabled(bool p_enable) { - dof_blur_far_enabled = p_enable; - RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount); -} - -bool CameraEffects::is_dof_blur_far_enabled() const { - return dof_blur_far_enabled; -} - -void CameraEffects::set_dof_blur_far_distance(float p_distance) { - dof_blur_far_distance = p_distance; - RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount); -} - -float CameraEffects::get_dof_blur_far_distance() const { - return dof_blur_far_distance; -} - -void CameraEffects::set_dof_blur_far_transition(float p_distance) { - dof_blur_far_transition = p_distance; - RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount); -} - -float CameraEffects::get_dof_blur_far_transition() const { - return dof_blur_far_transition; -} - -void CameraEffects::set_dof_blur_near_enabled(bool p_enable) { - dof_blur_near_enabled = p_enable; - RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount); - _change_notify(); -} - -bool CameraEffects::is_dof_blur_near_enabled() const { - return dof_blur_near_enabled; -} - -void CameraEffects::set_dof_blur_near_distance(float p_distance) { - dof_blur_near_distance = p_distance; - RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount); -} - -float CameraEffects::get_dof_blur_near_distance() const { - return dof_blur_near_distance; -} - -void CameraEffects::set_dof_blur_near_transition(float p_distance) { - dof_blur_near_transition = p_distance; - RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount); -} - -float CameraEffects::get_dof_blur_near_transition() const { - return dof_blur_near_transition; -} - -void CameraEffects::set_dof_blur_amount(float p_amount) { - dof_blur_amount = p_amount; - RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount); -} - -float CameraEffects::get_dof_blur_amount() const { - return dof_blur_amount; -} - -void CameraEffects::set_override_exposure_enabled(bool p_enabled) { - override_exposure_enabled = p_enabled; - RS::get_singleton()->camera_effects_set_custom_exposure(camera_effects, override_exposure_enabled, override_exposure); -} - -bool CameraEffects::is_override_exposure_enabled() const { - return override_exposure_enabled; -} - -void CameraEffects::set_override_exposure(float p_exposure) { - override_exposure = p_exposure; - RS::get_singleton()->camera_effects_set_custom_exposure(camera_effects, override_exposure_enabled, override_exposure); -} - -float CameraEffects::get_override_exposure() const { - return override_exposure; -} - -RID CameraEffects::get_rid() const { - return camera_effects; -} - -void CameraEffects::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraEffects::set_dof_blur_far_enabled); - ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraEffects::is_dof_blur_far_enabled); - - ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "intensity"), &CameraEffects::set_dof_blur_far_distance); - ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraEffects::get_dof_blur_far_distance); - - ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "intensity"), &CameraEffects::set_dof_blur_far_transition); - ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraEffects::get_dof_blur_far_transition); - - ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraEffects::set_dof_blur_near_enabled); - ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraEffects::is_dof_blur_near_enabled); - - ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "intensity"), &CameraEffects::set_dof_blur_near_distance); - ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraEffects::get_dof_blur_near_distance); - - ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "intensity"), &CameraEffects::set_dof_blur_near_transition); - ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraEffects::get_dof_blur_near_transition); - - ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "intensity"), &CameraEffects::set_dof_blur_amount); - ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraEffects::get_dof_blur_amount); - - ClassDB::bind_method(D_METHOD("set_override_exposure_enabled", "enable"), &CameraEffects::set_override_exposure_enabled); - ClassDB::bind_method(D_METHOD("is_override_exposure_enabled"), &CameraEffects::is_override_exposure_enabled); - - ClassDB::bind_method(D_METHOD("set_override_exposure", "exposure"), &CameraEffects::set_override_exposure); - ClassDB::bind_method(D_METHOD("get_override_exposure"), &CameraEffects::get_override_exposure); - - ADD_GROUP("DOF Blur", "dof_blur_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); - ADD_GROUP("Override Exposure", "override_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_exposure_enable"), "set_override_exposure_enabled", "is_override_exposure_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "override_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_override_exposure", "get_override_exposure"); -} - -CameraEffects::CameraEffects() { - camera_effects = RS::get_singleton()->camera_effects_create(); - - dof_blur_far_enabled = false; - dof_blur_far_distance = 10; - dof_blur_far_transition = 5; - - dof_blur_near_enabled = false; - dof_blur_near_distance = 2; - dof_blur_near_transition = 1; - - set_dof_blur_amount(0.1); - - override_exposure_enabled = false; - set_override_exposure(1.0); -} - -CameraEffects::~CameraEffects() { - RS::get_singleton()->free(camera_effects); -} diff --git a/scene/resources/environment.h b/scene/resources/environment.h index b8caa59aab..0df2c3cc27 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef ENVIRONMENT_H #define ENVIRONMENT_H -#include "core/resource.h" +#include "core/io/resource.h" #include "scene/resources/sky.h" #include "scene/resources/texture.h" #include "servers/rendering_server.h" @@ -41,7 +41,6 @@ class Environment : public Resource { public: enum BGMode { - BG_CLEAR_COLOR, BG_COLOR, BG_SKY, @@ -68,7 +67,19 @@ public: TONE_MAPPER_LINEAR, TONE_MAPPER_REINHARDT, TONE_MAPPER_FILMIC, - TONE_MAPPER_ACES + TONE_MAPPER_ACES, + }; + + enum SDFGICascades { + SDFGI_CASCADES_4, + SDFGI_CASCADES_6, + SDFGI_CASCADES_8, + }; + + enum SDFGIYScale { + SDFGI_Y_SCALE_DISABLED, + SDFGI_Y_SCALE_75_PERCENT, + SDFGI_Y_SCALE_50_PERCENT, }; enum GlowBlendMode { @@ -79,282 +90,320 @@ public: GLOW_BLEND_MODE_MIX, }; - enum SSAOBlur { - SSAO_BLUR_DISABLED, - SSAO_BLUR_1x1, - SSAO_BLUR_2x2, - SSAO_BLUR_3x3 + enum VolumetricFogShadowFilter { + VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED, + VOLUMETRIC_FOG_SHADOW_FILTER_LOW, + VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM, + VOLUMETRIC_FOG_SHADOW_FILTER_HIGH, }; private: RID environment; + // Background BGMode bg_mode = BG_CLEAR_COLOR; Ref<Sky> bg_sky; - float bg_sky_custom_fov; - Vector3 sky_rotation; + float bg_sky_custom_fov = 0.0; + Vector3 bg_sky_rotation; Color bg_color; - float bg_energy; - int bg_canvas_max_layer; + float bg_energy = 1.0; + int bg_canvas_max_layer = 0; + int bg_camera_feed_id = 1; + + // Ambient light Color ambient_color; - float ambient_energy; + AmbientSource ambient_source = AMBIENT_SOURCE_BG; + float ambient_energy = 1.0; + float ambient_sky_contribution = 1.0; + ReflectionSource reflection_source = REFLECTION_SOURCE_BG; Color ao_color; - float ambient_sky_contribution; - int camera_feed_id; - AmbientSource ambient_source; - ReflectionSource reflection_source; + void _update_ambient_light(); + // Tonemap ToneMapper tone_mapper = TONE_MAPPER_LINEAR; - float tonemap_exposure; - float tonemap_white; - bool tonemap_auto_exposure; - float tonemap_auto_exposure_max; - float tonemap_auto_exposure_min; - float tonemap_auto_exposure_speed; - float tonemap_auto_exposure_grey; - - bool adjustment_enabled; - float adjustment_contrast; - float adjustment_saturation; - float adjustment_brightness; - Ref<Texture2D> adjustment_color_correction; - - bool ssr_enabled; - int ssr_max_steps; - float ssr_fade_in; - float ssr_fade_out; - float ssr_depth_tolerance; - - bool ssao_enabled; - float ssao_radius; - float ssao_intensity; - float ssao_bias; - float ssao_direct_light_affect; - float ssao_ao_channel_affect; - SSAOBlur ssao_blur = SSAO_BLUR_3x3; - float ssao_edge_sharpness; - - bool glow_enabled; - int glow_levels; - float glow_intensity; - float glow_strength; - float glow_mix; - float glow_bloom; - GlowBlendMode glow_blend_mode = GLOW_BLEND_MODE_ADDITIVE; - float glow_hdr_bleed_threshold; - float glow_hdr_bleed_scale; - float glow_hdr_luminance_cap; - - bool fog_enabled; - Color fog_color; - Color fog_sun_color; - float fog_sun_amount; - - bool fog_depth_enabled; - float fog_depth_begin; - float fog_depth_end; - float fog_depth_curve; - - bool fog_transmit_enabled; - float fog_transmit_curve; - - bool fog_height_enabled; - float fog_height_min; - float fog_height_max; - float fog_height_curve; + float tonemap_exposure = 1.0; + float tonemap_white = 1.0; + bool tonemap_auto_exposure_enabled = false; + float tonemap_auto_exposure_min = 0.05; + float tonemap_auto_exposure_max = 8.0; + float tonemap_auto_exposure_speed = 0.5; + float tonemap_auto_exposure_grey = 0.4; + void _update_tonemap(); + + // SSR + bool ssr_enabled = false; + int ssr_max_steps = 64; + float ssr_fade_in = 0.15; + float ssr_fade_out = 2.0; + float ssr_depth_tolerance = 0.2; + void _update_ssr(); + + // SSAO + bool ssao_enabled = false; + float ssao_radius = 1.0; + float ssao_intensity = 2.0; + float ssao_power = 1.5; + float ssao_detail = 0.5; + float ssao_horizon = 0.06; + float ssao_sharpness = 0.98; + float ssao_direct_light_affect = 0.0; + float ssao_ao_channel_affect = 0.0; + void _update_ssao(); + + // SDFGI + bool sdfgi_enabled = false; + SDFGICascades sdfgi_cascades = SDFGI_CASCADES_6; + float sdfgi_min_cell_size = 0.2; + SDFGIYScale sdfgi_y_scale = SDFGI_Y_SCALE_DISABLED; + bool sdfgi_use_occlusion = false; + float sdfgi_bounce_feedback = 0.0; + bool sdfgi_read_sky_light = false; + float sdfgi_energy = 1.0; + float sdfgi_normal_bias = 1.1; + float sdfgi_probe_bias = 1.1; + void _update_sdfgi(); + + // Glow + bool glow_enabled = false; + Vector<float> glow_levels; + bool glow_normalize_levels = false; + float glow_intensity = 0.8; + float glow_strength = 1.0; + float glow_mix = 0.05; + float glow_bloom = 0.0; + GlowBlendMode glow_blend_mode = GLOW_BLEND_MODE_SOFTLIGHT; + float glow_hdr_bleed_threshold = 1.0; + float glow_hdr_bleed_scale = 2.0; + float glow_hdr_luminance_cap = 12.0; + void _update_glow(); + + // Fog + bool fog_enabled = false; + Color fog_light_color = Color(0.5, 0.6, 0.7); + float fog_light_energy = 1.0; + float fog_sun_scatter = 0.0; + float fog_density = 0.001; + float fog_height = 0.0; + float fog_height_density = 0.0; //can be negative to invert effect + float fog_aerial_perspective = 0.0; + + void _update_fog(); + + // Volumetric Fog + bool volumetric_fog_enabled = false; + float volumetric_fog_density = 0.01; + Color volumetric_fog_light = Color(0.0, 0.0, 0.0); + float volumetric_fog_light_energy = 1.0; + float volumetric_fog_length = 64.0; + float volumetric_fog_detail_spread = 2.0; + float volumetric_fog_gi_inject = 0.0; + bool volumetric_fog_temporal_reproject = true; + float volumetric_fog_temporal_reproject_amount = 0.9; + void _update_volumetric_fog(); + + // Adjustment + bool adjustment_enabled = false; + float adjustment_brightness = 1.0; + float adjustment_contrast = 1.0; + float adjustment_saturation = 1.0; + bool use_1d_color_correction = true; + Ref<Texture> adjustment_color_correction; + void _update_adjustment(); protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const; + virtual void _validate_property(PropertyInfo &property) const override; #ifndef DISABLE_DEPRECATED // Kept for compatibility from 3.x to 4.0. bool _set(const StringName &p_name, const Variant &p_value); #endif public: - void set_background(BGMode p_bg); + virtual RID get_rid() const override; + // Background + void set_background(BGMode p_bg); + BGMode get_background() const; void set_sky(const Ref<Sky> &p_sky); + Ref<Sky> get_sky() const; void set_sky_custom_fov(float p_scale); + float get_sky_custom_fov() const; void set_sky_rotation(const Vector3 &p_rotation); + Vector3 get_sky_rotation() const; void set_bg_color(const Color &p_color); + Color get_bg_color() const; void set_bg_energy(float p_energy); + float get_bg_energy() const; void set_canvas_max_layer(int p_max_layer); + int get_canvas_max_layer() const; + void set_camera_feed_id(int p_id); + int get_camera_feed_id() const; + + // Ambient light 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); + Color get_ambient_light_color() const; void set_ambient_source(AmbientSource p_source); AmbientSource get_ambient_source() const; - void set_reflection_source(ReflectionSource p_source); - ReflectionSource get_reflection_source() const; - - BGMode get_background() const; - Ref<Sky> get_sky() const; - float get_sky_custom_fov() const; - Vector3 get_sky_rotation() const; - Color get_bg_color() const; - float get_bg_energy() const; - int get_canvas_max_layer() const; - Color get_ambient_light_color() const; + void set_ambient_light_energy(float p_energy); float get_ambient_light_energy() const; + void set_ambient_light_sky_contribution(float p_ratio); float get_ambient_light_sky_contribution() const; - int get_camera_feed_id() const; + void set_reflection_source(ReflectionSource p_source); + ReflectionSource get_reflection_source() const; + void set_ao_color(const Color &p_color); + Color get_ao_color() const; + // Tonemap void set_tonemapper(ToneMapper p_tone_mapper); ToneMapper get_tonemapper() const; - void set_tonemap_exposure(float p_exposure); float get_tonemap_exposure() const; - void set_tonemap_white(float p_white); float get_tonemap_white() const; - - void set_tonemap_auto_exposure(bool p_enabled); - bool get_tonemap_auto_exposure() const; - - void set_tonemap_auto_exposure_max(float p_auto_exposure_max); - float get_tonemap_auto_exposure_max() const; - + void set_tonemap_auto_exposure_enabled(bool p_enabled); + bool is_tonemap_auto_exposure_enabled() const; void set_tonemap_auto_exposure_min(float p_auto_exposure_min); float get_tonemap_auto_exposure_min() const; - + void set_tonemap_auto_exposure_max(float p_auto_exposure_max); + float get_tonemap_auto_exposure_max() const; void set_tonemap_auto_exposure_speed(float p_auto_exposure_speed); float get_tonemap_auto_exposure_speed() const; - void set_tonemap_auto_exposure_grey(float p_auto_exposure_grey); float get_tonemap_auto_exposure_grey() const; - void set_adjustment_enable(bool p_enable); - bool is_adjustment_enabled() const; - - void set_adjustment_brightness(float p_brightness); - float get_adjustment_brightness() const; - - void set_adjustment_contrast(float p_contrast); - float get_adjustment_contrast() const; - - void set_adjustment_saturation(float p_saturation); - float get_adjustment_saturation() const; - - void set_adjustment_color_correction(const Ref<Texture2D> &p_ramp); - Ref<Texture2D> get_adjustment_color_correction() const; - - void set_ssr_enabled(bool p_enable); + // SSR + void set_ssr_enabled(bool p_enabled); bool is_ssr_enabled() const; - void set_ssr_max_steps(int p_steps); int get_ssr_max_steps() const; - void set_ssr_fade_in(float p_fade_in); float get_ssr_fade_in() const; - void set_ssr_fade_out(float p_fade_out); float get_ssr_fade_out() const; - void set_ssr_depth_tolerance(float p_depth_tolerance); float get_ssr_depth_tolerance() const; - void set_ssao_enabled(bool p_enable); + // SSAO + void set_ssao_enabled(bool p_enabled); bool is_ssao_enabled() const; - void set_ssao_radius(float p_radius); float get_ssao_radius() const; - void set_ssao_intensity(float p_intensity); float get_ssao_intensity() const; - - void set_ssao_bias(float p_bias); - float get_ssao_bias() const; - + void set_ssao_power(float p_power); + float get_ssao_power() const; + void set_ssao_detail(float p_detail); + float get_ssao_detail() const; + void set_ssao_horizon(float p_horizon); + float get_ssao_horizon() const; + void set_ssao_sharpness(float p_sharpness); + float get_ssao_sharpness() const; void set_ssao_direct_light_affect(float p_direct_light_affect); float get_ssao_direct_light_affect() const; - void set_ssao_ao_channel_affect(float p_ao_channel_affect); float get_ssao_ao_channel_affect() const; - void set_ao_color(const Color &p_color); - Color get_ao_color() const; - - void set_ssao_blur(SSAOBlur p_blur); - SSAOBlur get_ssao_blur() const; - - void set_ssao_edge_sharpness(float p_edge_sharpness); - float get_ssao_edge_sharpness() const; - + // SDFGI + void set_sdfgi_enabled(bool p_enabled); + bool is_sdfgi_enabled() const; + void set_sdfgi_cascades(SDFGICascades p_cascades); + SDFGICascades get_sdfgi_cascades() const; + void set_sdfgi_min_cell_size(float p_size); + float get_sdfgi_min_cell_size() const; + void set_sdfgi_max_distance(float p_distance); + float get_sdfgi_max_distance() const; + void set_sdfgi_cascade0_distance(float p_distance); + float get_sdfgi_cascade0_distance() const; + void set_sdfgi_y_scale(SDFGIYScale p_y_scale); + SDFGIYScale get_sdfgi_y_scale() const; + void set_sdfgi_use_occlusion(bool p_enabled); + bool is_sdfgi_using_occlusion() const; + void set_sdfgi_bounce_feedback(float p_amount); + float get_sdfgi_bounce_feedback() const; + void set_sdfgi_read_sky_light(bool p_enabled); + bool is_sdfgi_reading_sky_light() const; + void set_sdfgi_energy(float p_energy); + float get_sdfgi_energy() const; + void set_sdfgi_normal_bias(float p_bias); + float get_sdfgi_normal_bias() const; + void set_sdfgi_probe_bias(float p_bias); + float get_sdfgi_probe_bias() const; + + // Glow void set_glow_enabled(bool p_enabled); bool is_glow_enabled() const; - - void set_glow_level(int p_level, bool p_enabled); - bool is_glow_level_enabled(int p_level) const; - + void set_glow_level(int p_level, float p_intensity); + float get_glow_level(int p_level) const; + void set_glow_normalized(bool p_normalized); + bool is_glow_normalized() const; void set_glow_intensity(float p_intensity); float get_glow_intensity() const; - void set_glow_strength(float p_strength); float get_glow_strength() const; - void set_glow_mix(float p_mix); float get_glow_mix() const; - void set_glow_bloom(float p_threshold); float get_glow_bloom() const; - void set_glow_blend_mode(GlowBlendMode p_mode); GlowBlendMode get_glow_blend_mode() const; - void set_glow_hdr_bleed_threshold(float p_threshold); float get_glow_hdr_bleed_threshold() const; - + void set_glow_hdr_bleed_scale(float p_scale); + float get_glow_hdr_bleed_scale() const; void set_glow_hdr_luminance_cap(float p_amount); float get_glow_hdr_luminance_cap() const; - void set_glow_hdr_bleed_scale(float p_scale); - float get_glow_hdr_bleed_scale() const; + // Fog void set_fog_enabled(bool p_enabled); bool is_fog_enabled() const; - - void set_fog_color(const Color &p_color); - Color get_fog_color() const; - - void set_fog_sun_color(const Color &p_color); - Color get_fog_sun_color() const; - - void set_fog_sun_amount(float p_amount); - float get_fog_sun_amount() const; - - void set_fog_depth_enabled(bool p_enabled); - bool is_fog_depth_enabled() const; - - void set_fog_depth_begin(float p_distance); - float get_fog_depth_begin() const; - - void set_fog_depth_end(float p_distance); - float get_fog_depth_end() const; - - void set_fog_depth_curve(float p_curve); - float get_fog_depth_curve() const; - - void set_fog_transmit_enabled(bool p_enabled); - bool is_fog_transmit_enabled() const; - - void set_fog_transmit_curve(float p_curve); - float get_fog_transmit_curve() const; - - void set_fog_height_enabled(bool p_enabled); - bool is_fog_height_enabled() const; - - void set_fog_height_min(float p_distance); - float get_fog_height_min() const; - - void set_fog_height_max(float p_distance); - float get_fog_height_max() const; - - void set_fog_height_curve(float p_distance); - float get_fog_height_curve() const; - - virtual RID get_rid() const; + void set_fog_light_color(const Color &p_light_color); + Color get_fog_light_color() const; + void set_fog_light_energy(float p_amount); + float get_fog_light_energy() const; + void set_fog_sun_scatter(float p_amount); + float get_fog_sun_scatter() const; + + void set_fog_density(float p_amount); + float get_fog_density() const; + void set_fog_height(float p_amount); + float get_fog_height() const; + void set_fog_height_density(float p_amount); + float get_fog_height_density() const; + void set_fog_aerial_perspective(float p_aerial_perspective); + float get_fog_aerial_perspective() const; + + // Volumetric Fog + void set_volumetric_fog_enabled(bool p_enable); + bool is_volumetric_fog_enabled() const; + void set_volumetric_fog_density(float p_density); + float get_volumetric_fog_density() const; + void set_volumetric_fog_light(Color p_color); + Color get_volumetric_fog_light() const; + void set_volumetric_fog_light_energy(float p_begin); + float get_volumetric_fog_light_energy() const; + void set_volumetric_fog_length(float p_length); + float get_volumetric_fog_length() const; + void set_volumetric_fog_detail_spread(float p_detail_spread); + float get_volumetric_fog_detail_spread() const; + void set_volumetric_fog_gi_inject(float p_gi_inject); + float get_volumetric_fog_gi_inject() const; + void set_volumetric_fog_temporal_reprojection_enabled(bool p_enable); + bool is_volumetric_fog_temporal_reprojection_enabled() const; + void set_volumetric_fog_temporal_reprojection_amount(float p_amount); + float get_volumetric_fog_temporal_reprojection_amount() const; + + // Adjustment + void set_adjustment_enabled(bool p_enabled); + bool is_adjustment_enabled() const; + void set_adjustment_brightness(float p_brightness); + float get_adjustment_brightness() const; + void set_adjustment_contrast(float p_contrast); + float get_adjustment_contrast() const; + void set_adjustment_saturation(float p_saturation); + float get_adjustment_saturation() const; + void set_adjustment_color_correction(Ref<Texture> p_color_correction); + Ref<Texture> get_adjustment_color_correction() const; Environment(); ~Environment(); @@ -364,63 +413,9 @@ VARIANT_ENUM_CAST(Environment::BGMode) VARIANT_ENUM_CAST(Environment::AmbientSource) VARIANT_ENUM_CAST(Environment::ReflectionSource) VARIANT_ENUM_CAST(Environment::ToneMapper) +VARIANT_ENUM_CAST(Environment::SDFGICascades) +VARIANT_ENUM_CAST(Environment::SDFGIYScale) VARIANT_ENUM_CAST(Environment::GlowBlendMode) -VARIANT_ENUM_CAST(Environment::SSAOBlur) - -class CameraEffects : public Resource { - GDCLASS(CameraEffects, Resource); - -private: - RID camera_effects; - - bool dof_blur_far_enabled; - float dof_blur_far_distance; - float dof_blur_far_transition; - - bool dof_blur_near_enabled; - float dof_blur_near_distance; - float dof_blur_near_transition; - - float dof_blur_amount; - - bool override_exposure_enabled; - float override_exposure; - -protected: - static void _bind_methods(); - -public: - void set_dof_blur_far_enabled(bool p_enable); - bool is_dof_blur_far_enabled() const; - - void set_dof_blur_far_distance(float p_distance); - float get_dof_blur_far_distance() const; - - void set_dof_blur_far_transition(float p_distance); - float get_dof_blur_far_transition() const; - - void set_dof_blur_near_enabled(bool p_enable); - bool is_dof_blur_near_enabled() const; - - void set_dof_blur_near_distance(float p_distance); - float get_dof_blur_near_distance() const; - - void set_dof_blur_near_transition(float p_distance); - float get_dof_blur_near_transition() const; - - void set_dof_blur_amount(float p_amount); - float get_dof_blur_amount() const; - - void set_override_exposure_enabled(bool p_enabled); - bool is_override_exposure_enabled() const; - - void set_override_exposure(float p_exposure); - float get_override_exposure() const; - - virtual RID get_rid() const; - - CameraEffects(); - ~CameraEffects(); -}; +VARIANT_ENUM_CAST(Environment::VolumetricFogShadowFilter) #endif // ENVIRONMENT_H diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 1878b174e8..6f87c524d8 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,641 +31,1101 @@ #include "font.h" #include "core/io/resource_loader.h" -#include "core/method_bind_ext.gen.inc" -#include "core/os/file_access.h" +#include "core/string/translation.h" +#include "core/templates/hashfuncs.h" +#include "scene/resources/text_line.h" +#include "scene/resources/text_paragraph.h" -void Font::draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate, const Color &p_outline_modulate) const { - float length = get_string_size(p_text).width; - if (length >= p_width) { - draw(p_canvas_item, p_pos, p_text, p_modulate, p_width, p_outline_modulate); - return; - } +void FontData::_bind_methods() { + ClassDB::bind_method(D_METHOD("load_resource", "filename", "base_size"), &FontData::load_resource, DEFVAL(16)); + ClassDB::bind_method(D_METHOD("load_memory", "data", "type", "base_size"), &FontData::_load_memory, DEFVAL(16)); + ClassDB::bind_method(D_METHOD("new_bitmap", "height", "ascent", "base_size"), &FontData::new_bitmap); - float ofs = 0.f; - switch (p_align) { - case HALIGN_LEFT: { - ofs = 0; - } break; - case HALIGN_CENTER: { - ofs = Math::floor((p_width - length) / 2.0); - } break; - case HALIGN_RIGHT: { - ofs = p_width - length; - } break; - default: { - ERR_PRINT("Unknown halignment type"); - } break; - } - draw(p_canvas_item, p_pos + Point2(ofs, 0), p_text, p_modulate, p_width, p_outline_modulate); -} + ClassDB::bind_method(D_METHOD("bitmap_add_texture", "texture"), &FontData::bitmap_add_texture); + ClassDB::bind_method(D_METHOD("bitmap_add_char", "char", "texture_idx", "rect", "align", "advance"), &FontData::bitmap_add_char); + ClassDB::bind_method(D_METHOD("bitmap_add_kerning_pair", "A", "B", "kerning"), &FontData::bitmap_add_kerning_pair); -void Font::draw(RID p_canvas_item, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w, const Color &p_outline_modulate) const { - Vector2 ofs; + ClassDB::bind_method(D_METHOD("set_data_path", "path"), &FontData::set_data_path); + ClassDB::bind_method(D_METHOD("get_data_path"), &FontData::get_data_path); - int chars_drawn = 0; - bool with_outline = has_outline(); - for (int i = 0; i < p_text.length(); i++) { - int width = get_char_size(p_text[i]).width; + ClassDB::bind_method(D_METHOD("get_height", "size"), &FontData::get_height); + ClassDB::bind_method(D_METHOD("get_ascent", "size"), &FontData::get_ascent); + ClassDB::bind_method(D_METHOD("get_descent", "size"), &FontData::get_descent); - if (p_clip_w >= 0 && (ofs.x + width) > p_clip_w) { - break; //clip - } + ClassDB::bind_method(D_METHOD("get_underline_position", "size"), &FontData::get_underline_position); + ClassDB::bind_method(D_METHOD("get_underline_thickness", "size"), &FontData::get_underline_thickness); + + ClassDB::bind_method(D_METHOD("get_spacing", "type"), &FontData::get_spacing); + ClassDB::bind_method(D_METHOD("set_spacing", "type", "value"), &FontData::set_spacing); + + ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased); + ClassDB::bind_method(D_METHOD("get_antialiased"), &FontData::get_antialiased); + + ClassDB::bind_method(D_METHOD("get_variation_list"), &FontData::get_variation_list); + + ClassDB::bind_method(D_METHOD("set_variation", "tag", "value"), &FontData::set_variation); + ClassDB::bind_method(D_METHOD("get_variation", "tag"), &FontData::get_variation); + + ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontData::set_hinting); + ClassDB::bind_method(D_METHOD("get_hinting"), &FontData::get_hinting); + + ClassDB::bind_method(D_METHOD("set_force_autohinter", "enabled"), &FontData::set_force_autohinter); + ClassDB::bind_method(D_METHOD("get_force_autohinter"), &FontData::get_force_autohinter); + + ClassDB::bind_method(D_METHOD("set_distance_field_hint", "distance_field"), &FontData::set_distance_field_hint); + ClassDB::bind_method(D_METHOD("get_distance_field_hint"), &FontData::get_distance_field_hint); + + ClassDB::bind_method(D_METHOD("has_char", "char"), &FontData::has_char); + ClassDB::bind_method(D_METHOD("get_supported_chars"), &FontData::get_supported_chars); + + ClassDB::bind_method(D_METHOD("get_glyph_advance", "index", "size"), &FontData::get_glyph_advance); + ClassDB::bind_method(D_METHOD("get_glyph_kerning", "index_a", "index_b", "size"), &FontData::get_glyph_kerning); + + ClassDB::bind_method(D_METHOD("get_base_size"), &FontData::get_base_size); + + ClassDB::bind_method(D_METHOD("has_outline"), &FontData::has_outline); + + ClassDB::bind_method(D_METHOD("is_language_supported", "language"), &FontData::is_language_supported); + ClassDB::bind_method(D_METHOD("set_language_support_override", "language", "supported"), &FontData::set_language_support_override); + ClassDB::bind_method(D_METHOD("get_language_support_override", "language"), &FontData::get_language_support_override); + ClassDB::bind_method(D_METHOD("remove_language_support_override", "language"), &FontData::remove_language_support_override); + ClassDB::bind_method(D_METHOD("get_language_support_overrides"), &FontData::get_language_support_overrides); + + ClassDB::bind_method(D_METHOD("is_script_supported", "script"), &FontData::is_script_supported); + ClassDB::bind_method(D_METHOD("set_script_support_override", "script", "supported"), &FontData::set_script_support_override); + ClassDB::bind_method(D_METHOD("get_script_support_override", "script"), &FontData::get_script_support_override); + ClassDB::bind_method(D_METHOD("remove_script_support_override", "script"), &FontData::remove_script_support_override); + ClassDB::bind_method(D_METHOD("get_script_support_overrides"), &FontData::get_script_support_overrides); + + ClassDB::bind_method(D_METHOD("get_glyph_index", "char", "variation_selector"), &FontData::get_glyph_index, DEFVAL(0x0000)); + ClassDB::bind_method(D_METHOD("draw_glyph", "canvas", "size", "pos", "index", "color"), &FontData::draw_glyph, DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_glyph_outline", "canvas", "size", "outline_size", "pos", "index", "color"), &FontData::draw_glyph_outline, DEFVAL(Color(1, 1, 1))); - ofs.x += draw_char(p_canvas_item, p_pos + ofs, p_text[i], p_text[i + 1], with_outline ? p_outline_modulate : p_modulate, with_outline); - ++chars_drawn; + ADD_PROPERTY(PropertyInfo(Variant::STRING, "data_path", PROPERTY_HINT_FILE, "*.ttf,*.otf,*.woff,*.fnt,*.font"), "set_data_path", "get_data_path"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "get_antialiased"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter"), "set_force_autohinter", "get_force_autohinter"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_field_hint"), "set_distance_field_hint", "get_distance_field_hint"); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting"); + + ADD_GROUP("Extra Spacing", "extra_spacing"); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_glyph"), "set_spacing", "get_spacing", SPACING_GLYPH); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_space"), "set_spacing", "get_spacing", SPACING_SPACE); + + BIND_ENUM_CONSTANT(SPACING_GLYPH); + BIND_ENUM_CONSTANT(SPACING_SPACE); +} + +bool FontData::_set(const StringName &p_name, const Variant &p_value) { + String str = p_name; + if (str.begins_with("language_support_override/")) { + String lang = str.get_slicec('/', 1); + if (lang == "_new") { + return false; + } + set_language_support_override(lang, p_value); + return true; + } + if (str.begins_with("script_support_override/")) { + String scr = str.get_slicec('/', 1); + if (scr == "_new") { + return false; + } + set_script_support_override(scr, p_value); + return true; + } + if (str.begins_with("variation/")) { + String name = str.get_slicec('/', 1); + set_variation(name, p_value); + return true; } - if (has_outline()) { - ofs = Vector2(0, 0); - for (int i = 0; i < chars_drawn; i++) { - ofs.x += draw_char(p_canvas_item, p_pos + ofs, p_text[i], p_text[i + 1], p_modulate, false); + return false; +} + +bool FontData::_get(const StringName &p_name, Variant &r_ret) const { + String str = p_name; + if (str.begins_with("language_support_override/")) { + String lang = str.get_slicec('/', 1); + if (lang == "_new") { + return true; } + r_ret = get_language_support_override(lang); + return true; } + if (str.begins_with("script_support_override/")) { + String scr = str.get_slicec('/', 1); + if (scr == "_new") { + return true; + } + r_ret = get_script_support_override(scr); + return true; + } + if (str.begins_with("variation/")) { + String name = str.get_slicec('/', 1); + + r_ret = get_variation(name); + return true; + } + + return false; } -void Font::update_changes() { - emit_changed(); +void FontData::_get_property_list(List<PropertyInfo> *p_list) const { + Vector<String> lang_over = get_language_support_overrides(); + for (int i = 0; i < lang_over.size(); i++) { + p_list->push_back(PropertyInfo(Variant::BOOL, "language_support_override/" + lang_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE)); + } + p_list->push_back(PropertyInfo(Variant::NIL, "language_support_override/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + + Vector<String> scr_over = get_script_support_overrides(); + for (int i = 0; i < scr_over.size(); i++) { + p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE)); + } + p_list->push_back(PropertyInfo(Variant::NIL, "script_support_override/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + + Dictionary variations = get_variation_list(); + for (const Variant *ftr = variations.next(nullptr); ftr != nullptr; ftr = variations.next(ftr)) { + Vector3i v = variations[*ftr]; + p_list->push_back(PropertyInfo(Variant::FLOAT, "variation/" + TS->tag_to_name(*ftr), PROPERTY_HINT_RANGE, itos(v.x) + "," + itos(v.y), PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE)); + } } -void Font::_bind_methods() { - ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "string", "modulate", "clip_w", "outline_modulate"), &Font::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(-1), DEFVAL(Color(1, 1, 1))); - ClassDB::bind_method(D_METHOD("get_ascent"), &Font::get_ascent); - ClassDB::bind_method(D_METHOD("get_descent"), &Font::get_descent); - 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", "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); +void FontData::reset_state() { + if (rid != RID()) { + TS->free(rid); + } + base_size = 16; + path = String(); } -Font::Font() { +RID FontData::get_rid() const { + return rid; } -///////////////////////////////////////////////////////////////// +void FontData::load_resource(const String &p_filename, int p_base_size) { + if (rid != RID()) { + TS->free(rid); + } + rid = TS->create_font_resource(p_filename, p_base_size); + path = p_filename; + base_size = TS->font_get_base_size(rid); + emit_changed(); +} -void BitmapFont::_set_chars(const Vector<int> &p_chars) { - int len = p_chars.size(); - //char 1 charsize 1 texture, 4 rect, 2 align, advance 1 - ERR_FAIL_COND(len % 9); - if (!len) { - return; //none to do +void FontData::_load_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size) { + if (rid != RID()) { + TS->free(rid); } - int chars = len / 9; + rid = TS->create_font_memory(p_data.ptr(), p_data.size(), p_type, p_base_size); + path = TTR("(Memory: " + p_type.to_upper() + " @ 0x" + String::num_int64((uint64_t)p_data.ptr(), 16, true) + ")"); + base_size = TS->font_get_base_size(rid); + emit_changed(); +} - const int *r = p_chars.ptr(); - for (int i = 0; i < chars; i++) { - const int *data = &r[i * 9]; - add_char(data[0], data[1], Rect2(data[2], data[3], data[4], data[5]), Size2(data[6], data[7]), data[8]); +void FontData::load_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size) { + if (rid != RID()) { + TS->free(rid); } + rid = TS->create_font_memory(p_data, p_size, p_type, p_base_size); + path = TTR("(Memory: " + p_type.to_upper() + " @ 0x" + String::num_int64((uint64_t)p_data, 16, true) + ")"); + base_size = TS->font_get_base_size(rid); + emit_changed(); } -Vector<int> BitmapFont::_get_chars() const { - Vector<int> chars; +void FontData::new_bitmap(float p_height, float p_ascent, int p_base_size) { + if (rid != RID()) { + TS->free(rid); + } + rid = TS->create_font_bitmap(p_height, p_ascent, p_base_size); + path = TTR("(Bitmap: " + String::num_int64(rid.get_id(), 16, true) + ")"); + base_size = TS->font_get_base_size(rid); + emit_changed(); +} - const CharType *key = nullptr; +void FontData::bitmap_add_texture(const Ref<Texture> &p_texture) { + if (rid != RID()) { + TS->font_bitmap_add_texture(rid, p_texture); + } +} - while ((key = char_map.next(key))) { - const Character *c = char_map.getptr(*key); - ERR_FAIL_COND_V(!c, Vector<int>()); - chars.push_back(*key); - chars.push_back(c->texture_idx); - chars.push_back(c->rect.position.x); - chars.push_back(c->rect.position.y); +void FontData::bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) { + if (rid != RID()) { + TS->font_bitmap_add_char(rid, p_char, p_texture_idx, p_rect, p_align, p_advance); + } +} - chars.push_back(c->rect.size.x); - chars.push_back(c->rect.size.y); - chars.push_back(c->h_align); - chars.push_back(c->v_align); - chars.push_back(c->advance); +void FontData::bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) { + if (rid != RID()) { + TS->font_bitmap_add_kerning_pair(rid, p_A, p_B, p_kerning); } +} - return chars; +void FontData::set_data_path(const String &p_path) { + load_resource(p_path, base_size); } -void BitmapFont::_set_kernings(const Vector<int> &p_kernings) { - int len = p_kernings.size(); - ERR_FAIL_COND(len % 3); - if (!len) { - return; +String FontData::get_data_path() const { + return path; +} + +float FontData::get_height(int p_size) const { + if (rid == RID()) { + return 0.f; // Do not raise errors in getters, to prevent editor from spamming errors on incomplete (without data_path set) fonts. } - const int *r = p_kernings.ptr(); + return TS->font_get_height(rid, (p_size < 0) ? base_size : p_size); +} - for (int i = 0; i < len / 3; i++) { - const int *data = &r[i * 3]; - add_kerning_pair(data[0], data[1], data[2]); +float FontData::get_ascent(int p_size) const { + if (rid == RID()) { + return 0.f; } + return TS->font_get_ascent(rid, (p_size < 0) ? base_size : p_size); } -Vector<int> BitmapFont::_get_kernings() const { - Vector<int> kernings; +float FontData::get_descent(int p_size) const { + if (rid == RID()) { + return 0.f; + } + return TS->font_get_descent(rid, (p_size < 0) ? base_size : p_size); +} - for (Map<KerningPairKey, int>::Element *E = kerning_map.front(); E; E = E->next()) { - kernings.push_back(E->key().A); - kernings.push_back(E->key().B); - kernings.push_back(E->get()); +float FontData::get_underline_position(int p_size) const { + if (rid == RID()) { + return 0.f; } + return TS->font_get_underline_position(rid, (p_size < 0) ? base_size : p_size); +} - return kernings; +Dictionary FontData::get_feature_list() const { + if (rid == RID()) { + return Dictionary(); + } + return TS->font_get_feature_list(rid); } -void BitmapFont::_set_textures(const Vector<Variant> &p_textures) { - textures.clear(); - for (int i = 0; i < p_textures.size(); i++) { - Ref<Texture2D> tex = p_textures[i]; - ERR_CONTINUE(!tex.is_valid()); - add_texture(tex); +float FontData::get_underline_thickness(int p_size) const { + if (rid == RID()) { + return 0.f; } + return TS->font_get_underline_thickness(rid, (p_size < 0) ? base_size : p_size); } -Vector<Variant> BitmapFont::_get_textures() const { - Vector<Variant> rtextures; - for (int i = 0; i < textures.size(); i++) { - rtextures.push_back(textures[i]); +Dictionary FontData::get_variation_list() const { + if (rid == RID()) { + return Dictionary(); } - return rtextures; + return TS->font_get_variation_list(rid); } -Error BitmapFont::create_from_fnt(const String &p_file) { - //fnt format used by angelcode bmfont - //http://www.angelcode.com/products/bmfont/ +void FontData::set_variation(const String &p_name, double p_value) { + ERR_FAIL_COND(rid == RID()); + TS->font_set_variation(rid, p_name, p_value); + emit_changed(); +} - FileAccess *f = FileAccess::open(p_file, FileAccess::READ); +double FontData::get_variation(const String &p_name) const { + if (rid == RID()) { + return 0; + } + return TS->font_get_variation(rid, p_name); +} - ERR_FAIL_COND_V_MSG(!f, ERR_FILE_NOT_FOUND, "Can't open font: " + p_file + "."); +int FontData::get_spacing(int p_type) const { + if (rid == RID()) { + return 0; + } + if (p_type == SPACING_GLYPH) { + return TS->font_get_spacing_glyph(rid); + } else { + return TS->font_get_spacing_space(rid); + } +} - clear(); +void FontData::set_spacing(int p_type, int p_value) { + ERR_FAIL_COND(rid == RID()); + if (p_type == SPACING_GLYPH) { + TS->font_set_spacing_glyph(rid, p_value); + } else { + TS->font_set_spacing_space(rid, p_value); + } + emit_changed(); +} - while (true) { - String line = f->get_line(); +void FontData::set_antialiased(bool p_antialiased) { + ERR_FAIL_COND(rid == RID()); + TS->font_set_antialiased(rid, p_antialiased); + emit_changed(); +} - int delimiter = line.find(" "); - String type = line.substr(0, delimiter); - int pos = delimiter + 1; - Map<String, String> keys; +bool FontData::get_antialiased() const { + if (rid == RID()) { + return false; + } + return TS->font_get_antialiased(rid); +} - while (pos < line.size() && line[pos] == ' ') { - pos++; - } +void FontData::set_distance_field_hint(bool p_distance_field) { + ERR_FAIL_COND(rid == RID()); + TS->font_set_distance_field_hint(rid, p_distance_field); + emit_changed(); +} - while (pos < line.size()) { - int eq = line.find("=", pos); - if (eq == -1) { - break; - } - String key = line.substr(pos, eq - pos); - int end = -1; - String value; - if (line[eq + 1] == '"') { - end = line.find("\"", eq + 2); - if (end == -1) { - break; - } - value = line.substr(eq + 2, end - 1 - eq - 1); - pos = end + 1; - } else { - end = line.find(" ", eq + 1); - if (end == -1) { - end = line.size(); - } +bool FontData::get_distance_field_hint() const { + if (rid == RID()) { + return false; + } + return TS->font_get_distance_field_hint(rid); +} - value = line.substr(eq + 1, end - eq); +void FontData::set_hinting(TextServer::Hinting p_hinting) { + ERR_FAIL_COND(rid == RID()); + TS->font_set_hinting(rid, p_hinting); + emit_changed(); +} - pos = end; - } +TextServer::Hinting FontData::get_hinting() const { + if (rid == RID()) { + return TextServer::HINTING_NONE; + } + return TS->font_get_hinting(rid); +} - while (pos < line.size() && line[pos] == ' ') { - pos++; - } +void FontData::set_force_autohinter(bool p_enabeld) { + ERR_FAIL_COND(rid == RID()); + TS->font_set_force_autohinter(rid, p_enabeld); + emit_changed(); +} - keys[key] = value; - } +bool FontData::get_force_autohinter() const { + if (rid == RID()) { + return false; + } + return TS->font_get_force_autohinter(rid); +} - if (type == "info") { - if (keys.has("face")) { - set_name(keys["face"]); - } - /* - if (keys.has("size")) - font->set_height(keys["size"].to_int()); - */ - - } else if (type == "common") { - if (keys.has("lineHeight")) { - set_height(keys["lineHeight"].to_int()); - } - if (keys.has("base")) { - set_ascent(keys["base"].to_int()); - } +bool FontData::has_char(char32_t p_char) const { + if (rid == RID()) { + return false; + } + return TS->font_has_char(rid, p_char); +} - } else if (type == "page") { - if (keys.has("file")) { - String base_dir = p_file.get_base_dir(); - String file = base_dir.plus_file(keys["file"]); - Ref<Texture2D> tex = ResourceLoader::load(file); - if (tex.is_null()) { - ERR_PRINT("Can't load font texture!"); - } else { - add_texture(tex); - } - } - } else if (type == "char") { - CharType idx = 0; - if (keys.has("id")) { - idx = keys["id"].to_int(); - } +String FontData::get_supported_chars() const { + ERR_FAIL_COND_V(rid == RID(), String()); + return TS->font_get_supported_chars(rid); +} - Rect2 rect; +Vector2 FontData::get_glyph_advance(uint32_t p_index, int p_size) const { + ERR_FAIL_COND_V(rid == RID(), Vector2()); + return TS->font_get_glyph_advance(rid, p_index, (p_size < 0) ? base_size : p_size); +} - if (keys.has("x")) { - rect.position.x = keys["x"].to_int(); - } - if (keys.has("y")) { - rect.position.y = keys["y"].to_int(); - } - if (keys.has("width")) { - rect.size.width = keys["width"].to_int(); - } - if (keys.has("height")) { - rect.size.height = keys["height"].to_int(); - } +Vector2 FontData::get_glyph_kerning(uint32_t p_index_a, uint32_t p_index_b, int p_size) const { + ERR_FAIL_COND_V(rid == RID(), Vector2()); + return TS->font_get_glyph_kerning(rid, p_index_a, p_index_b, (p_size < 0) ? base_size : p_size); +} - Point2 ofs; +bool FontData::has_outline() const { + if (rid == RID()) { + return false; + } + return TS->font_has_outline(rid); +} - if (keys.has("xoffset")) { - ofs.x = keys["xoffset"].to_int(); - } - if (keys.has("yoffset")) { - ofs.y = keys["yoffset"].to_int(); - } +float FontData::get_base_size() const { + return base_size; +} - int texture = 0; - if (keys.has("page")) { - texture = keys["page"].to_int(); - } - int advance = -1; - if (keys.has("xadvance")) { - advance = keys["xadvance"].to_int(); - } +bool FontData::is_language_supported(const String &p_language) const { + if (rid == RID()) { + return false; + } + return TS->font_is_language_supported(rid, p_language); +} - add_char(idx, texture, rect, ofs, advance); +void FontData::set_language_support_override(const String &p_language, bool p_supported) { + ERR_FAIL_COND(rid == RID()); + TS->font_set_language_support_override(rid, p_language, p_supported); + emit_changed(); +} - } else if (type == "kerning") { - CharType first = 0, second = 0; - int k = 0; +bool FontData::get_language_support_override(const String &p_language) const { + if (rid == RID()) { + return false; + } + return TS->font_get_language_support_override(rid, p_language); +} - if (keys.has("first")) { - first = keys["first"].to_int(); - } - if (keys.has("second")) { - second = keys["second"].to_int(); - } - if (keys.has("amount")) { - k = keys["amount"].to_int(); - } +void FontData::remove_language_support_override(const String &p_language) { + ERR_FAIL_COND(rid == RID()); + TS->font_remove_language_support_override(rid, p_language); + emit_changed(); +} - add_kerning_pair(first, second, -k); - } +Vector<String> FontData::get_language_support_overrides() const { + if (rid == RID()) { + return Vector<String>(); + } + return TS->font_get_language_support_overrides(rid); +} - if (f->eof_reached()) { - break; - } +bool FontData::is_script_supported(const String &p_script) const { + if (rid == RID()) { + return false; } + return TS->font_is_script_supported(rid, p_script); +} - memdelete(f); +void FontData::set_script_support_override(const String &p_script, bool p_supported) { + ERR_FAIL_COND(rid == RID()); + TS->font_set_script_support_override(rid, p_script, p_supported); + emit_changed(); +} - return OK; +bool FontData::get_script_support_override(const String &p_script) const { + if (rid == RID()) { + return false; + } + return TS->font_get_script_support_override(rid, p_script); } -void BitmapFont::set_height(float p_height) { - height = p_height; +void FontData::remove_script_support_override(const String &p_script) { + ERR_FAIL_COND(rid == RID()); + TS->font_remove_script_support_override(rid, p_script); + emit_changed(); } -float BitmapFont::get_height() const { - return height; +Vector<String> FontData::get_script_support_overrides() const { + if (rid == RID()) { + return Vector<String>(); + } + return TS->font_get_script_support_overrides(rid); } -void BitmapFont::set_ascent(float p_ascent) { - ascent = p_ascent; +uint32_t FontData::get_glyph_index(char32_t p_char, char32_t p_variation_selector) const { + ERR_FAIL_COND_V(rid == RID(), 0); + return TS->font_get_glyph_index(rid, p_char, p_variation_selector); } -float BitmapFont::get_ascent() const { - return ascent; +Vector2 FontData::draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const { + ERR_FAIL_COND_V(rid == RID(), Vector2()); + return TS->font_draw_glyph(rid, p_canvas, (p_size <= 0) ? base_size : p_size, p_pos, p_index, p_color); } -float BitmapFont::get_descent() const { - return height - ascent; +Vector2 FontData::draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const { + ERR_FAIL_COND_V(rid == RID(), Vector2()); + return TS->font_draw_glyph_outline(rid, p_canvas, (p_size <= 0) ? base_size : p_size, p_outline_size, p_pos, p_index, p_color); } -float BitmapFont::get_underline_position() const { - return 2; +FontData::FontData() {} + +FontData::FontData(const String &p_filename, int p_base_size) { + load_resource(p_filename, p_base_size); } -float BitmapFont::get_underline_thickness() const { - return 1; +FontData::FontData(const PackedByteArray &p_data, const String &p_type, int p_base_size) { + _load_memory(p_data, p_type, p_base_size); } -void BitmapFont::add_texture(const Ref<Texture2D> &p_texture) { - ERR_FAIL_COND_MSG(p_texture.is_null(), "It's not a reference to a valid Texture object."); - textures.push_back(p_texture); +FontData::~FontData() { + if (rid != RID()) { + TS->free(rid); + } } -int BitmapFont::get_texture_count() const { - return textures.size(); -}; +/*************************************************************************/ -Ref<Texture2D> BitmapFont::get_texture(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, textures.size(), Ref<Texture2D>()); - return textures[p_idx]; -}; +void Font::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_data", "data"), &Font::add_data); + ClassDB::bind_method(D_METHOD("set_data", "idx", "data"), &Font::set_data); + ClassDB::bind_method(D_METHOD("get_data_count"), &Font::get_data_count); + ClassDB::bind_method(D_METHOD("get_data", "idx"), &Font::get_data); + ClassDB::bind_method(D_METHOD("remove_data", "idx"), &Font::remove_data); -int BitmapFont::get_character_count() const { - return char_map.size(); -}; + ClassDB::bind_method(D_METHOD("get_height", "size"), &Font::get_height, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_ascent", "size"), &Font::get_ascent, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_descent", "size"), &Font::get_descent, DEFVAL(-1)); -Vector<CharType> BitmapFont::get_char_keys() const { - Vector<CharType> chars; - chars.resize(char_map.size()); - const CharType *ct = nullptr; - int count = 0; - while ((ct = char_map.next(ct))) { - chars.write[count++] = *ct; - }; + ClassDB::bind_method(D_METHOD("get_underline_position", "size"), &Font::get_underline_position, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_underline_thickness", "size"), &Font::get_underline_thickness, DEFVAL(-1)); - return chars; -}; + ClassDB::bind_method(D_METHOD("get_spacing", "type"), &Font::get_spacing); + ClassDB::bind_method(D_METHOD("set_spacing", "type", "value"), &Font::set_spacing); -BitmapFont::Character BitmapFont::get_character(CharType p_char) const { - if (!char_map.has(p_char)) { - ERR_FAIL_V(Character()); - }; + ClassDB::bind_method(D_METHOD("get_string_size", "text", "size"), &Font::get_string_size, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_multiline_string_size", "text", "width", "size", "flags"), &Font::get_multiline_string_size, DEFVAL(-1), DEFVAL(-1), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND)); - return char_map[p_char]; -}; + ClassDB::bind_method(D_METHOD("draw_string", "canvas_item", "pos", "text", "align", "width", "size", "modulate", "outline_size", "outline_modulate", "flags"), &Font::draw_string, DEFVAL(HALIGN_LEFT), DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND)); + ClassDB::bind_method(D_METHOD("draw_multiline_string", "canvas_item", "pos", "text", "align", "width", "max_lines", "size", "modulate", "outline_size", "outline_modulate", "flags"), &Font::draw_multiline_string, DEFVAL(HALIGN_LEFT), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND)); -void BitmapFont::add_char(CharType p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) { - if (p_advance < 0) { - p_advance = p_rect.size.width; - } + ClassDB::bind_method(D_METHOD("has_char", "char"), &Font::has_char); + ClassDB::bind_method(D_METHOD("get_supported_chars"), &Font::get_supported_chars); + + ClassDB::bind_method(D_METHOD("get_char_size", "char", "next", "size"), &Font::get_char_size, DEFVAL(0), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "pos", "char", "next", "size", "modulate", "outline_size", "outline_modulate"), &Font::draw_char, DEFVAL(0), DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(1, 1, 1, 0))); + + ClassDB::bind_method(D_METHOD("update_changes"), &Font::update_changes); - Character c; - c.rect = p_rect; - c.texture_idx = p_texture_idx; - c.v_align = p_align.y; - c.advance = p_advance; - c.h_align = p_align.x; + ADD_GROUP("Extra Spacing", "extra_spacing"); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_top"), "set_spacing", "get_spacing", SPACING_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_bottom"), "set_spacing", "get_spacing", SPACING_BOTTOM); - char_map[p_char] = c; + BIND_ENUM_CONSTANT(SPACING_TOP); + BIND_ENUM_CONSTANT(SPACING_BOTTOM); } -void BitmapFont::add_kerning_pair(CharType p_A, CharType p_B, int p_kerning) { - KerningPairKey kpk; - kpk.A = p_A; - kpk.B = p_B; +void Font::_data_changed() { + cache.clear(); + cache_wrap.clear(); - if (p_kerning == 0 && kerning_map.has(kpk)) { - kerning_map.erase(kpk); - } else { - kerning_map[kpk] = p_kerning; + emit_changed(); + notify_property_list_changed(); +} + +bool Font::_set(const StringName &p_name, const Variant &p_value) { + String str = p_name; +#ifndef DISABLE_DEPRECATED + if (str == "font_data") { // Compatibility, DynamicFont main data + Ref<FontData> fd = p_value; + if (fd.is_valid()) { + add_data(fd); + return true; + } + return false; + } else if (str.begins_with("fallback/")) { // Compatibility, DynamicFont fallback data + Ref<FontData> fd = p_value; + if (fd.is_valid()) { + add_data(fd); + return true; + } + return false; + } else if (str == "fallback") { // Compatibility, BitmapFont fallback + Ref<Font> f = p_value; + if (f.is_valid()) { + for (int i = 0; i < f->get_data_count(); i++) { + add_data(f->get_data(i)); + } + return true; + } + return false; } +#endif /* DISABLE_DEPRECATED */ + if (str.begins_with("data/")) { + int idx = str.get_slicec('/', 1).to_int(); + Ref<FontData> fd = p_value; + + if (fd.is_valid()) { + if (idx == data.size()) { + add_data(fd); + return true; + } else if (idx >= 0 && idx < data.size()) { + set_data(idx, fd); + return true; + } else { + return false; + } + } else if (idx >= 0 && idx < data.size()) { + remove_data(idx); + return true; + } + } + + return false; } -Vector<BitmapFont::KerningPairKey> BitmapFont::get_kerning_pair_keys() const { - Vector<BitmapFont::KerningPairKey> ret; - ret.resize(kerning_map.size()); - int i = 0; +bool Font::_get(const StringName &p_name, Variant &r_ret) const { + String str = p_name; + if (str.begins_with("data/")) { + int idx = str.get_slicec('/', 1).to_int(); + + if (idx == data.size()) { + r_ret = Ref<FontData>(); + return true; + } else if (idx >= 0 && idx < data.size()) { + r_ret = get_data(idx); + return true; + } + } + + return false; +} - for (Map<KerningPairKey, int>::Element *E = kerning_map.front(); E; E = E->next()) { - ret.write[i++] = E->key(); +void Font::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < data.size(); i++) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "FontData")); } - return ret; + p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(data.size()), PROPERTY_HINT_RESOURCE_TYPE, "FontData")); +} + +void Font::reset_state() { + spacing_top = 0; + spacing_bottom = 0; + cache.clear(); + cache_wrap.clear(); + data.clear(); } -int BitmapFont::get_kerning_pair(CharType p_A, CharType p_B) const { - KerningPairKey kpk; - kpk.A = p_A; - kpk.B = p_B; +void Font::add_data(const Ref<FontData> &p_data) { + ERR_FAIL_COND(p_data.is_null()); + data.push_back(p_data); - const Map<KerningPairKey, int>::Element *E = kerning_map.find(kpk); - if (E) { - return E->get(); + if (data[data.size() - 1].is_valid()) { + data.write[data.size() - 1]->connect("changed", callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED); } - return 0; + cache.clear(); + cache_wrap.clear(); + + emit_changed(); + notify_property_list_changed(); } -void BitmapFont::set_distance_field_hint(bool p_distance_field) { - distance_field_hint = p_distance_field; +void Font::set_data(int p_idx, const Ref<FontData> &p_data) { + ERR_FAIL_COND(p_data.is_null()); + ERR_FAIL_INDEX(p_idx, data.size()); + + if (data[p_idx].is_valid()) { + data.write[p_idx]->disconnect("changed", callable_mp(this, &Font::_data_changed)); + } + + data.write[p_idx] = p_data; + + if (data[p_idx].is_valid()) { + data.write[p_idx]->connect("changed", callable_mp(this, &Font::_data_changed), varray(), CONNECT_REFERENCE_COUNTED); + } + + cache.clear(); + cache_wrap.clear(); + emit_changed(); + notify_property_list_changed(); +} + +int Font::get_data_count() const { + return data.size(); } -bool BitmapFont::is_distance_field_hint() const { - return distance_field_hint; +Ref<FontData> Font::get_data(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, data.size(), Ref<FontData>()); + return data[p_idx]; } -void BitmapFont::clear() { - height = 1; - ascent = 0; - char_map.clear(); - textures.clear(); - kerning_map.clear(); - distance_field_hint = false; +void Font::remove_data(int p_idx) { + ERR_FAIL_INDEX(p_idx, data.size()); + + if (data[p_idx].is_valid()) { + data.write[p_idx]->disconnect("changed", callable_mp(this, &Font::_data_changed)); + } + + data.remove(p_idx); + + cache.clear(); + cache_wrap.clear(); + + emit_changed(); + notify_property_list_changed(); } -Size2 Font::get_string_size(const String &p_string) const { - float w = 0; +Dictionary Font::get_feature_list() const { + Dictionary out; + for (int i = 0; i < data.size(); i++) { + Dictionary data_ftrs = data[i]->get_feature_list(); + for (const Variant *ftr = data_ftrs.next(nullptr); ftr != nullptr; ftr = data_ftrs.next(ftr)) { + out[*ftr] = data_ftrs[*ftr]; + } + } + return out; +} - int l = p_string.length(); - if (l == 0) { - return Size2(0, get_height()); +float Font::get_height(int p_size) const { + float ret = 0.f; + for (int i = 0; i < data.size(); i++) { + ret = MAX(ret, data[i]->get_height(p_size)); } - const CharType *sptr = &p_string[0]; + return ret + spacing_top + spacing_bottom; +} - for (int i = 0; i < l; i++) { - w += get_char_size(sptr[i], sptr[i + 1]).width; +float Font::get_ascent(int p_size) const { + float ret = 0.f; + for (int i = 0; i < data.size(); i++) { + ret = MAX(ret, data[i]->get_ascent(p_size)); } + return ret + spacing_top; +} - return Size2(w, get_height()); +float Font::get_descent(int p_size) const { + float ret = 0.f; + for (int i = 0; i < data.size(); i++) { + ret = MAX(ret, data[i]->get_descent(p_size)); + } + return ret + spacing_bottom; } -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())); +float Font::get_underline_position(int p_size) const { + float ret = 0.f; + for (int i = 0; i < data.size(); i++) { + ret = MAX(ret, data[i]->get_underline_position(p_size)); + } + return ret; +} - int l = p_string.length(); - if (l == 0) { - return Size2(p_width, get_height()); +float Font::get_underline_thickness(int p_size) const { + float ret = 0.f; + for (int i = 0; i < data.size(); i++) { + ret = MAX(ret, data[i]->get_underline_thickness(p_size)); } + return ret; +} - 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; - } - } +int Font::get_spacing(int p_type) const { + if (p_type == SPACING_TOP) { + return spacing_top; + } else if (p_type == SPACING_BOTTOM) { + return spacing_bottom; } - return Size2(p_width, h); + return 0; } -void BitmapFont::set_fallback(const Ref<BitmapFont> &p_fallback) { - for (Ref<BitmapFont> fallback_child = p_fallback; fallback_child != nullptr; fallback_child = fallback_child->get_fallback()) { - ERR_FAIL_COND_MSG(fallback_child == this, "Can't set as fallback one of its parents to prevent crashes due to recursive loop."); +void Font::set_spacing(int p_type, int p_value) { + if (p_type == SPACING_TOP) { + spacing_top = p_value; + } else if (p_type == SPACING_BOTTOM) { + spacing_bottom = p_value; } - fallback = p_fallback; + emit_changed(); + notify_property_list_changed(); } -Ref<BitmapFont> BitmapFont::get_fallback() const { - return fallback; +// Drawing string and string sizes, cached. + +Size2 Font::get_string_size(const String &p_text, int p_size) const { + ERR_FAIL_COND_V(data.is_empty(), Size2()); + + uint64_t hash = p_text.hash64(); + hash = hash_djb2_one_64(p_size, hash); + + Ref<TextLine> buffer; + if (cache.has(hash)) { + buffer = cache.get(hash); + } else { + buffer.instance(); + int size = p_size <= 0 ? data[0]->get_base_size() : p_size; + buffer->add_string(p_text, Ref<Font>(this), size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); + cache.insert(hash, buffer); + } + if (buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) { + return buffer->get_size() + Vector2(0, spacing_top + spacing_bottom); + } else { + return buffer->get_size() + Vector2(spacing_top + spacing_bottom, 0); + } } -float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const { - const Character *c = char_map.getptr(p_char); +Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p_size, uint8_t p_flags) const { + ERR_FAIL_COND_V(data.is_empty(), Size2()); + + uint64_t hash = p_text.hash64(); + hash = hash_djb2_one_64(p_size, hash); - if (!c) { - if (fallback.is_valid()) { - return fallback->draw_char(p_canvas_item, p_pos, p_char, p_next, p_modulate, p_outline); + uint64_t wrp_hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash); + wrp_hash = hash_djb2_one_64(p_flags, wrp_hash); + + Ref<TextParagraph> lines_buffer; + if (cache_wrap.has(wrp_hash)) { + lines_buffer = cache_wrap.get(wrp_hash); + } else { + lines_buffer.instance(); + int size = p_size <= 0 ? data[0]->get_base_size() : p_size; + lines_buffer->add_string(p_text, Ref<Font>(this), size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); + lines_buffer->set_width(p_width); + lines_buffer->set_flags(p_flags); + cache_wrap.insert(wrp_hash, lines_buffer); + } + + Size2 ret; + for (int i = 0; i < lines_buffer->get_line_count(); i++) { + Size2 line_size = lines_buffer->get_line_size(i); + if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) { + ret.x = MAX(ret.x, line_size.x); + ret.y += line_size.y + spacing_top + spacing_bottom; + } else { + ret.y = MAX(ret.y, line_size.y); + ret.x += line_size.x + spacing_top + spacing_bottom; } - return 0; } + return ret; +} + +void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const { + ERR_FAIL_COND(data.is_empty()); + + uint64_t hash = p_text.hash64(); + hash = hash_djb2_one_64(p_size, hash); - ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0); - if (!p_outline && c->texture_idx != -1) { - Point2 cpos = p_pos; - cpos.x += c->h_align; - cpos.y -= ascent; - cpos.y += c->v_align; - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, RID(), RID(), Color(1, 1, 1, 1), false); + Ref<TextLine> buffer; + if (cache.has(hash)) { + buffer = cache.get(hash); + } else { + buffer.instance(); + int size = p_size <= 0 ? data[0]->get_base_size() : p_size; + buffer->add_string(p_text, Ref<Font>(this), size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); + cache.insert(hash, buffer); } - return get_char_size(p_char, p_next).width; + Vector2 ofs = p_pos; + if (buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) { + ofs.y += spacing_top - buffer->get_line_ascent(); + } else { + ofs.x += spacing_top - buffer->get_line_ascent(); + } + + buffer->set_width(p_width); + buffer->set_align(p_align); + + if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) { + buffer->draw_outline(p_canvas_item, ofs, p_outline_size, p_outline_modulate); + } + buffer->draw(p_canvas_item, ofs, p_modulate); } -Size2 BitmapFont::get_char_size(CharType p_char, CharType p_next) const { - const Character *c = char_map.getptr(p_char); +void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const { + ERR_FAIL_COND(data.is_empty()); - if (!c) { - if (fallback.is_valid()) { - return fallback->get_char_size(p_char, p_next); - } - return Size2(); + uint64_t hash = p_text.hash64(); + hash = hash_djb2_one_64(p_size, hash); + + uint64_t wrp_hash = hash_djb2_one_64(hash_djb2_one_float(p_width), hash); + wrp_hash = hash_djb2_one_64(p_flags, wrp_hash); + + Ref<TextParagraph> lines_buffer; + if (cache_wrap.has(wrp_hash)) { + lines_buffer = cache_wrap.get(wrp_hash); + } else { + lines_buffer.instance(); + int size = p_size <= 0 ? data[0]->get_base_size() : p_size; + lines_buffer->add_string(p_text, Ref<Font>(this), size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); + lines_buffer->set_width(p_width); + lines_buffer->set_flags(p_flags); + cache_wrap.insert(wrp_hash, lines_buffer); } - Size2 ret(c->advance, c->rect.size.y); + lines_buffer->set_align(p_align); - if (p_next) { - KerningPairKey kpk; - kpk.A = p_char; - kpk.B = p_next; + Vector2 lofs = p_pos; + for (int i = 0; i < lines_buffer->get_line_count(); i++) { + if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) { + lofs.y += spacing_top; + if (i == 0) { + lofs.y -= lines_buffer->get_line_ascent(0); + } + } else { + lofs.x += spacing_top; + if (i == 0) { + lofs.x -= lines_buffer->get_line_ascent(0); + } + } + if (p_width > 0) { + lines_buffer->set_align(p_align); + } - const Map<KerningPairKey, int>::Element *E = kerning_map.find(kpk); - if (E) { - ret.width -= E->get(); + if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) { + lines_buffer->draw_line_outline(p_canvas_item, lofs, i, p_outline_size, p_outline_modulate); + } + lines_buffer->draw_line(p_canvas_item, lofs, i, p_modulate); + + Size2 line_size = lines_buffer->get_line_size(i); + if (lines_buffer->get_orientation() == TextServer::ORIENTATION_HORIZONTAL) { + lofs.y += line_size.y + spacing_bottom; + } else { + lofs.x += line_size.x + spacing_bottom; + } + + if ((p_max_lines > 0) && (i >= p_max_lines)) { + return; } } +} - return ret; +bool Font::has_char(char32_t p_char) const { + for (int i = 0; i < data.size(); i++) { + if (data[i]->has_char(p_char)) { + return true; + } + } + return false; } -void BitmapFont::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_from_fnt", "path"), &BitmapFont::create_from_fnt); - ClassDB::bind_method(D_METHOD("set_height", "px"), &BitmapFont::set_height); +String Font::get_supported_chars() const { + String chars; + for (int i = 0; i < data.size(); i++) { + String data_chars = data[i]->get_supported_chars(); + for (int j = 0; j < data_chars.length(); j++) { + if (chars.find_char(data_chars[j]) == -1) { + chars += data_chars[j]; + } + } + } + return chars; +} - ClassDB::bind_method(D_METHOD("set_ascent", "px"), &BitmapFont::set_ascent); +Size2 Font::get_char_size(char32_t p_char, char32_t p_next, int p_size) const { + for (int i = 0; i < data.size(); i++) { + if (data[i]->has_char(p_char)) { + int size = p_size <= 0 ? data[i]->get_base_size() : p_size; + uint32_t glyph_a = data[i]->get_glyph_index(p_char); + Size2 ret = Size2(data[i]->get_glyph_advance(glyph_a, size).x, data[i]->get_height(size)); + if ((p_next != 0) && data[i]->has_char(p_next)) { + uint32_t glyph_b = data[i]->get_glyph_index(p_next); + ret.x -= data[i]->get_glyph_kerning(glyph_a, glyph_b, size).x; + } + return ret; + } + } + return Size2(); +} - ClassDB::bind_method(D_METHOD("add_kerning_pair", "char_a", "char_b", "kerning"), &BitmapFont::add_kerning_pair); - ClassDB::bind_method(D_METHOD("get_kerning_pair", "char_a", "char_b"), &BitmapFont::get_kerning_pair); +float Font::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const { + for (int i = 0; i < data.size(); i++) { + if (data[i]->has_char(p_char)) { + int size = p_size <= 0 ? data[i]->get_base_size() : p_size; + uint32_t glyph_a = data[i]->get_glyph_index(p_char); + float ret = data[i]->get_glyph_advance(glyph_a, size).x; + if ((p_next != 0) && data[i]->has_char(p_next)) { + uint32_t glyph_b = data[i]->get_glyph_index(p_next); + ret -= data[i]->get_glyph_kerning(glyph_a, glyph_b, size).x; + } + if (p_outline_size > 0 && p_outline_modulate.a != 0.0f) { + data[i]->draw_glyph_outline(p_canvas_item, size, p_outline_size, p_pos, glyph_a, p_outline_modulate); + } + data[i]->draw_glyph(p_canvas_item, size, p_pos, glyph_a, p_modulate); + return ret; + } + } + return 0; +} - ClassDB::bind_method(D_METHOD("add_texture", "texture"), &BitmapFont::add_texture); - ClassDB::bind_method(D_METHOD("add_char", "character", "texture", "rect", "align", "advance"), &BitmapFont::add_char, DEFVAL(Point2()), DEFVAL(-1)); +Vector<RID> Font::get_rids() const { + Vector<RID> ret; + for (int i = 0; i < data.size(); i++) { + RID rid = data[i]->get_rid(); + if (rid != RID()) { + ret.push_back(rid); + } + } + return ret; +} - ClassDB::bind_method(D_METHOD("get_texture_count"), &BitmapFont::get_texture_count); - ClassDB::bind_method(D_METHOD("get_texture", "idx"), &BitmapFont::get_texture); +void Font::update_changes() { + emit_changed(); +} - ClassDB::bind_method(D_METHOD("get_char_size", "char", "next"), &BitmapFont::get_char_size, DEFVAL(0)); +Font::Font() { + cache.set_capacity(128); + cache_wrap.set_capacity(32); +} - ClassDB::bind_method(D_METHOD("set_distance_field_hint", "enable"), &BitmapFont::set_distance_field_hint); +Font::~Font() { + cache.clear(); + cache_wrap.clear(); +} - ClassDB::bind_method(D_METHOD("clear"), &BitmapFont::clear); +/*************************************************************************/ - ClassDB::bind_method(D_METHOD("_set_chars"), &BitmapFont::_set_chars); - ClassDB::bind_method(D_METHOD("_get_chars"), &BitmapFont::_get_chars); +RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + if (r_error) { + *r_error = ERR_FILE_CANT_OPEN; + } - ClassDB::bind_method(D_METHOD("_set_kernings"), &BitmapFont::_set_kernings); - ClassDB::bind_method(D_METHOD("_get_kernings"), &BitmapFont::_get_kernings); + Ref<FontData> dfont; + dfont.instance(); + dfont->load_resource(p_path); - ClassDB::bind_method(D_METHOD("_set_textures"), &BitmapFont::_set_textures); - ClassDB::bind_method(D_METHOD("_get_textures"), &BitmapFont::_get_textures); + if (r_error) { + *r_error = OK; + } - ClassDB::bind_method(D_METHOD("set_fallback", "fallback"), &BitmapFont::set_fallback); - ClassDB::bind_method(D_METHOD("get_fallback"), &BitmapFont::get_fallback); + return dfont; +} - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_textures", "_get_textures"); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "chars", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_chars", "_get_chars"); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "kernings", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_kernings", "_get_kernings"); +void ResourceFormatLoaderFont::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { +#ifndef DISABLE_DEPRECATED + if (p_type == "DynamicFontData") { + p_extensions->push_back("ttf"); + p_extensions->push_back("otf"); + p_extensions->push_back("woff"); + return; + } + if (p_type == "BitmapFont") { // BitmapFont (*.font, *fnt) is handled by ResourceFormatLoaderCompatFont + return; + } +#endif /* DISABLE_DEPRECATED */ + if (p_type == "" || handles_type(p_type)) { + get_recognized_extensions(p_extensions); + } +} - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "1,1024,1"), "set_height", "get_height"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ascent", PROPERTY_HINT_RANGE, "0,1024,1"), "set_ascent", "get_ascent"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_field"), "set_distance_field_hint", "is_distance_field_hint"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback", PROPERTY_HINT_RESOURCE_TYPE, "BitmapFont"), "set_fallback", "get_fallback"); +void ResourceFormatLoaderFont::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("ttf"); + p_extensions->push_back("otf"); + p_extensions->push_back("woff"); + p_extensions->push_back("font"); + p_extensions->push_back("fnt"); } -BitmapFont::BitmapFont() { - clear(); +bool ResourceFormatLoaderFont::handles_type(const String &p_type) const { + return (p_type == "FontData"); } -BitmapFont::~BitmapFont() { - clear(); +String ResourceFormatLoaderFont::get_resource_type(const String &p_path) const { + String el = p_path.get_extension().to_lower(); + if (el == "ttf" || el == "otf" || el == "woff" || el == "font" || el == "fnt") { + return "FontData"; + } + return ""; } -//////////// +#ifndef DISABLE_DEPRECATED -RES ResourceFormatLoaderBMFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; } - Ref<BitmapFont> font; - font.instance(); + Ref<FontData> dfont; + dfont.instance(); + dfont->load_resource(p_path); - Error err = font->create_from_fnt(p_path); + Ref<Font> font; + font.instance(); + font->add_data(dfont); - if (err) { - if (r_error) { - *r_error = err; - } - return RES(); + if (r_error) { + *r_error = OK; } return font; } -void ResourceFormatLoaderBMFont::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("fnt"); +void ResourceFormatLoaderCompatFont::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { + if (p_type == "BitmapFont") { + p_extensions->push_back("font"); + p_extensions->push_back("fnt"); + } } -bool ResourceFormatLoaderBMFont::handles_type(const String &p_type) const { - return (p_type == "BitmapFont"); +void ResourceFormatLoaderCompatFont::get_recognized_extensions(List<String> *p_extensions) const { } -String ResourceFormatLoaderBMFont::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "fnt") { - return "BitmapFont"; - } +bool ResourceFormatLoaderCompatFont::handles_type(const String &p_type) const { + return (p_type == "Font"); +} + +String ResourceFormatLoaderCompatFont::get_resource_type(const String &p_path) const { return ""; } + +#endif /* DISABLE_DEPRECATED */ diff --git a/scene/resources/font.h b/scene/resources/font.h index 14312308bb..200373aa8c 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,179 +31,215 @@ #ifndef FONT_H #define FONT_H -#include "core/map.h" -#include "core/resource.h" +#include "core/io/resource.h" +#include "core/templates/lru.h" +#include "core/templates/map.h" #include "scene/resources/texture.h" +#include "servers/text_server.h" -class Font : public Resource { - GDCLASS(Font, Resource); +/*************************************************************************/ + +class FontData : public Resource { + GDCLASS(FontData, Resource); + +public: + enum SpacingType { + SPACING_GLYPH, + SPACING_SPACE, + }; + +private: + RID rid; + int base_size = 16; + String path; protected: static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + virtual void reset_state() override; + public: - virtual float get_height() const = 0; + virtual RID get_rid() const override; - virtual float get_ascent() const = 0; - virtual float get_descent() const = 0; - virtual float get_underline_position() const = 0; - virtual float get_underline_thickness() const = 0; + void load_resource(const String &p_filename, int p_base_size = 16); + void load_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16); + void _load_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16); - 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; + void new_bitmap(float p_height, float p_ascent, int p_base_size = 16); - virtual bool is_distance_field_hint() const = 0; + void bitmap_add_texture(const Ref<Texture> &p_texture); + void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance); + void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning); - void draw(RID p_canvas_item, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1, const Color &p_outline_modulate = Color(1, 1, 1)) const; - void draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate = Color(1, 1, 1), const Color &p_outline_modulate = Color(1, 1, 1)) const; + void set_data_path(const String &p_path); + String get_data_path() const; - virtual bool has_outline() const { return false; } - virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const = 0; + float get_height(int p_size) const; + float get_ascent(int p_size) const; + float get_descent(int p_size) const; - void update_changes(); - Font(); -}; + Dictionary get_feature_list() const; + Dictionary get_variation_list() const; -// Helper class to that draws outlines immediately and draws characters in its destructor. -class FontDrawer { - const Ref<Font> &font; - Color outline_color; - bool has_outline; - - struct PendingDraw { - RID canvas_item; - Point2 pos; - CharType chr; - CharType next; - Color modulate; - }; + void set_variation(const String &p_name, double p_value); + double get_variation(const String &p_name) const; - Vector<PendingDraw> pending_draws; + float get_underline_position(int p_size) const; + float get_underline_thickness(int p_size) const; -public: - FontDrawer(const Ref<Font> &p_font, const Color &p_outline_color) : - font(p_font), - outline_color(p_outline_color) { - has_outline = p_font->has_outline(); - } - - float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) { - if (has_outline) { - PendingDraw draw = { p_canvas_item, p_pos, p_char, p_next, p_modulate }; - pending_draws.push_back(draw); - } - return font->draw_char(p_canvas_item, p_pos, p_char, p_next, has_outline ? outline_color : p_modulate, has_outline); - } - - ~FontDrawer() { - for (int i = 0; i < pending_draws.size(); ++i) { - const PendingDraw &draw = pending_draws[i]; - font->draw_char(draw.canvas_item, draw.pos, draw.chr, draw.next, draw.modulate, false); - } - } -}; + int get_spacing(int p_type) const; + void set_spacing(int p_type, int p_value); -class BitmapFont : public Font { - GDCLASS(BitmapFont, Font); - RES_BASE_EXTENSION("font"); + void set_antialiased(bool p_antialiased); + bool get_antialiased() const; - Vector<Ref<Texture2D>> textures; + void set_distance_field_hint(bool p_distance_field); + bool get_distance_field_hint() const; -public: - struct Character { - int texture_idx; - Rect2 rect; - float v_align; - float h_align; - float advance; - - Character() { - texture_idx = 0; - v_align = 0; - } - }; + void set_force_autohinter(bool p_enabeld); + bool get_force_autohinter() const; + + void set_hinting(TextServer::Hinting p_hinting); + TextServer::Hinting get_hinting() const; + + bool has_char(char32_t p_char) const; + String get_supported_chars() const; + + Vector2 get_glyph_advance(uint32_t p_index, int p_size) const; + Vector2 get_glyph_kerning(uint32_t p_index_a, uint32_t p_index_b, int p_size) const; + + bool has_outline() const; + float get_base_size() const; + + bool is_language_supported(const String &p_language) const; + void set_language_support_override(const String &p_language, bool p_supported); + bool get_language_support_override(const String &p_language) const; + void remove_language_support_override(const String &p_language); + Vector<String> get_language_support_overrides() const; + + bool is_script_supported(const String &p_script) const; + void set_script_support_override(const String &p_script, bool p_supported); + bool get_script_support_override(const String &p_script) const; + void remove_script_support_override(const String &p_script); + Vector<String> get_script_support_overrides() const; + + uint32_t get_glyph_index(char32_t p_char, char32_t p_variation_selector = 0x0000) const; - struct KerningPairKey { - union { - struct { - uint32_t A, B; - }; + Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const; + Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const; - uint64_t pair; - }; + FontData(); + FontData(const String &p_filename, int p_base_size); + FontData(const PackedByteArray &p_data, const String &p_type, int p_base_size); - _FORCE_INLINE_ bool operator<(const KerningPairKey &p_r) const { return pair < p_r.pair; } + ~FontData(); +}; + +/*************************************************************************/ + +class TextLine; +class TextParagraph; + +class Font : public Resource { + GDCLASS(Font, Resource); + +public: + enum SpacingType { + SPACING_TOP, + SPACING_BOTTOM, }; private: - HashMap<CharType, Character> char_map; - Map<KerningPairKey, int> kerning_map; - - float height; - float ascent; - bool distance_field_hint; + int spacing_top = 0; + int spacing_bottom = 0; - void _set_chars(const Vector<int> &p_chars); - Vector<int> _get_chars() const; - void _set_kernings(const Vector<int> &p_kernings); - Vector<int> _get_kernings() const; - void _set_textures(const Vector<Variant> &p_textures); - Vector<Variant> _get_textures() const; + mutable LRUCache<uint64_t, Ref<TextLine>> cache; + mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap; - Ref<BitmapFont> fallback; + Vector<Ref<FontData>> data; protected: static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + virtual void reset_state() override; + + void _data_changed(); + public: - Error create_from_fnt(const String &p_file); + Dictionary get_feature_list() const; - void set_height(float p_height); - float get_height() const; + // Font data control. + void add_data(const Ref<FontData> &p_data); + void set_data(int p_idx, const Ref<FontData> &p_data); + int get_data_count() const; + Ref<FontData> get_data(int p_idx) const; + void remove_data(int p_idx); - void set_ascent(float p_ascent); - float get_ascent() const; - float get_descent() const; - float get_underline_position() const; - float get_underline_thickness() const; + float get_height(int p_size = -1) const; + float get_ascent(int p_size = -1) const; + float get_descent(int p_size = -1) const; - void add_texture(const Ref<Texture2D> &p_texture); - void add_char(CharType p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance = -1); + float get_underline_position(int p_size = -1) const; + float get_underline_thickness(int p_size = -1) const; - int get_character_count() const; - Vector<CharType> get_char_keys() const; - Character get_character(CharType p_char) const; + int get_spacing(int p_type) const; + void set_spacing(int p_type, int p_value); - int get_texture_count() const; - Ref<Texture2D> get_texture(int p_idx) const; + // Drawing string. + Size2 get_string_size(const String &p_text, int p_size = -1) const; + Size2 get_multiline_string_size(const String &p_text, float p_width = -1, int p_size = -1, uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND) const; - void add_kerning_pair(CharType p_A, CharType p_B, int p_kerning); - int get_kerning_pair(CharType p_A, CharType p_B) const; - Vector<KerningPairKey> get_kerning_pair_keys() const; + void draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const; + void draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const; - Size2 get_char_size(CharType p_char, CharType p_next = 0) const; + // Helper functions. + bool has_char(char32_t p_char) const; + String get_supported_chars() const; - void set_fallback(const Ref<BitmapFont> &p_fallback); - Ref<BitmapFont> get_fallback() const; + Size2 get_char_size(char32_t p_char, char32_t p_next = 0, int p_size = -1) const; + float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const; - void clear(); + Vector<RID> get_rids() const; - void set_distance_field_hint(bool p_distance_field); - bool is_distance_field_hint() const; + void update_changes(); - float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const; + Font(); + ~Font(); +}; + +VARIANT_ENUM_CAST(FontData::SpacingType); +VARIANT_ENUM_CAST(Font::SpacingType); + +/*************************************************************************/ - BitmapFont(); - ~BitmapFont(); +class ResourceFormatLoaderFont : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; }; -class ResourceFormatLoaderBMFont : public ResourceFormatLoader { +#ifndef DISABLE_DEPRECATED + +class ResourceFormatLoaderCompatFont : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; }; -#endif +#endif /* DISABLE_DEPRECATED */ + +#endif /* FONT_H */ diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp index d271c906ff..7b9b942142 100644 --- a/scene/resources/gradient.cpp +++ b/scene/resources/gradient.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,20 +32,13 @@ #include "core/core_string_names.h" -//setter and getter names for property serialization -#define COLOR_RAMP_GET_OFFSETS "get_offsets" -#define COLOR_RAMP_GET_COLORS "get_colors" -#define COLOR_RAMP_SET_OFFSETS "set_offsets" -#define COLOR_RAMP_SET_COLORS "set_colors" - Gradient::Gradient() { - //Set initial color ramp transition from black to white + //Set initial gradient transition from black to white points.resize(2); points.write[0].color = Color(0, 0, 0, 1); points.write[0].offset = 0; points.write[1].color = Color(1, 1, 1, 1); points.write[1].offset = 1; - is_sorted = true; } Gradient::~Gradient() { @@ -53,7 +46,7 @@ Gradient::~Gradient() { void Gradient::_bind_methods() { ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &Gradient::add_point); - ClassDB::bind_method(D_METHOD("remove_point", "offset"), &Gradient::remove_point); + ClassDB::bind_method(D_METHOD("remove_point", "point"), &Gradient::remove_point); ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &Gradient::set_offset); ClassDB::bind_method(D_METHOD("get_offset", "point"), &Gradient::get_offset); @@ -65,14 +58,14 @@ void Gradient::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &Gradient::set_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &Gradient::get_offsets); + ClassDB::bind_method(D_METHOD("set_offsets", "offsets"), &Gradient::set_offsets); + ClassDB::bind_method(D_METHOD("get_offsets"), &Gradient::get_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &Gradient::set_colors); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &Gradient::get_colors); + ClassDB::bind_method(D_METHOD("set_colors", "colors"), &Gradient::set_colors); + ClassDB::bind_method(D_METHOD("get_colors"), &Gradient::get_colors); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "offsets"), "set_offsets", "get_offsets"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "colors"), "set_colors", "get_colors"); } Vector<float> Gradient::get_offsets() const { @@ -129,7 +122,7 @@ void Gradient::add_point(float p_offset, const Color &p_color) { void Gradient::remove_point(int p_index) { ERR_FAIL_INDEX(p_index, points.size()); - ERR_FAIL_COND(points.size() <= 2); + ERR_FAIL_COND(points.size() <= 1); points.remove(p_index); emit_signal(CoreStringNames::get_singleton()->changed); } @@ -141,32 +134,29 @@ void Gradient::set_points(Vector<Gradient::Point> &p_points) { } void Gradient::set_offset(int pos, const float offset) { - ERR_FAIL_COND(pos < 0); - if (points.size() <= pos) { - points.resize(pos + 1); - } + ERR_FAIL_INDEX(pos, points.size()); + _update_sorting(); points.write[pos].offset = offset; is_sorted = false; emit_signal(CoreStringNames::get_singleton()->changed); } -float Gradient::get_offset(int pos) const { +float Gradient::get_offset(int pos) { ERR_FAIL_INDEX_V(pos, points.size(), 0.0); + _update_sorting(); return points[pos].offset; } void Gradient::set_color(int pos, const Color &color) { - ERR_FAIL_COND(pos < 0); - if (points.size() <= pos) { - points.resize(pos + 1); - is_sorted = false; - } + ERR_FAIL_INDEX(pos, points.size()); + _update_sorting(); points.write[pos].color = color; emit_signal(CoreStringNames::get_singleton()->changed); } -Color Gradient::get_color(int pos) const { +Color Gradient::get_color(int pos) { ERR_FAIL_INDEX_V(pos, points.size(), Color()); + _update_sorting(); return points[pos].color; } diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h index d40dcc8d44..cf5b179c45 100644 --- a/scene/resources/gradient.h +++ b/scene/resources/gradient.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef GRADIENT_H #define GRADIENT_H -#include "core/resource.h" +#include "core/io/resource.h" class Gradient : public Resource { GDCLASS(Gradient, Resource); @@ -39,7 +39,7 @@ class Gradient : public Resource { public: struct Point { - float offset; + float offset = 0.0; Color color; bool operator<(const Point &p_ponit) const { return offset < p_ponit.offset; @@ -48,7 +48,13 @@ public: private: Vector<Point> points; - bool is_sorted; + bool is_sorted = true; + _FORCE_INLINE_ void _update_sorting() { + if (!is_sorted) { + points.sort(); + is_sorted = true; + } + } protected: static void _bind_methods(); @@ -64,10 +70,10 @@ public: Vector<Point> &get_points(); void set_offset(int pos, const float offset); - float get_offset(int pos) const; + float get_offset(int pos); void set_color(int pos, const Color &color); - Color get_color(int pos) const; + Color get_color(int pos); void set_offsets(const Vector<float> &p_offsets); Vector<float> get_offsets() const; @@ -76,14 +82,11 @@ public: Vector<Color> get_colors() const; _FORCE_INLINE_ Color get_color_at_offset(float p_offset) { - if (points.empty()) { + if (points.is_empty()) { return Color(0, 0, 0, 1); } - if (!is_sorted) { - points.sort(); - is_sorted = true; - } + _update_sorting(); //binary search int low = 0; diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp index e112c6b436..5593bb766f 100644 --- a/scene/resources/height_map_shape_3d.cpp +++ b/scene/resources/height_map_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #include "height_map_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() { +Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const { Vector<Vector3> points; if ((map_width != 0) && (map_depth != 0)) { @@ -107,8 +107,6 @@ void HeightMapShape3D::set_map_width(int p_new) { _update_shape(); notify_change_to_owners(); - _change_notify("map_width"); - _change_notify("map_data"); } } @@ -133,8 +131,6 @@ void HeightMapShape3D::set_map_depth(int p_new) { _update_shape(); notify_change_to_owners(); - _change_notify("map_depth"); - _change_notify("map_data"); } } @@ -171,7 +167,6 @@ void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) { _update_shape(); notify_change_to_owners(); - _change_notify("map_data"); } PackedFloat32Array HeightMapShape3D::get_map_data() const { @@ -193,16 +188,12 @@ void HeightMapShape3D::_bind_methods() { HeightMapShape3D::HeightMapShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) { - map_width = 2; - map_depth = 2; map_data.resize(map_width * map_depth); real_t *w = map_data.ptrw(); 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/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h index 291d41a34e..6fc88cff90 100644 --- a/scene/resources/height_map_shape_3d.h +++ b/scene/resources/height_map_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,15 +36,15 @@ class HeightMapShape3D : public Shape3D { GDCLASS(HeightMapShape3D, Shape3D); - int map_width; - int map_depth; + int map_width = 2; + int map_depth = 2; PackedFloat32Array map_data; - float min_height; - float max_height; + float min_height = 0.0; + float max_height = 0.0; protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: void set_map_width(int p_new); @@ -54,8 +54,8 @@ public: void set_map_data(PackedFloat32Array p_new); PackedFloat32Array get_map_data() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override; HeightMapShape3D(); }; diff --git a/scene/resources/line_shape_2d.cpp b/scene/resources/line_shape_2d.cpp index 802ccaaee6..d206f12287 100644 --- a/scene/resources/line_shape_2d.cpp +++ b/scene/resources/line_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,15 +30,16 @@ #include "line_shape_2d.h" +#include "core/math/geometry_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { Vector2 point = get_distance() * get_normal(); - Vector2 l[2][2] = { { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }, { point, point + get_normal() * 30 } }; + Vector2 l[2][2] = { { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }, { point, point + get_normal() * 30 } }; for (int i = 0; i < 2; i++) { - Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l[i]); + Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, l[i]); if (p_point.distance_to(closest) < p_tolerance) { return true; } @@ -76,7 +77,7 @@ real_t LineShape2D::get_distance() const { void LineShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector2 point = get_distance() * get_normal(); - Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }; + Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; RS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, 3); Vector2 l2[2] = { point, point + get_normal() * 30 }; RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3); @@ -85,7 +86,7 @@ void LineShape2D::draw(const RID &p_to_rid, const Color &p_color) { Rect2 LineShape2D::get_rect() const { Vector2 point = get_distance() * get_normal(); - Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }; + Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; Vector2 l2[2] = { point, point + get_normal() * 30 }; Rect2 rect; rect.position = l1[0]; @@ -112,7 +113,5 @@ void LineShape2D::_bind_methods() { LineShape2D::LineShape2D() : Shape2D(PhysicsServer2D::get_singleton()->line_shape_create()) { - normal = Vector2(0, 1); - distance = 0; _update_shape(); } diff --git a/scene/resources/line_shape_2d.h b/scene/resources/line_shape_2d.h index 74e8d57d03..9f0405ad29 100644 --- a/scene/resources/line_shape_2d.h +++ b/scene/resources/line_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,8 +36,8 @@ class LineShape2D : public Shape2D { GDCLASS(LineShape2D, Shape2D); - Vector2 normal; - real_t distance; + Vector2 normal = Vector2(0, 1); + real_t distance = 0.0; void _update_shape(); @@ -45,7 +45,7 @@ protected: static void _bind_methods(); public: - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override; void set_normal(const Vector2 &p_normal); void set_distance(real_t p_distance); @@ -53,9 +53,9 @@ public: Vector2 get_normal() const; real_t get_distance() const; - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - virtual real_t get_enclosing_radius() const; + virtual void draw(const RID &p_to_rid, const Color &p_color) override; + virtual Rect2 get_rect() const override; + virtual real_t get_enclosing_radius() const override; LineShape2D(); }; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 1e95a35726..062d921855 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,12 +30,13 @@ #include "material.h" -#include "core/engine.h" +#include "core/config/engine.h" #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" #endif +#include "scene/main/scene_tree.h" #include "scene/scene_string_names.h" void Material::set_next_pass(const Ref<Material> &p_pass) { @@ -80,6 +81,14 @@ void Material::_validate_property(PropertyInfo &property) const { } } +void Material::inspect_native_shader_code() { + SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop()); + RID shader = get_shader_rid(); + if (st && shader.is_valid()) { + st->call_group("_native_shader_source_visualizer", "_inspect_shader", shader); + } +} + void Material::_bind_methods() { ClassDB::bind_method(D_METHOD("set_next_pass", "next_pass"), &Material::set_next_pass); ClassDB::bind_method(D_METHOD("get_next_pass"), &Material::get_next_pass); @@ -87,6 +96,9 @@ void Material::_bind_methods() { ClassDB::bind_method(D_METHOD("set_render_priority", "priority"), &Material::set_render_priority); ClassDB::bind_method(D_METHOD("get_render_priority"), &Material::get_render_priority); + ClassDB::bind_method(D_METHOD("inspect_native_shader_code"), &Material::inspect_native_shader_code); + ClassDB::set_method_flags(get_class_static(), _scs_create("inspect_native_shader_code"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + ADD_PROPERTY(PropertyInfo(Variant::INT, "render_priority", PROPERTY_HINT_RANGE, itos(RENDER_PRIORITY_MIN) + "," + itos(RENDER_PRIORITY_MAX) + ",1"), "set_render_priority", "get_render_priority"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "next_pass", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_next_pass", "get_next_pass"); @@ -180,7 +192,7 @@ Variant ShaderMaterial::property_get_revert(const String &p_name) { void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) { // Only connect/disconnect the signal when running in the editor. - // This can be a slow operation, and `_change_notify()` (which is called by `_shader_changed()`) + // This can be a slow operation, and `notify_property_list_changed()` (which is called by `_shader_changed()`) // does nothing in non-editor builds anyway. See GH-34741 for details. if (shader.is_valid() && Engine::get_singleton()->is_editor_hint()) { shader->disconnect("changed", callable_mp(this, &ShaderMaterial::_shader_changed)); @@ -198,7 +210,7 @@ void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) { } RS::get_singleton()->material_set_shader(_get_material(), rid); - _change_notify(); //properties for shader exposed + notify_property_list_changed(); //properties for shader exposed emit_changed(); } @@ -215,7 +227,7 @@ Variant ShaderMaterial::get_shader_param(const StringName &p_param) const { } void ShaderMaterial::_shader_changed() { - _change_notify(); //update all properties + notify_property_list_changed(); //update all properties } void ShaderMaterial::_bind_methods() { @@ -260,6 +272,13 @@ Shader::Mode ShaderMaterial::get_shader_mode() const { return Shader::MODE_SPATIAL; } } +RID ShaderMaterial::get_shader_rid() const { + if (shader.is_valid()) { + return shader->get_rid(); + } else { + return RID(); + } +} ShaderMaterial::ShaderMaterial() { } @@ -324,7 +343,6 @@ void BaseMaterial3D::init_shaders() { shader_names->rim_texture_channel = "rim_texture_channel"; shader_names->heightmap_texture_channel = "heightmap_texture_channel"; shader_names->refraction_texture_channel = "refraction_texture_channel"; - shader_names->alpha_scissor_threshold = "alpha_scissor_threshold"; shader_names->transmittance_color = "transmittance_color"; shader_names->transmittance_curve = "transmittance_curve"; @@ -349,6 +367,12 @@ void BaseMaterial3D::init_shaders() { shader_names->texture_names[TEXTURE_DETAIL_ALBEDO] = "texture_detail_albedo"; shader_names->texture_names[TEXTURE_DETAIL_NORMAL] = "texture_detail_normal"; shader_names->texture_names[TEXTURE_ORM] = "texture_orm"; + + shader_names->alpha_scissor_threshold = "alpha_scissor_threshold"; + shader_names->alpha_hash_scale = "alpha_hash_scale"; + + shader_names->alpha_antialiasing_edge = "alpha_antialiasing_edge"; + shader_names->albedo_texture_size = "albedo_texture_size"; } Ref<StandardMaterial3D> BaseMaterial3D::materials_for_2d[BaseMaterial3D::MAX_MATERIALS_FOR_2D]; @@ -435,6 +459,8 @@ void BaseMaterial3D::_update_shader() { case BLEND_MODE_MUL: code += "blend_mul"; break; + case BLEND_MODE_MAX: + break; // Internal value, skip. } DepthDrawMode ddm = depth_draw_mode; @@ -452,10 +478,8 @@ void BaseMaterial3D::_update_shader() { case DEPTH_DRAW_DISABLED: code += ",depth_draw_never"; break; - } - - if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) { - code += ",depth_prepass_alpha"; + case DEPTH_DRAW_MAX: + break; // Internal value, skip. } switch (cull_mode) { @@ -468,6 +492,8 @@ void BaseMaterial3D::_update_shader() { case CULL_DISABLED: code += ",cull_disabled"; break; + case CULL_MAX: + break; // Internal value, skip. } switch (diffuse_mode) { case DIFFUSE_BURLEY: @@ -485,6 +511,8 @@ void BaseMaterial3D::_update_shader() { case DIFFUSE_TOON: code += ",diffuse_toon"; break; + case DIFFUSE_MAX: + break; // Internal value, skip. } switch (specular_mode) { case SPECULAR_SCHLICK_GGX: @@ -502,6 +530,8 @@ void BaseMaterial3D::_update_shader() { case SPECULAR_DISABLED: code += ",specular_disabled"; break; + case SPECULAR_MAX: + break; // Internal value, skip. } if (features[FEATURE_SUBSURFACE_SCATTERING] && flags[FLAG_SUBSURFACE_MODE_SKIN]) { code += ",sss_mode_skin"; @@ -525,6 +555,23 @@ void BaseMaterial3D::_update_shader() { if (flags[FLAG_USE_SHADOW_TO_OPACITY]) { code += ",shadow_to_opacity"; } + + if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) { + code += ",depth_prepass_alpha"; + } + + // Although its technically possible to do alpha antialiasing without using alpha hash or alpha scissor, + // it is restricted in the base material because it has no use, and abusing it with regular Alpha blending can + // saturate the MSAA mask + if (transparency == TRANSPARENCY_ALPHA_HASH || transparency == TRANSPARENCY_ALPHA_SCISSOR) { + // alpha antialiasing is only useful in ALPHA_HASH or ALPHA_SCISSOR + if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { + code += ",alpha_to_coverage"; + } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { + code += ",alpha_to_coverage_and_one"; + } + } + code += ";\n"; code += "uniform vec4 albedo : hint_color;\n"; @@ -541,8 +588,18 @@ void BaseMaterial3D::_update_shader() { code += "uniform float distance_fade_max;\n"; } + // alpha scissor is only valid if there is not antialiasing edge + // alpha hash is valid whenever, but not with alpha scissor if (transparency == TRANSPARENCY_ALPHA_SCISSOR) { code += "uniform float alpha_scissor_threshold;\n"; + } else if (transparency == TRANSPARENCY_ALPHA_HASH) { + code += "uniform float alpha_hash_scale;\n"; + } + // if alpha antialiasing isn't off, add in the edge variable + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF && + (transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH)) { + code += "uniform float alpha_antialiasing_edge;\n"; + code += "uniform ivec2 albedo_texture_size;\n"; } code += "uniform float point_size : hint_range(0,128);\n"; @@ -568,6 +625,8 @@ void BaseMaterial3D::_update_shader() { case TEXTURE_CHANNEL_GRAYSCALE: { code += "uniform sampler2D texture_roughness : hint_roughness_gray," + texfilter_str + ";\n"; } break; + case TEXTURE_CHANNEL_MAX: + break; // Internal value, skip. } code += "uniform float specular;\n"; @@ -676,7 +735,7 @@ void BaseMaterial3D::_update_shader() { if (flags[FLAG_SRGB_VERTEX_COLOR]) { code += "\tif (!OUTPUT_IS_SRGB) {\n"; - code += "\t\tCOLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );\n"; + code += "\t\tCOLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045)));\n"; code += "\t}\n"; } if (flags[FLAG_USE_POINT_SIZE]) { @@ -731,6 +790,8 @@ void BaseMaterial3D::_update_shader() { 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; + case BILLBOARD_MAX: + break; // Internal value, skip. } if (flags[FLAG_FIXED_SIZE]) { @@ -903,6 +964,8 @@ void BaseMaterial3D::_update_shader() { case TEXTURE_CHANNEL_GRAYSCALE: { code += "\tvec4 roughness_texture_channel = vec4(0.333333,0.333333,0.333333,0.0);\n"; } break; + case TEXTURE_CHANNEL_MAX: + break; // Internal value, skip. } if (flags[FLAG_UV1_USE_TRIPLANAR]) { @@ -925,11 +988,11 @@ void BaseMaterial3D::_update_shader() { if (features[FEATURE_NORMAL_MAPPING]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tNORMALMAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; + code += "\tNORMAL_MAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; } else { - code += "\tNORMALMAP = texture(texture_normal,base_uv).rgb;\n"; + code += "\tNORMAL_MAP = texture(texture_normal,base_uv).rgb;\n"; } - code += "\tNORMALMAP_DEPTH = normal_scale;\n"; + code += "\tNORMAL_MAP_DEPTH = normal_scale;\n"; } if (features[FEATURE_EMISSION]) { @@ -956,7 +1019,7 @@ void BaseMaterial3D::_update_shader() { if (features[FEATURE_REFRACTION]) { if (features[FEATURE_NORMAL_MAPPING]) { - code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) );\n"; + code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMAL_MAP.x + BINORMAL * NORMAL_MAP.y + NORMAL * NORMAL_MAP.z,NORMAL_MAP_DEPTH) );\n"; } else { code += "\tvec3 ref_normal = NORMAL;\n"; } @@ -970,10 +1033,17 @@ void BaseMaterial3D::_update_shader() { code += "\tALBEDO *= 1.0 - ref_amount;\n"; code += "\tALPHA = 1.0;\n"; - } else if (transparency == TRANSPARENCY_ALPHA || transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { + } else if (transparency != TRANSPARENCY_DISABLED || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { code += "\tALPHA = albedo.a * albedo_tex.a;\n"; + } + if (transparency == TRANSPARENCY_ALPHA_HASH) { + code += "\tALPHA_HASH_SCALE = alpha_hash_scale;\n"; } else if (transparency == TRANSPARENCY_ALPHA_SCISSOR) { - code += "\tif (albedo.a * albedo_tex.a < alpha_scissor_threshold) discard;\n"; + code += "\tALPHA_SCISSOR_THRESHOLD = alpha_scissor_threshold;\n"; + } + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF && (transparency == TRANSPARENCY_ALPHA_HASH || transparency == TRANSPARENCY_ALPHA_SCISSOR)) { + code += "\tALPHA_ANTIALIASING_EDGE = alpha_antialiasing_edge;\n"; + code += "\tALPHA_TEXTURE_COORDINATE = UV * vec2(albedo_texture_size);\n"; } if (proximity_fade_enabled) { @@ -1143,10 +1213,12 @@ void BaseMaterial3D::_update_shader() { case BLEND_MODE_MUL: { code += "\tvec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb*detail_tex.rgb,detail_tex.a);\n"; } break; + case BLEND_MODE_MAX: + break; // Internal value, skip. } - code += "\tvec3 detail_norm = mix(NORMALMAP,detail_norm_tex.rgb,detail_tex.a);\n"; - code += "\tNORMALMAP = mix(NORMALMAP,detail_norm,detail_mask_tex.r);\n"; + code += "\tvec3 detail_norm = mix(NORMAL_MAP,detail_norm_tex.rgb,detail_tex.a);\n"; + code += "\tNORMAL_MAP = mix(NORMAL_MAP,detail_norm,detail_mask_tex.r);\n"; code += "\tALBEDO.rgb = mix(ALBEDO.rgb,detail,detail_mask_tex.r);\n"; } @@ -1417,13 +1489,27 @@ void BaseMaterial3D::set_transparency(Transparency p_transparency) { transparency = p_transparency; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::Transparency BaseMaterial3D::get_transparency() const { return transparency; } +void BaseMaterial3D::set_alpha_antialiasing(AlphaAntiAliasing p_alpha_aa) { + if (alpha_antialiasing_mode == p_alpha_aa) { + return; + } + + alpha_antialiasing_mode = p_alpha_aa; + _queue_shader_change(); + notify_property_list_changed(); +} + +BaseMaterial3D::AlphaAntiAliasing BaseMaterial3D::get_alpha_antialiasing() const { + return alpha_antialiasing_mode; +} + void BaseMaterial3D::set_shading_mode(ShadingMode p_shading_mode) { if (shading_mode == p_shading_mode) { return; @@ -1431,7 +1517,7 @@ void BaseMaterial3D::set_shading_mode(ShadingMode p_shading_mode) { shading_mode = p_shading_mode; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::ShadingMode BaseMaterial3D::get_shading_mode() const { @@ -1499,7 +1585,7 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) { flags[p_flag] = p_enabled; if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN) { - _change_notify(); + notify_property_list_changed(); } _queue_shader_change(); } @@ -1516,7 +1602,7 @@ void BaseMaterial3D::set_feature(Feature p_feature, bool p_enabled) { } features[p_feature] = p_enabled; - _change_notify(); + notify_property_list_changed(); _queue_shader_change(); } @@ -1530,7 +1616,11 @@ void BaseMaterial3D::set_texture(TextureParam p_param, const Ref<Texture2D> &p_t textures[p_param] = p_texture; RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); RS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid); - _change_notify(); + if (p_texture.is_valid() && p_param == TEXTURE_ALBEDO) { + RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo_texture_size, + Vector2i(p_texture->get_width(), p_texture->get_height())); + } + notify_property_list_changed(); _queue_shader_change(); } @@ -1605,10 +1695,34 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { property.usage = 0; } + // you can only enable anti-aliasing (in mataerials) on alpha scissor and alpha hash + const bool can_select_aa = (transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH); + // alpha anti aliasiasing is only enabled when you can select aa + const bool alpha_aa_enabled = (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) && can_select_aa; + + // alpha scissor slider isn't needed when alpha antialiasing is enabled if (property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) { property.usage = 0; } + // alpha hash scale slider is only needed if transparency is alpha hash + if (property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) { + property.usage = 0; + } + + if (property.name == "alpha_antialiasing_mode" && !can_select_aa) { + property.usage = 0; + } + + // we cant choose an antialiasing mode if alpha isnt possible + if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) { + property.usage = 0; + } + + if (property.name == "blend_mode" && alpha_aa_enabled) { + property.usage = 0; + } + if ((property.name == "heightmap_min_layers" || property.name == "heightmap_max_layers") && !deep_parallax) { property.usage = 0; } @@ -1746,7 +1860,7 @@ float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const { void BaseMaterial3D::set_billboard_mode(BillboardMode p_mode) { billboard_mode = p_mode; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::BillboardMode BaseMaterial3D::get_billboard_mode() const { @@ -1783,7 +1897,7 @@ bool BaseMaterial3D::get_particles_anim_loop() const { void BaseMaterial3D::set_heightmap_deep_parallax(bool p_enable) { deep_parallax = p_enable; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } bool BaseMaterial3D::is_heightmap_deep_parallax_enabled() const { @@ -1829,7 +1943,7 @@ bool BaseMaterial3D::get_heightmap_deep_parallax_flip_binormal() const { void BaseMaterial3D::set_grow_enabled(bool p_enable) { grow_enabled = p_enable; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } bool BaseMaterial3D::is_grow_enabled() const { @@ -1845,6 +1959,24 @@ float BaseMaterial3D::get_alpha_scissor_threshold() const { return alpha_scissor_threshold; } +void BaseMaterial3D::set_alpha_hash_scale(float p_scale) { + alpha_hash_scale = p_scale; + RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_hash_scale, p_scale); +} + +float BaseMaterial3D::get_alpha_hash_scale() const { + return alpha_hash_scale; +} + +void BaseMaterial3D::set_alpha_antialiasing_edge(float p_edge) { + alpha_antialiasing_edge = p_edge; + RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_antialiasing_edge, p_edge); +} + +float BaseMaterial3D::get_alpha_antialiasing_edge() const { + return alpha_antialiasing_edge; +} + void BaseMaterial3D::set_grow(float p_grow) { grow = p_grow; RS::get_singleton()->material_set_param(_get_material(), shader_names->grow, p_grow); @@ -1961,7 +2093,7 @@ void BaseMaterial3D::set_on_top_of_alpha() { void BaseMaterial3D::set_proximity_fade(bool p_enable) { proximity_fade_enabled = p_enable; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } bool BaseMaterial3D::is_proximity_fade_enabled() const { @@ -1980,7 +2112,7 @@ float BaseMaterial3D::get_proximity_fade_distance() const { void BaseMaterial3D::set_distance_fade(DistanceFadeMode p_mode) { distance_fade = p_mode; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::DistanceFadeMode BaseMaterial3D::get_distance_fade() const { @@ -2033,6 +2165,12 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transparency", "transparency"), &BaseMaterial3D::set_transparency); ClassDB::bind_method(D_METHOD("get_transparency"), &BaseMaterial3D::get_transparency); + ClassDB::bind_method(D_METHOD("set_alpha_antialiasing", "alpha_aa"), &BaseMaterial3D::set_alpha_antialiasing); + ClassDB::bind_method(D_METHOD("get_alpha_antialiasing"), &BaseMaterial3D::get_alpha_antialiasing); + + ClassDB::bind_method(D_METHOD("set_alpha_antialiasing_edge", "edge"), &BaseMaterial3D::set_alpha_antialiasing_edge); + ClassDB::bind_method(D_METHOD("get_alpha_antialiasing_edge"), &BaseMaterial3D::get_alpha_antialiasing_edge); + ClassDB::bind_method(D_METHOD("set_shading_mode", "shading_mode"), &BaseMaterial3D::set_shading_mode); ClassDB::bind_method(D_METHOD("get_shading_mode"), &BaseMaterial3D::get_shading_mode); @@ -2186,6 +2324,9 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_alpha_scissor_threshold", "threshold"), &BaseMaterial3D::set_alpha_scissor_threshold); ClassDB::bind_method(D_METHOD("get_alpha_scissor_threshold"), &BaseMaterial3D::get_alpha_scissor_threshold); + ClassDB::bind_method(D_METHOD("set_alpha_hash_scale", "threshold"), &BaseMaterial3D::set_alpha_hash_scale); + ClassDB::bind_method(D_METHOD("get_alpha_hash_scale"), &BaseMaterial3D::get_alpha_hash_scale); + ClassDB::bind_method(D_METHOD("set_grow_enabled", "enable"), &BaseMaterial3D::set_grow_enabled); ClassDB::bind_method(D_METHOD("is_grow_enabled"), &BaseMaterial3D::is_grow_enabled); @@ -2217,8 +2358,11 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_distance_fade_min_distance"), &BaseMaterial3D::get_distance_fade_min_distance); ADD_GROUP("Transparency", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,AlphaScissor,DepthPrePass"), "set_transparency", "get_transparency"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth PrePass"), "set_transparency", "get_transparency"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge"); ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), "set_blend_mode", "get_blend_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Back,Front,Disabled"), "set_cull_mode", "get_cull_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode"); @@ -2292,10 +2436,10 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Height", "heightmap_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "heightmap_enabled"), "set_feature", "get_feature", FEATURE_HEIGHT_MAPPING); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "heightmap_scale", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_heightmap_scale", "get_heightmap_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "heightmap_scale", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_heightmap_scale", "get_heightmap_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_deep_parallax"), "set_heightmap_deep_parallax", "is_heightmap_deep_parallax_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_min_layers", PROPERTY_HINT_RANGE, "1,32,1"), "set_heightmap_deep_parallax_min_layers", "get_heightmap_deep_parallax_min_layers"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_max_layers", PROPERTY_HINT_RANGE, "1,32,1"), "set_heightmap_deep_parallax_max_layers", "get_heightmap_deep_parallax_max_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_min_layers", PROPERTY_HINT_RANGE, "1,64,1"), "set_heightmap_deep_parallax_min_layers", "get_heightmap_deep_parallax_min_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_max_layers", PROPERTY_HINT_RANGE, "1,64,1"), "set_heightmap_deep_parallax_max_layers", "get_heightmap_deep_parallax_max_layers"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_flip_tangent"), "set_heightmap_deep_parallax_flip_tangent", "get_heightmap_deep_parallax_flip_tangent"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_flip_binormal"), "set_heightmap_deep_parallax_flip_binormal", "get_heightmap_deep_parallax_flip_binormal"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "heightmap_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_HEIGHTMAP); @@ -2414,6 +2558,7 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(TRANSPARENCY_DISABLED); BIND_ENUM_CONSTANT(TRANSPARENCY_ALPHA); BIND_ENUM_CONSTANT(TRANSPARENCY_ALPHA_SCISSOR); + BIND_ENUM_CONSTANT(TRANSPARENCY_ALPHA_HASH); BIND_ENUM_CONSTANT(TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); BIND_ENUM_CONSTANT(TRANSPARENCY_MAX); @@ -2441,6 +2586,10 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(BLEND_MODE_SUB); BIND_ENUM_CONSTANT(BLEND_MODE_MUL); + BIND_ENUM_CONSTANT(ALPHA_ANTIALIASING_OFF); + BIND_ENUM_CONSTANT(ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); + BIND_ENUM_CONSTANT(ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); + BIND_ENUM_CONSTANT(DEPTH_DRAW_OPAQUE_ONLY); BIND_ENUM_CONSTANT(DEPTH_DRAW_ALWAYS); BIND_ENUM_CONSTANT(DEPTH_DRAW_DISABLED); @@ -2506,8 +2655,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : element(this) { orm = p_orm; // Initialize to the same values as the shader - transparency = TRANSPARENCY_DISABLED; - shading_mode = SHADING_MODE_PER_PIXEL; set_albedo(Color(1.0, 1.0, 1.0, 1.0)); set_specular(0.5); set_roughness(1.0); @@ -2539,11 +2686,13 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_particles_anim_h_frames(1); set_particles_anim_v_frames(1); set_particles_anim_loop(false); - set_alpha_scissor_threshold(0.98); - emission_op = EMISSION_OP_ADD; - proximity_fade_enabled = false; - distance_fade = DISTANCE_FADE_DISABLED; + set_transparency(TRANSPARENCY_DISABLED); + set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF); + set_alpha_scissor_threshold(0.05); + set_alpha_hash_scale(1.0); + set_alpha_antialiasing_edge(0.3); + set_proximity_fade_distance(1); set_distance_fade_min_distance(0); set_distance_fade_max_distance(10); @@ -2555,37 +2704,14 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_ao_texture_channel(TEXTURE_CHANNEL_RED); set_refraction_texture_channel(TEXTURE_CHANNEL_RED); - grow_enabled = false; set_grow(0.0); - deep_parallax = false; - heightmap_parallax_flip_tangent = false; - heightmap_parallax_flip_binormal = false; set_heightmap_deep_parallax_min_layers(8); set_heightmap_deep_parallax_max_layers(32); set_heightmap_deep_parallax_flip_tangent(false); //also sets binormal - detail_uv = DETAIL_UV_1; - blend_mode = BLEND_MODE_MIX; - detail_blend_mode = BLEND_MODE_MIX; - depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY; - cull_mode = CULL_BACK; - for (int i = 0; i < FLAG_MAX; i++) { - flags[i] = false; - } flags[FLAG_USE_TEXTURE_REPEAT] = true; - diffuse_mode = DIFFUSE_BURLEY; - specular_mode = SPECULAR_SCHLICK_GGX; - - for (int i = 0; i < FEATURE_MAX; i++) { - features[i] = false; - } - - current_key.key0 = 0; - current_key.key1 = 0; - current_key.invalid_key = 1; - texture_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; _queue_shader_change(); } @@ -2633,6 +2759,12 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value) set_transparency(TRANSPARENCY_ALPHA_SCISSOR); } return true; + } else if (p_name == "params_use_alpha_hash") { + bool use_hash = p_value; + if (use_hash) { + set_transparency(TRANSPARENCY_ALPHA_HASH); + } + return true; } else if (p_name == "params_depth_draw_mode") { int mode = p_value; if (mode == 3) { @@ -2667,6 +2799,8 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value) { "params_grow", "grow" }, { "params_grow_amount", "grow_amount" }, { "params_alpha_scissor_threshold", "alpha_scissor_threshold" }, + { "params_alpha_hash_scale", "alpha_hash_scale" }, + { "params_alpha_antialiasing_edge", "alpha_antialiasing_edge" }, { "depth_scale", "heightmap_scale" }, { "depth_deep_parallax", "heightmap_deep_parallax" }, diff --git a/scene/resources/material.h b/scene/resources/material.h index 433e3d304e..70452a5f74 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,8 +31,8 @@ #ifndef MATERIAL_H #define MATERIAL_H -#include "core/resource.h" -#include "core/self_list.h" +#include "core/io/resource.h" +#include "core/templates/self_list.h" #include "scene/resources/shader.h" #include "scene/resources/texture.h" #include "servers/rendering/shader_language.h" @@ -47,12 +47,14 @@ class Material : public Resource { Ref<Material> next_pass; int render_priority; + void inspect_native_shader_code(); + protected: _FORCE_INLINE_ RID _get_material() const { return material; } static void _bind_methods(); virtual bool _can_do_next_pass() const { return false; } - void _validate_property(PropertyInfo &property) const; + void _validate_property(PropertyInfo &property) const override; public: enum { @@ -65,7 +67,8 @@ public: void set_render_priority(int p_priority); int get_render_priority() const; - virtual RID get_rid() const; + virtual RID get_rid() const override; + virtual RID get_shader_rid() const = 0; virtual Shader::Mode get_shader_mode() const = 0; Material(); @@ -85,9 +88,9 @@ protected: static void _bind_methods(); - void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; + void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; - virtual bool _can_do_next_pass() const; + virtual bool _can_do_next_pass() const override; void _shader_changed(); @@ -98,7 +101,9 @@ public: void set_shader_param(const StringName &p_param, const Variant &p_value); Variant get_shader_param(const StringName &p_param) const; - virtual Shader::Mode get_shader_mode() const; + virtual Shader::Mode get_shader_mode() const override; + + virtual RID get_shader_rid() const override; ShaderMaterial(); ~ShaderMaterial(); @@ -145,17 +150,26 @@ public: enum DetailUV { DETAIL_UV_1, - DETAIL_UV_2 + DETAIL_UV_2, + DETAIL_UV_MAX }; enum Transparency { TRANSPARENCY_DISABLED, TRANSPARENCY_ALPHA, TRANSPARENCY_ALPHA_SCISSOR, + TRANSPARENCY_ALPHA_HASH, TRANSPARENCY_ALPHA_DEPTH_PRE_PASS, TRANSPARENCY_MAX, }; + enum AlphaAntiAliasing { + ALPHA_ANTIALIASING_OFF, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE, + ALPHA_ANTIALIASING_MAX + }; + enum ShadingMode { SHADING_MODE_UNSHADED, SHADING_MODE_PER_PIXEL, @@ -184,18 +198,21 @@ public: BLEND_MODE_ADD, BLEND_MODE_SUB, BLEND_MODE_MUL, + BLEND_MODE_MAX }; enum DepthDrawMode { DEPTH_DRAW_OPAQUE_ONLY, DEPTH_DRAW_ALWAYS, DEPTH_DRAW_DISABLED, + DEPTH_DRAW_MAX }; enum CullMode { CULL_BACK, CULL_FRONT, - CULL_DISABLED + CULL_DISABLED, + CULL_MAX }; enum Flags { @@ -227,6 +244,7 @@ public: DIFFUSE_LAMBERT_WRAP, DIFFUSE_OREN_NAYAR, DIFFUSE_TOON, + DIFFUSE_MAX }; enum SpecularMode { @@ -235,6 +253,7 @@ public: SPECULAR_PHONG, SPECULAR_TOON, SPECULAR_DISABLED, + SPECULAR_MAX }; enum BillboardMode { @@ -242,6 +261,7 @@ public: BILLBOARD_ENABLED, BILLBOARD_FIXED_Y, BILLBOARD_PARTICLES, + BILLBOARD_MAX }; enum TextureChannel { @@ -249,12 +269,14 @@ public: TEXTURE_CHANNEL_GREEN, TEXTURE_CHANNEL_BLUE, TEXTURE_CHANNEL_ALPHA, - TEXTURE_CHANNEL_GRAYSCALE + TEXTURE_CHANNEL_GRAYSCALE, + TEXTURE_CHANNEL_MAX }; enum EmissionOperator { EMISSION_OP_ADD, - EMISSION_OP_MULTIPLY + EMISSION_OP_MULTIPLY, + EMISSION_OP_MAX }; enum DistanceFadeMode { @@ -262,49 +284,53 @@ public: DISTANCE_FADE_PIXEL_ALPHA, DISTANCE_FADE_PIXEL_DITHER, DISTANCE_FADE_OBJECT_DITHER, + DISTANCE_FADE_MAX }; private: - union MaterialKey { - struct { - uint64_t feature_mask : FEATURE_MAX; - uint64_t detail_uv : 1; - uint64_t blend_mode : 2; - uint64_t depth_draw_mode : 2; - uint64_t cull_mode : 2; - uint64_t flags : FLAG_MAX; - uint64_t detail_blend_mode : 2; - uint64_t diffuse_mode : 3; - uint64_t specular_mode : 3; - uint64_t invalid_key : 1; - uint64_t deep_parallax : 1; - uint64_t billboard_mode : 2; - uint64_t grow : 1; - uint64_t proximity_fade : 1; - uint64_t distance_fade : 2; - uint64_t emission_op : 1; - uint64_t texture_filter : 3; - uint64_t transparency : 2; - uint64_t shading_mode : 2; - uint64_t roughness_channel : 3; - }; - - struct { - uint64_t key0; - uint64_t key1; - }; + struct MaterialKey { + // enum values + uint64_t texture_filter : get_num_bits(TEXTURE_FILTER_MAX - 1); + uint64_t detail_uv : get_num_bits(DETAIL_UV_MAX - 1); + uint64_t transparency : get_num_bits(TRANSPARENCY_MAX - 1); + uint64_t alpha_antialiasing_mode : get_num_bits(ALPHA_ANTIALIASING_MAX - 1); + uint64_t shading_mode : get_num_bits(SHADING_MODE_MAX - 1); + uint64_t blend_mode : get_num_bits(BLEND_MODE_MAX - 1); + uint64_t depth_draw_mode : get_num_bits(DEPTH_DRAW_MAX - 1); + uint64_t cull_mode : get_num_bits(CULL_MAX - 1); + uint64_t diffuse_mode : get_num_bits(DIFFUSE_MAX - 1); + uint64_t specular_mode : get_num_bits(SPECULAR_MAX - 1); + uint64_t billboard_mode : get_num_bits(BILLBOARD_MAX - 1); + uint64_t detail_blend_mode : get_num_bits(BLEND_MODE_MAX - 1); + uint64_t roughness_channel : get_num_bits(TEXTURE_CHANNEL_MAX - 1); + uint64_t emission_op : get_num_bits(EMISSION_OP_MAX - 1); + uint64_t distance_fade : get_num_bits(DISTANCE_FADE_MAX - 1); + + // flag bitfield + uint64_t feature_mask : FEATURE_MAX - 1; + uint64_t flags : FLAG_MAX - 1; + + // booleans + uint64_t deep_parallax : 1; + uint64_t grow : 1; + uint64_t proximity_fade : 1; + + MaterialKey() { + memset(this, 0, sizeof(MaterialKey)); + } bool operator==(const MaterialKey &p_key) const { - return (key0 == p_key.key0) && (key1 == p_key.key1); + return memcmp(this, &p_key, sizeof(MaterialKey)) == 0; } + bool operator<(const MaterialKey &p_key) const { - return (key0 == p_key.key0) ? (key1 < p_key.key1) : (key0 < p_key.key0); + return memcmp(this, &p_key, sizeof(MaterialKey)) < 0; } }; struct ShaderData { RID shader; - int users; + int users = 0; }; static Map<MaterialKey, ShaderData> shader_map; @@ -313,13 +339,7 @@ private: _FORCE_INLINE_ MaterialKey _compute_key() const { MaterialKey mk; - mk.key0 = 0; - mk.key1 = 0; - for (int i = 0; i < FEATURE_MAX; i++) { - if (features[i]) { - mk.feature_mask |= ((uint64_t)1 << i); - } - } + mk.detail_uv = detail_uv; mk.blend_mode = blend_mode; mk.depth_draw_mode = depth_draw_mode; @@ -328,20 +348,28 @@ private: mk.transparency = transparency; mk.shading_mode = shading_mode; mk.roughness_channel = roughness_texture_channel; - for (int i = 0; i < FLAG_MAX; i++) { - if (flags[i]) { - mk.flags |= ((uint64_t)1 << i); - } - } mk.detail_blend_mode = detail_blend_mode; mk.diffuse_mode = diffuse_mode; mk.specular_mode = specular_mode; mk.billboard_mode = billboard_mode; - mk.deep_parallax = deep_parallax ? 1 : 0; + mk.deep_parallax = deep_parallax; mk.grow = grow_enabled; mk.proximity_fade = proximity_fade_enabled; mk.distance_fade = distance_fade; mk.emission_op = emission_op; + mk.alpha_antialiasing_mode = alpha_antialiasing_mode; + + for (int i = 0; i < FEATURE_MAX; i++) { + if (features[i]) { + mk.feature_mask |= ((uint64_t)1 << i); + } + } + + for (int i = 0; i < FLAG_MAX; i++) { + if (flags[i]) { + mk.flags |= ((uint64_t)1 << i); + } + } return mk; } @@ -392,9 +420,14 @@ private: StringName rim_texture_channel; StringName heightmap_texture_channel; StringName refraction_texture_channel; - StringName alpha_scissor_threshold; StringName texture_names[TEXTURE_MAX]; + + StringName alpha_scissor_threshold; + StringName alpha_hash_scale; + + StringName alpha_antialiasing_edge; + StringName albedo_texture_size; }; static Mutex material_mutex; @@ -433,16 +466,18 @@ private: float refraction; float point_size; float alpha_scissor_threshold; - bool grow_enabled; + float alpha_hash_scale; + float alpha_antialiasing_edge; + bool grow_enabled = false; float ao_light_affect; float grow; int particles_anim_h_frames; int particles_anim_v_frames; bool particles_anim_loop; - Transparency transparency; - ShadingMode shading_mode; + Transparency transparency = TRANSPARENCY_DISABLED; + ShadingMode shading_mode = SHADING_MODE_PER_PIXEL; - TextureFilter texture_filter; + TextureFilter texture_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; Vector3 uv1_scale; Vector3 uv1_offset; @@ -452,37 +487,39 @@ private: Vector3 uv2_offset; float uv2_triplanar_sharpness; - DetailUV detail_uv; + DetailUV detail_uv = DETAIL_UV_1; - bool deep_parallax; + bool deep_parallax = false; int deep_parallax_min_layers; int deep_parallax_max_layers; - bool heightmap_parallax_flip_tangent; - bool heightmap_parallax_flip_binormal; + bool heightmap_parallax_flip_tangent = false; + bool heightmap_parallax_flip_binormal = false; - bool proximity_fade_enabled; + bool proximity_fade_enabled = false; float proximity_fade_distance; - DistanceFadeMode distance_fade; + DistanceFadeMode distance_fade = DISTANCE_FADE_DISABLED; float distance_fade_max_distance; float distance_fade_min_distance; - BlendMode blend_mode; - BlendMode detail_blend_mode; - DepthDrawMode depth_draw_mode; - CullMode cull_mode; - bool flags[FLAG_MAX]; - SpecularMode specular_mode; - DiffuseMode diffuse_mode; + BlendMode blend_mode = BLEND_MODE_MIX; + BlendMode detail_blend_mode = BLEND_MODE_MIX; + DepthDrawMode depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY; + CullMode cull_mode = CULL_BACK; + bool flags[FLAG_MAX] = {}; + SpecularMode specular_mode = SPECULAR_SCHLICK_GGX; + DiffuseMode diffuse_mode = DIFFUSE_BURLEY; BillboardMode billboard_mode; - EmissionOperator emission_op; + EmissionOperator emission_op = EMISSION_OP_ADD; TextureChannel metallic_texture_channel; TextureChannel roughness_texture_channel; TextureChannel ao_texture_channel; TextureChannel refraction_texture_channel; - bool features[FEATURE_MAX]; + AlphaAntiAliasing alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; + + bool features[FEATURE_MAX] = {}; Ref<Texture2D> textures[TEXTURE_MAX]; @@ -496,8 +533,8 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const; - virtual bool _can_do_next_pass() const { return true; } + void _validate_property(PropertyInfo &property) const override; + virtual bool _can_do_next_pass() const override { return true; } public: void set_albedo(const Color &p_albedo); @@ -584,6 +621,12 @@ public: void set_transparency(Transparency p_transparency); Transparency get_transparency() const; + void set_alpha_antialiasing(AlphaAntiAliasing p_alpha_aa); + AlphaAntiAliasing get_alpha_antialiasing() const; + + void set_alpha_antialiasing_edge(float p_edge); + float get_alpha_antialiasing_edge() const; + void set_shading_mode(ShadingMode p_shading_mode); ShadingMode get_shading_mode() const; @@ -660,6 +703,9 @@ public: void set_alpha_scissor_threshold(float p_threshold); float get_alpha_scissor_threshold() const; + void set_alpha_hash_scale(float p_scale); + float get_alpha_hash_scale() const; + void set_on_top_of_alpha(); void set_proximity_fade(bool p_enable); @@ -695,9 +741,9 @@ public: static RID get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false); - RID get_shader_rid() const; + virtual RID get_shader_rid() const override; - virtual Shader::Mode get_shader_mode() const; + virtual Shader::Mode get_shader_mode() const override; BaseMaterial3D(bool p_orm); virtual ~BaseMaterial3D(); @@ -707,6 +753,7 @@ VARIANT_ENUM_CAST(BaseMaterial3D::TextureParam) VARIANT_ENUM_CAST(BaseMaterial3D::TextureFilter) VARIANT_ENUM_CAST(BaseMaterial3D::ShadingMode) VARIANT_ENUM_CAST(BaseMaterial3D::Transparency) +VARIANT_ENUM_CAST(BaseMaterial3D::AlphaAntiAliasing) VARIANT_ENUM_CAST(BaseMaterial3D::DetailUV) VARIANT_ENUM_CAST(BaseMaterial3D::Feature) VARIANT_ENUM_CAST(BaseMaterial3D::BlendMode) diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 10f0a040d0..1a2b21299a 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +30,7 @@ #include "mesh.h" -#include "core/pair.h" +#include "core/templates/pair.h" #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" #include "surface_tool.h" @@ -74,7 +74,7 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { } Array a = surface_get_arrays(i); - ERR_FAIL_COND_V(a.empty(), Ref<TriangleMesh>()); + ERR_FAIL_COND_V(a.is_empty(), Ref<TriangleMesh>()); int vc = surface_get_array_len(i); Vector<Vector3> vertices = a[ARRAY_VERTEX]; @@ -157,7 +157,7 @@ void Mesh::generate_debug_mesh_indices(Vector<Vector3> &r_points) { bool Mesh::surface_is_softbody_friendly(int p_idx) const { const uint32_t surface_format = surface_get_format(p_idx); - return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE && (!(surface_format & Mesh::ARRAY_COMPRESS_NORMAL))); + return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE); } Vector<Face3> Mesh::get_faces() const { @@ -168,7 +168,6 @@ Vector<Face3> Mesh::get_faces() const { return Vector<Face3>(); /* for (int i=0;i<surfaces.size();i++) { - if (RenderingServer::get_singleton()->mesh_surface_get_primitive_type( mesh, i ) != RenderingServer::PRIMITIVE_TRIANGLES ) continue; @@ -181,12 +180,10 @@ Vector<Face3> Mesh::get_faces() const { bool has_indices; if (len>0) { - indices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_INDEX); has_indices=true; } else { - len=vertices.size(); has_indices=false; } @@ -210,11 +207,9 @@ Vector<Face3> Mesh::get_faces() const { for (int i=0;i<len/3;i++) { - Face3 face; for (int j=0;j<3;j++) { - int idx=i*3+j; face.vertex[j] = has_indices ? verticesptr[ indicesptr[ idx ] ] : verticesptr[idx]; } @@ -231,7 +226,7 @@ Ref<Shape3D> Mesh::create_convex_shape() const { for (int i = 0; i < get_surface_count(); i++) { Array a = surface_get_arrays(i); - ERR_FAIL_COND_V(a.empty(), Ref<ConvexPolygonShape3D>()); + ERR_FAIL_COND_V(a.is_empty(), Ref<ConvexPolygonShape3D>()); Vector<Vector3> v = a[ARRAY_VERTEX]; vertices.append_array(v); } @@ -271,7 +266,7 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const { } Array a = surface_get_arrays(i); - ERR_FAIL_COND_V(a.empty(), Ref<ArrayMesh>()); + ERR_FAIL_COND_V(a.is_empty(), Ref<ArrayMesh>()); if (i == 0) { arrays = a; @@ -485,8 +480,30 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES); BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP); - BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); - BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); + BIND_ENUM_CONSTANT(ARRAY_VERTEX); + BIND_ENUM_CONSTANT(ARRAY_NORMAL); + BIND_ENUM_CONSTANT(ARRAY_TANGENT); + BIND_ENUM_CONSTANT(ARRAY_COLOR); + BIND_ENUM_CONSTANT(ARRAY_TEX_UV); + BIND_ENUM_CONSTANT(ARRAY_TEX_UV2); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM0); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM1); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM2); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM3); + BIND_ENUM_CONSTANT(ARRAY_BONES); + BIND_ENUM_CONSTANT(ARRAY_WEIGHTS); + BIND_ENUM_CONSTANT(ARRAY_INDEX); + BIND_ENUM_CONSTANT(ARRAY_MAX); + + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_UNORM); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_SNORM); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_HALF); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_HALF); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_R_FLOAT); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_FLOAT); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGB_FLOAT); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_FLOAT); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_MAX); BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX); BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL); @@ -494,31 +511,31 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR); BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV); BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3); BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES); BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_BLEND_SHAPE_MASK); - BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BASE); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3_SHIFT); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_MASK); + BIND_ENUM_CONSTANT(ARRAY_COMPRESS_FLAGS_BASE); - BIND_ENUM_CONSTANT(ARRAY_VERTEX); - BIND_ENUM_CONSTANT(ARRAY_NORMAL); - BIND_ENUM_CONSTANT(ARRAY_TANGENT); - BIND_ENUM_CONSTANT(ARRAY_COLOR); - BIND_ENUM_CONSTANT(ARRAY_TEX_UV); - BIND_ENUM_CONSTANT(ARRAY_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_BONES); - BIND_ENUM_CONSTANT(ARRAY_WEIGHTS); - BIND_ENUM_CONSTANT(ARRAY_INDEX); - BIND_ENUM_CONSTANT(ARRAY_MAX); + BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); + BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE); + BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS); + + BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); + BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); } void Mesh::clear_cache() const { @@ -565,11 +582,50 @@ Vector<Ref<Shape3D>> Mesh::convex_decompose() const { Mesh::Mesh() { } +#if 0 static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_format, uint32_t p_elements) { - bool vertex_16bit = p_format & ((1 << (Mesh::ARRAY_VERTEX + Mesh::ARRAY_COMPRESS_BASE))); - bool has_bones = (p_format & Mesh::ARRAY_FORMAT_BONES); - bool bone_8 = has_bones && !(p_format & (Mesh::ARRAY_COMPRESS_INDEX << 2)); - bool weight_32 = has_bones && !(p_format & (Mesh::ARRAY_COMPRESS_TEX_UV2 << 2)); + enum ArrayType { + OLD_ARRAY_VERTEX = 0, + OLD_ARRAY_NORMAL = 1, + OLD_ARRAY_TANGENT = 2, + OLD_ARRAY_COLOR = 3, + OLD_ARRAY_TEX_UV = 4, + OLD_ARRAY_TEX_UV2 = 5, + OLD_ARRAY_BONES = 6, + OLD_ARRAY_WEIGHTS = 7, + OLD_ARRAY_INDEX = 8, + OLD_ARRAY_MAX = 9 + }; + + enum ArrayFormat { + /* OLD_ARRAY FORMAT FLAGS */ + OLD_ARRAY_FORMAT_VERTEX = 1 << OLD_ARRAY_VERTEX, // mandatory + OLD_ARRAY_FORMAT_NORMAL = 1 << OLD_ARRAY_NORMAL, + OLD_ARRAY_FORMAT_TANGENT = 1 << OLD_ARRAY_TANGENT, + OLD_ARRAY_FORMAT_COLOR = 1 << OLD_ARRAY_COLOR, + OLD_ARRAY_FORMAT_TEX_UV = 1 << OLD_ARRAY_TEX_UV, + OLD_ARRAY_FORMAT_TEX_UV2 = 1 << OLD_ARRAY_TEX_UV2, + OLD_ARRAY_FORMAT_BONES = 1 << OLD_ARRAY_BONES, + OLD_ARRAY_FORMAT_WEIGHTS = 1 << OLD_ARRAY_WEIGHTS, + OLD_ARRAY_FORMAT_INDEX = 1 << OLD_ARRAY_INDEX, + + OLD_ARRAY_COMPRESS_BASE = (OLD_ARRAY_INDEX + 1), + OLD_ARRAY_COMPRESS_NORMAL = 1 << (OLD_ARRAY_NORMAL + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TANGENT = 1 << (OLD_ARRAY_TANGENT + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_COLOR = 1 << (OLD_ARRAY_COLOR + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TEX_UV = 1 << (OLD_ARRAY_TEX_UV + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TEX_UV2 = 1 << (OLD_ARRAY_TEX_UV2 + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_INDEX = 1 << (OLD_ARRAY_INDEX + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_DEFAULT = OLD_ARRAY_COMPRESS_NORMAL | OLD_ARRAY_COMPRESS_TANGENT | OLD_ARRAY_COMPRESS_COLOR | OLD_ARRAY_COMPRESS_TEX_UV | OLD_ARRAY_COMPRESS_TEX_UV2, + + OLD_ARRAY_FLAG_USE_2D_VERTICES = OLD_ARRAY_COMPRESS_INDEX << 1, + OLD_ARRAY_FLAG_USE_DYNAMIC_UPDATE = OLD_ARRAY_COMPRESS_INDEX << 3, + }; + + bool vertex_16bit = p_format & ((1 << (OLD_ARRAY_VERTEX + OLD_ARRAY_COMPRESS_BASE))); + bool has_bones = (p_format & OLD_ARRAY_FORMAT_BONES); + bool bone_8 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_INDEX << 2)); + bool weight_32 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_TEX_UV2 << 2)); print_line("convert vertex16: " + itos(vertex_16bit) + " convert bone 8 " + itos(bone_8) + " convert weight 32 " + itos(weight_32)); @@ -577,7 +633,7 @@ static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, ui return p_src; } - bool vertex_2d = (p_format & (Mesh::ARRAY_COMPRESS_INDEX << 1)); + bool vertex_2d = (p_format & (OLD_ARRAY_COMPRESS_INDEX << 1)); uint32_t src_stride = p_src.size() / p_elements; uint32_t dst_stride = src_stride + (vertex_16bit ? 4 : 0) + (bone_8 ? 4 : 0) - (weight_32 ? 8 : 0); @@ -676,25 +732,11 @@ static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, ui return ret; } +#endif bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { String sname = p_name; - if (p_name == "blend_shape/names") { - Vector<String> sk = p_value; - int sz = sk.size(); - const String *r = sk.ptr(); - for (int i = 0; i < sz; i++) { - add_blend_shape(r[i]); - } - return true; - } - - if (p_name == "blend_shape/mode") { - set_blend_shape_mode(BlendShapeMode(int(p_value))); - return true; - } - if (sname.begins_with("surface_")) { int sl = sname.find("/"); if (sl == -1) { @@ -732,6 +774,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { add_surface_from_arrays(PrimitiveType(int(d["primitive"])), d["arrays"], d["morph_arrays"]); } else if (d.has("array_data")) { +#if 0 //print_line("array data (old style"); //older format (3.x) Vector<uint8_t> array_data = d["array_data"]; @@ -798,6 +841,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { } add_surface(format, PrimitiveType(primitive), array_data, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb); +#endif } else { ERR_FAIL_V(false); } @@ -816,6 +860,28 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { return false; } +void ArrayMesh::_set_blend_shape_names(const PackedStringArray &p_names) { + ERR_FAIL_COND(surfaces.size() > 0); + + blend_shapes.resize(p_names.size()); + for (int i = 0; i < p_names.size(); i++) { + blend_shapes.write[i] = p_names[i]; + } + + if (mesh.is_valid()) { + RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size()); + } +} + +PackedStringArray ArrayMesh::_get_blend_shape_names() const { + PackedStringArray sarr; + sarr.resize(blend_shapes.size()); + for (int i = 0; i < blend_shapes.size(); i++) { + sarr.write[i] = blend_shapes[i]; + } + return sarr; +} + Array ArrayMesh::_get_surfaces() const { if (mesh.is_null()) { return Array(); @@ -829,6 +895,12 @@ Array ArrayMesh::_get_surfaces() const { data["primitive"] = surface.primitive; data["vertex_data"] = surface.vertex_data; data["vertex_count"] = surface.vertex_count; + if (surface.skin_data.size()) { + data["skin_data"] = surface.skin_data; + } + if (surface.attribute_data.size()) { + data["attribute_data"] = surface.attribute_data; + } data["aabb"] = surface.aabb; if (surface.index_count) { data["index_data"] = surface.index_data; @@ -853,9 +925,8 @@ Array ArrayMesh::_get_surfaces() const { data["bone_aabbs"] = bone_aabbs; } - Array blend_shapes; - for (int j = 0; j < surface.blend_shapes.size(); j++) { - blend_shapes.push_back(surface.blend_shapes[j]); + if (surface.blend_shape_data.size()) { + data["blend_shapes"] = surface.blend_shape_data; } if (surfaces[i].material.is_valid()) { @@ -872,7 +943,6 @@ Array ArrayMesh::_get_surfaces() const { ret.push_back(data); } - print_line("Saving surfaces: " + itos(ret.size())); return ret; } @@ -881,6 +951,7 @@ void ArrayMesh::_create_if_empty() const { if (!mesh.is_valid()) { mesh = RS::get_singleton()->mesh_create(); RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode); + RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size()); } } @@ -902,6 +973,12 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { surface.primitive = RS::PrimitiveType(int(d["primitive"])); surface.vertex_data = d["vertex_data"]; surface.vertex_count = d["vertex_count"]; + if (d.has("attribute_data")) { + surface.attribute_data = d["attribute_data"]; + } + if (d.has("skin_data")) { + surface.skin_data = d["skin_data"]; + } surface.aabb = d["aabb"]; if (d.has("index_data")) { @@ -929,10 +1006,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { } if (d.has("blend_shapes")) { - Array blend_shapes; - for (int j = 0; j < blend_shapes.size(); j++) { - surface.blend_shapes.push_back(blend_shapes[j]); - } + surface.blend_shape_data = d["blend_shapes"]; } Ref<Material> material; @@ -952,15 +1026,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { if (d.has("2d")) { _2d = d["2d"]; } - /* - print_line("format: " + itos(surface.format)); - print_line("aabb: " + surface.aabb); - print_line("array size: " + itos(surface.vertex_data.size())); - print_line("vertex count: " + itos(surface.vertex_count)); - print_line("index size: " + itos(surface.index_data.size())); - print_line("index count: " + itos(surface.index_count)); - print_line("primitive: " + itos(surface.primitive)); -*/ + surface_data.push_back(surface); surface_materials.push_back(material); surface_names.push_back(name); @@ -976,7 +1042,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { } else { // if mesh does not exist (first time this is loaded, most likely), // we can create it with a single call, which is a lot more efficient and thread friendly - mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data); + mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data, blend_shapes.size()); RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode); } @@ -988,7 +1054,6 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { s.aabb = surface_data[i].aabb; if (i == 0) { aabb = s.aabb; - blend_shapes.resize(surface_data[i].blend_shapes.size()); } else { aabb.merge_with(s.aabb); } @@ -1012,18 +1077,7 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const { } String sname = p_name; - - if (p_name == "blend_shape/names") { - Vector<String> sk; - for (int i = 0; i < blend_shapes.size(); i++) { - sk.push_back(blend_shapes[i]); - } - r_ret = sk; - return true; - } else if (p_name == "blend_shape/mode") { - r_ret = get_blend_shape_mode(); - return true; - } else if (sname.begins_with("surface_")) { + if (sname.begins_with("surface_")) { int sl = sname.find("/"); if (sl == -1) { return false; @@ -1041,16 +1095,20 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const { return true; } +void ArrayMesh::reset_state() { + clear_surfaces(); + clear_blend_shapes(); + + aabb = AABB(); + blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE; + custom_aabb = AABB(); +} + void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const { if (_is_generated()) { return; } - if (blend_shapes.size()) { - p_list->push_back(PropertyInfo(Variant::PACKED_STRING_ARRAY, "blend_shape/names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::INT, "blend_shape/mode", PROPERTY_HINT_ENUM, "Normalized,Relative")); - } - for (int i = 0; i < surfaces.size(); i++) { p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); if (surfaces[i].is_2d) { @@ -1076,7 +1134,7 @@ void ArrayMesh::_recompute_aabb() { #ifndef _MSC_VER #warning need to add binding to add_surface using future MeshSurfaceData object #endif -void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t>> &p_blend_shapes, const Vector<AABB> &p_bone_aabb, const Vector<RS::SurfaceData::LOD> &p_lods) { +void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) { _create_if_empty(); Surface s; @@ -1096,16 +1154,18 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const sd.aabb = p_aabb; sd.vertex_count = p_vertex_count; sd.vertex_data = p_array; + sd.attribute_data = p_attribute_array; + sd.skin_data = p_skin_array; sd.index_count = p_index_count; sd.index_data = p_index_array; - sd.blend_shapes = p_blend_shapes; - sd.bone_aabbs = p_bone_aabb; + sd.blend_shape_data = p_blend_shape_data; + sd.bone_aabbs = p_bone_aabbs; sd.lods = p_lods; RenderingServer::get_singleton()->mesh_add_surface(mesh, sd); clear_cache(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -1117,15 +1177,17 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & Error err = RS::get_singleton()->mesh_create_surface_data_from_arrays(&surface, (RenderingServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_lods, p_flags); ERR_FAIL_COND(err != OK); - /* print_line("format: " + itos(surface.format)); + /* Debug code. + print_line("format: " + itos(surface.format)); print_line("aabb: " + surface.aabb); print_line("array size: " + itos(surface.vertex_data.size())); print_line("vertex count: " + itos(surface.vertex_count)); print_line("index size: " + itos(surface.index_data.size())); print_line("index count: " + itos(surface.index_count)); print_line("primitive: " + itos(surface.primitive)); -*/ - add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shapes, surface.bone_aabbs, surface.lods); + */ + + add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.attribute_data, surface.skin_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shape_data, surface.bone_aabbs, surface.lods); } Array ArrayMesh::surface_get_arrays(int p_surface) const { @@ -1161,7 +1223,10 @@ void ArrayMesh::add_blend_shape(const StringName &p_name) { } blend_shapes.push_back(name); - //RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size()); + + if (mesh.is_valid()) { + RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size()); + } } int ArrayMesh::get_blend_shape_count() const { @@ -1177,6 +1242,10 @@ void ArrayMesh::clear_blend_shapes() { ERR_FAIL_COND_MSG(surfaces.size(), "Can't set shape key count if surfaces are already created."); blend_shapes.clear(); + + if (mesh.is_valid()) { + RS::get_singleton()->mesh_set_blend_shape_count(mesh, 0); + } } void ArrayMesh::set_blend_shape_mode(BlendShapeMode p_mode) { @@ -1218,7 +1287,6 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) surfaces.write[p_idx].material = p_material; RenderingServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid()); - _change_notify("material"); emit_changed(); } @@ -1290,7 +1358,7 @@ AABB ArrayMesh::get_custom_aabb() const { return custom_aabb; } -void ArrayMesh::regen_normalmaps() { +void ArrayMesh::regen_normal_maps() { if (surfaces.size() == 0) { return; } @@ -1314,9 +1382,9 @@ bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_v struct ArrayMeshLightmapSurface { Ref<Material> material; - Vector<SurfaceTool::Vertex> vertices; - Mesh::PrimitiveType primitive; - uint32_t format; + LocalVector<SurfaceTool::Vertex> vertices; + Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX; + uint32_t format = 0; }; Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) { @@ -1355,7 +1423,7 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach Array arrays = surface_get_arrays(i); s.material = surface_get_material(i); - s.vertices = SurfaceTool::create_vertex_array_from_triangle_arrays(arrays); + SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices); Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX]; int vc = rvertices.size(); @@ -1458,29 +1526,29 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second]; if (lightmap_surfaces[surface].format & ARRAY_FORMAT_COLOR) { - surfaces_tools.write[surface]->add_color(v.color); + surfaces_tools.write[surface]->set_color(v.color); } if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TEX_UV) { - surfaces_tools.write[surface]->add_uv(v.uv); + surfaces_tools.write[surface]->set_uv(v.uv); } if (lightmap_surfaces[surface].format & ARRAY_FORMAT_NORMAL) { - surfaces_tools.write[surface]->add_normal(v.normal); + surfaces_tools.write[surface]->set_normal(v.normal); } if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TANGENT) { Plane t; t.normal = v.tangent; t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1; - surfaces_tools.write[surface]->add_tangent(t); + surfaces_tools.write[surface]->set_tangent(t); } if (lightmap_surfaces[surface].format & ARRAY_FORMAT_BONES) { - surfaces_tools.write[surface]->add_bones(v.bones); + surfaces_tools.write[surface]->set_bones(v.bones); } if (lightmap_surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) { - surfaces_tools.write[surface]->add_weights(v.weights); + surfaces_tools.write[surface]->set_weights(v.weights); } Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]); - surfaces_tools.write[surface]->add_uv2(uv2); + surfaces_tools.write[surface]->set_uv2(uv2); surfaces_tools.write[surface]->add_vertex(v.vertex); } @@ -1505,6 +1573,19 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach return OK; } +void ArrayMesh::set_shadow_mesh(const Ref<ArrayMesh> &p_mesh) { + shadow_mesh = p_mesh; + if (shadow_mesh.is_valid()) { + RS::get_singleton()->mesh_set_shadow_mesh(mesh, shadow_mesh->get_rid()); + } else { + RS::get_singleton()->mesh_set_shadow_mesh(mesh, RID()); + } +} + +Ref<ArrayMesh> ArrayMesh::get_shadow_mesh() const { + return shadow_mesh; +} + void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape); ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &ArrayMesh::get_blend_shape_count); @@ -1513,7 +1594,7 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ArrayMesh::set_blend_shape_mode); ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode); - ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); + ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0)); ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces); ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region); ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len); @@ -1526,8 +1607,8 @@ void ArrayMesh::_bind_methods() { 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("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("regen_normal_maps"), &ArrayMesh::regen_normal_maps); + ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normal_maps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("lightmap_unwrap", "transform", "texel_size"), &ArrayMesh::lightmap_unwrap); ClassDB::set_method_flags(get_class_static(), _scs_create("lightmap_unwrap"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("get_faces"), &ArrayMesh::get_faces); @@ -1536,36 +1617,20 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb); ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ArrayMesh::get_custom_aabb); + ClassDB::bind_method(D_METHOD("set_shadow_mesh", "mesh"), &ArrayMesh::set_shadow_mesh); + ClassDB::bind_method(D_METHOD("get_shadow_mesh"), &ArrayMesh::get_shadow_mesh); + + ClassDB::bind_method(D_METHOD("_set_blend_shape_names", "blend_shape_names"), &ArrayMesh::_set_blend_shape_names); + ClassDB::bind_method(D_METHOD("_get_blend_shape_names"), &ArrayMesh::_get_blend_shape_names); + ClassDB::bind_method(D_METHOD("_set_surfaces", "surfaces"), &ArrayMesh::_set_surfaces); ClassDB::bind_method(D_METHOD("_get_surfaces"), &ArrayMesh::_get_surfaces); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "_blend_shape_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_blend_shape_names", "_get_blend_shape_names"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces"); ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode"); ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); - - BIND_CONSTANT(NO_INDEX_ARRAY); - BIND_CONSTANT(ARRAY_WEIGHTS_SIZE); - - BIND_ENUM_CONSTANT(ARRAY_VERTEX); - BIND_ENUM_CONSTANT(ARRAY_NORMAL); - BIND_ENUM_CONSTANT(ARRAY_TANGENT); - BIND_ENUM_CONSTANT(ARRAY_COLOR); - BIND_ENUM_CONSTANT(ARRAY_TEX_UV); - BIND_ENUM_CONSTANT(ARRAY_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_BONES); - BIND_ENUM_CONSTANT(ARRAY_WEIGHTS); - BIND_ENUM_CONSTANT(ARRAY_INDEX); - BIND_ENUM_CONSTANT(ARRAY_MAX); - - BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_TANGENT); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shadow_mesh", PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh"), "set_shadow_mesh", "get_shadow_mesh"); } void ArrayMesh::reload_from_file() { @@ -1576,13 +1641,12 @@ void ArrayMesh::reload_from_file() { Resource::reload_from_file(); - _change_notify(); + notify_property_list_changed(); } ArrayMesh::ArrayMesh() { //mesh is now created on demand //mesh = RenderingServer::get_singleton()->mesh_create(); - blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE; } ArrayMesh::~ArrayMesh() { diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 44e4e78322..2ce519e644 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,9 +31,9 @@ #ifndef MESH_H #define MESH_H +#include "core/io/resource.h" #include "core/math/face3.h" #include "core/math/triangle_mesh.h" -#include "core/resource.h" #include "scene/resources/material.h" #include "scene/resources/shape_3d.h" #include "servers/rendering_server.h" @@ -50,19 +50,24 @@ protected: public: enum { - NO_INDEX_ARRAY = RenderingServer::NO_INDEX_ARRAY, ARRAY_WEIGHTS_SIZE = RenderingServer::ARRAY_WEIGHTS_SIZE }; - + enum BlendShapeMode { + BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED, + BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE, + }; enum ArrayType { - ARRAY_VERTEX = RenderingServer::ARRAY_VERTEX, ARRAY_NORMAL = RenderingServer::ARRAY_NORMAL, ARRAY_TANGENT = RenderingServer::ARRAY_TANGENT, ARRAY_COLOR = RenderingServer::ARRAY_COLOR, ARRAY_TEX_UV = RenderingServer::ARRAY_TEX_UV, ARRAY_TEX_UV2 = RenderingServer::ARRAY_TEX_UV2, + ARRAY_CUSTOM0 = RenderingServer::ARRAY_CUSTOM0, + ARRAY_CUSTOM1 = RenderingServer::ARRAY_CUSTOM1, + ARRAY_CUSTOM2 = RenderingServer::ARRAY_CUSTOM2, + ARRAY_CUSTOM3 = RenderingServer::ARRAY_CUSTOM3, ARRAY_BONES = RenderingServer::ARRAY_BONES, ARRAY_WEIGHTS = RenderingServer::ARRAY_WEIGHTS, ARRAY_INDEX = RenderingServer::ARRAY_INDEX, @@ -70,30 +75,47 @@ public: }; + enum ArrayCustomFormat { + ARRAY_CUSTOM_RGBA8_UNORM, + ARRAY_CUSTOM_RGBA8_SNORM, + ARRAY_CUSTOM_RG_HALF, + ARRAY_CUSTOM_RGBA_HALF, + ARRAY_CUSTOM_R_FLOAT, + ARRAY_CUSTOM_RG_FLOAT, + ARRAY_CUSTOM_RGB_FLOAT, + ARRAY_CUSTOM_RGBA_FLOAT, + ARRAY_CUSTOM_MAX + }; + enum ArrayFormat { - /* ARRAY FORMAT FLAGS */ - ARRAY_FORMAT_VERTEX = 1 << ARRAY_VERTEX, // mandatory - ARRAY_FORMAT_NORMAL = 1 << ARRAY_NORMAL, - ARRAY_FORMAT_TANGENT = 1 << ARRAY_TANGENT, - ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR, - ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV, - ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2, - ARRAY_FORMAT_BONES = 1 << ARRAY_BONES, - ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS, - ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX, - - ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1), - ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE), - - ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1, - ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3, - - ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 + ARRAY_FORMAT_VERTEX = RS::ARRAY_FORMAT_VERTEX, + ARRAY_FORMAT_NORMAL = RS::ARRAY_FORMAT_NORMAL, + ARRAY_FORMAT_TANGENT = RS::ARRAY_FORMAT_TANGENT, + ARRAY_FORMAT_COLOR = RS::ARRAY_FORMAT_COLOR, + ARRAY_FORMAT_TEX_UV = RS::ARRAY_FORMAT_TEX_UV, + ARRAY_FORMAT_TEX_UV2 = RS::ARRAY_FORMAT_TEX_UV2, + ARRAY_FORMAT_CUSTOM0 = RS::ARRAY_FORMAT_CUSTOM0, + ARRAY_FORMAT_CUSTOM1 = RS::ARRAY_FORMAT_CUSTOM1, + ARRAY_FORMAT_CUSTOM2 = RS::ARRAY_FORMAT_CUSTOM2, + ARRAY_FORMAT_CUSTOM3 = RS::ARRAY_FORMAT_CUSTOM3, + ARRAY_FORMAT_BONES = RS::ARRAY_FORMAT_BONES, + ARRAY_FORMAT_WEIGHTS = RS::ARRAY_FORMAT_WEIGHTS, + ARRAY_FORMAT_INDEX = RS::ARRAY_FORMAT_INDEX, + + ARRAY_FORMAT_BLEND_SHAPE_MASK = RS::ARRAY_FORMAT_BLEND_SHAPE_MASK, + + ARRAY_FORMAT_CUSTOM_BASE = RS::ARRAY_FORMAT_CUSTOM_BASE, + ARRAY_FORMAT_CUSTOM0_SHIFT = RS::ARRAY_FORMAT_CUSTOM0_SHIFT, + ARRAY_FORMAT_CUSTOM1_SHIFT = RS::ARRAY_FORMAT_CUSTOM1_SHIFT, + ARRAY_FORMAT_CUSTOM2_SHIFT = RS::ARRAY_FORMAT_CUSTOM2_SHIFT, + ARRAY_FORMAT_CUSTOM3_SHIFT = RS::ARRAY_FORMAT_CUSTOM3_SHIFT, + + ARRAY_FORMAT_CUSTOM_MASK = RS::ARRAY_FORMAT_CUSTOM_MASK, + ARRAY_COMPRESS_FLAGS_BASE = RS::ARRAY_COMPRESS_FLAGS_BASE, + + ARRAY_FLAG_USE_2D_VERTICES = RS::ARRAY_FLAG_USE_2D_VERTICES, + ARRAY_FLAG_USE_DYNAMIC_UPDATE = RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE, + ARRAY_FLAG_USE_8_BONE_WEIGHTS = RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS, }; @@ -106,12 +128,6 @@ public: PRIMITIVE_MAX = RenderingServer::PRIMITIVE_MAX, }; - enum BlendShapeMode { - - BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED, - BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE, - }; - virtual int get_surface_count() const = 0; virtual int surface_get_array_len(int p_idx) const = 0; virtual int surface_get_array_index_len(int p_idx) const = 0; @@ -155,25 +171,29 @@ class ArrayMesh : public Mesh { GDCLASS(ArrayMesh, Mesh); RES_BASE_EXTENSION("mesh"); + PackedStringArray _get_blend_shape_names() const; + void _set_blend_shape_names(const PackedStringArray &p_names); + Array _get_surfaces() const; void _set_surfaces(const Array &p_data); + Ref<ArrayMesh> shadow_mesh; private: struct Surface { - uint32_t format; - int array_length; - int index_array_length; - PrimitiveType primitive; + uint32_t format = 0; + int array_length = 0; + int index_array_length = 0; + PrimitiveType primitive = PrimitiveType::PRIMITIVE_MAX; String name; AABB aabb; Ref<Material> material; - bool is_2d; + bool is_2d = false; }; Vector<Surface> surfaces; mutable RID mesh; AABB aabb; - BlendShapeMode blend_shape_mode; + BlendShapeMode blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE; Vector<StringName> blend_shapes; AABB custom_aabb; @@ -187,20 +207,22 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + static void _bind_methods(); public: - void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = ARRAY_COMPRESS_DEFAULT); + void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0); - void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t>> &p_blend_shapes = Vector<Vector<uint8_t>>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>()); + void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>()); - Array surface_get_arrays(int p_surface) const; - Array surface_get_blend_shape_arrays(int p_surface) const; - Dictionary surface_get_lods(int p_surface) const; + Array surface_get_arrays(int p_surface) const override; + Array surface_get_blend_shape_arrays(int p_surface) const override; + Dictionary surface_get_lods(int p_surface) const override; void add_blend_shape(const StringName &p_name); - int get_blend_shape_count() const; - StringName get_blend_shape_name(int p_index) const; + int get_blend_shape_count() const override; + StringName get_blend_shape_name(int p_index) const override; void clear_blend_shapes(); void set_blend_shape_mode(BlendShapeMode p_mode); @@ -208,21 +230,20 @@ public: void surface_update_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); - int get_surface_count() const; - void surface_remove(int p_idx); + int get_surface_count() const override; void clear_surfaces(); void surface_set_custom_aabb(int p_idx, const AABB &p_aabb); //only recognized by driver - int surface_get_array_len(int p_idx) const; - int surface_get_array_index_len(int p_idx) const; - uint32_t surface_get_format(int p_idx) const; - PrimitiveType surface_get_primitive_type(int p_idx) const; + int surface_get_array_len(int p_idx) const override; + int surface_get_array_index_len(int p_idx) const override; + uint32_t surface_get_format(int p_idx) const override; + PrimitiveType surface_get_primitive_type(int p_idx) const override; bool surface_is_alpha_sorting_enabled(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 void surface_set_material(int p_idx, const Ref<Material> &p_material) override; + virtual Ref<Material> surface_get_material(int p_idx) const override; int surface_find_by_name(const String &p_name) const; void surface_set_name(int p_idx, const String &p_name); @@ -231,15 +252,18 @@ public: void set_custom_aabb(const AABB &p_custom); AABB get_custom_aabb() const; - AABB get_aabb() const; - virtual RID get_rid() const; + AABB get_aabb() const override; + virtual RID get_rid() const override; - void regen_normalmaps(); + void regen_normal_maps(); Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); - virtual void reload_from_file(); + virtual void reload_from_file() override; + + void set_shadow_mesh(const Ref<ArrayMesh> &p_mesh); + Ref<ArrayMesh> get_shadow_mesh() const; ArrayMesh(); @@ -248,6 +272,7 @@ public: VARIANT_ENUM_CAST(Mesh::ArrayType); VARIANT_ENUM_CAST(Mesh::ArrayFormat); +VARIANT_ENUM_CAST(Mesh::ArrayCustomFormat); VARIANT_ENUM_CAST(Mesh::PrimitiveType); VARIANT_ENUM_CAST(Mesh::BlendShapeMode); diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index a5c360f123..3fb4f8f211 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,13 +43,35 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf ERR_FAIL_COND_V(p_mesh->surface_get_primitive_type(p_surface) != Mesh::PRIMITIVE_TRIANGLES, ERR_INVALID_PARAMETER); Array arrays = p_mesh->surface_get_arrays(p_surface); - ERR_FAIL_COND_V(arrays.empty(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(arrays.is_empty(), ERR_INVALID_PARAMETER); Vector<Vector3> varray = arrays[Mesh::ARRAY_VERTEX]; int vcount = varray.size(); ERR_FAIL_COND_V(vcount == 0, ERR_INVALID_PARAMETER); + Vector<int> indices; + + if (arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) { + indices = arrays[Mesh::ARRAY_INDEX]; + } else { + //make code simpler + indices.resize(vcount); + int *iw = indices.ptrw(); + for (int i = 0; i < vcount; i++) { + iw[i] = i; + } + } + + int icount = indices.size(); + const int *r = indices.ptr(); + + ERR_FAIL_COND_V(icount == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(icount % 3, ERR_INVALID_PARAMETER); + for (int i = 0; i < icount; i++) { + ERR_FAIL_INDEX_V(r[i], vcount, ERR_INVALID_PARAMETER); + } + clear(); format = p_mesh->surface_get_format(p_surface); material = p_mesh->surface_get_material(p_surface); @@ -128,22 +150,6 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf vertices.write[i] = v; } - Vector<int> indices; - - if (arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) { - indices = arrays[Mesh::ARRAY_INDEX]; - } else { - //make code simpler - indices.resize(vcount); - int *iw = indices.ptrw(); - for (int i = 0; i < vcount; i++) { - iw[i] = i; - } - } - - int icount = indices.size(); - const int *r = indices.ptr(); - Map<Point2i, int> edge_indices; for (int i = 0; i < icount; i += 3) { diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h index bf9f0dd25f..f5c8f11437 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 MeshDataTool : public Reference { GDCLASS(MeshDataTool, Reference); - int format; + int format = 0; struct Vertex { Vector3 vertex; Color color; @@ -54,7 +54,7 @@ class MeshDataTool : public Reference { Vector<Vertex> vertices; struct Edge { - int vertex[2]; + int vertex[2] = {}; Vector<int> faces; Variant meta; }; @@ -62,8 +62,8 @@ class MeshDataTool : public Reference { Vector<Edge> edges; struct Face { - int v[3]; - int edges[3]; + int v[3] = {}; + int edges[3] = {}; Variant meta; }; diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index 09b0d4b038..ad90481fbd 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 +109,14 @@ void MeshLibrary::create_item(int p_item) { ERR_FAIL_COND(p_item < 0); ERR_FAIL_COND(item_map.has(p_item)); item_map[p_item] = Item(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_name(int p_item, const String &p_name) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].name = p_name; emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { @@ -124,25 +124,25 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { item_map[p_item].mesh = p_mesh; notify_change_to_owners(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].shapes = p_shapes; - _change_notify(); + notify_property_list_changed(); notify_change_to_owners(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].navmesh = p_navmesh; - _change_notify(); + notify_property_list_changed(); notify_change_to_owners(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) { @@ -150,14 +150,14 @@ void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_tran item_map[p_item].navmesh_transform = p_transform; notify_change_to_owners(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_preview(int p_item, const Ref<Texture2D> &p_preview) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].preview = p_preview; emit_changed(); - _change_notify(); + notify_property_list_changed(); } String MeshLibrary::get_item_name(int p_item) const { @@ -198,14 +198,14 @@ void MeshLibrary::remove_item(int p_item) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map.erase(p_item); notify_change_to_owners(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } void MeshLibrary::clear() { item_map.clear(); notify_change_to_owners(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -264,6 +264,9 @@ Array MeshLibrary::_get_item_shapes(int p_item) const { return ret; } +void MeshLibrary::reset_state() { + clear(); +} void MeshLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("create_item", "id"), &MeshLibrary::create_item); ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name); diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index 7b78398669..1da624c275 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 GRID_THEME_H -#define GRID_THEME_H +#ifndef MESH_LIBRARY_H +#define MESH_LIBRARY_H -#include "core/map.h" -#include "core/resource.h" +#include "core/io/resource.h" +#include "core/templates/map.h" #include "mesh.h" #include "scene/3d/navigation_region_3d.h" #include "shape_3d.h" @@ -65,6 +65,7 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; static void _bind_methods(); public: @@ -96,4 +97,4 @@ public: ~MeshLibrary(); }; -#endif // CUBE_GRID_THEME_H +#endif // MESH_LIBRARY_H diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index f71cf383e5..4991887eb3 100644 --- a/scene/resources/multimesh.cpp +++ b/scene/resources/multimesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -217,7 +217,7 @@ Ref<Mesh> MultiMesh::get_mesh() const { void MultiMesh::set_instance_count(int p_count) { ERR_FAIL_COND(p_count < 0); - RenderingServer::get_singleton()->multimesh_allocate(multimesh, p_count, RS::MultimeshTransformFormat(transform_format), use_colors, use_custom_data); + RenderingServer::get_singleton()->multimesh_allocate_data(multimesh, p_count, RS::MultimeshTransformFormat(transform_format), use_colors, use_custom_data); instance_count = p_count; } @@ -361,11 +361,6 @@ void MultiMesh::_bind_methods() { MultiMesh::MultiMesh() { multimesh = RenderingServer::get_singleton()->multimesh_create(); - use_colors = false; - use_custom_data = false; - transform_format = TRANSFORM_2D; - visible_instance_count = -1; - instance_count = 0; } MultiMesh::~MultiMesh() { diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h index 8478789d41..ca5c42d47a 100644 --- a/scene/resources/multimesh.h +++ b/scene/resources/multimesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,11 +47,11 @@ public: private: Ref<Mesh> mesh; RID multimesh; - TransformFormat transform_format; - bool use_colors; - bool use_custom_data; - int instance_count; - int visible_instance_count; + TransformFormat transform_format = TRANSFORM_2D; + bool use_colors = false; + bool use_custom_data = false; + int instance_count = 0; + int visible_instance_count = -1; protected: static void _bind_methods(); @@ -105,7 +105,7 @@ public: virtual AABB get_aabb() const; - virtual RID get_rid() const; + virtual RID get_rid() const override; MultiMesh(); ~MultiMesh(); diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index e815da5d45..84f3c23f77 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -74,7 +74,7 @@ int NavigationMesh::get_sample_partition_type() const { 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(); + notify_property_list_changed(); } int NavigationMesh::get_parsed_geometry_type() const { @@ -106,7 +106,7 @@ bool NavigationMesh::get_collision_mask_bit(int p_bit) const { void NavigationMesh::set_source_geometry_mode(int p_geometry_mode) { ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX); source_geometry_mode = static_cast<SourceGeometryMode>(p_geometry_mode); - _change_notify(); + notify_property_list_changed(); } int NavigationMesh::get_source_geometry_mode() const { @@ -251,7 +251,7 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const { void NavigationMesh::set_vertices(const Vector<Vector3> &p_vertices) { vertices = p_vertices; - _change_notify(); + notify_property_list_changed(); } Vector<Vector3> NavigationMesh::get_vertices() const { @@ -263,7 +263,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(); + notify_property_list_changed(); } Array NavigationMesh::_get_polygons() const { @@ -280,7 +280,7 @@ void NavigationMesh::add_polygon(const Vector<int> &p_polygon) { Polygon polygon; polygon.indices = p_polygon; polygons.push_back(polygon); - _change_notify(); + notify_property_list_changed(); } int NavigationMesh::get_polygon_count() const { @@ -510,27 +510,4 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const { } } -NavigationMesh::NavigationMesh() { - cell_size = 0.3f; - cell_height = 0.2f; - agent_height = 2.0f; - agent_radius = 0.6f; - agent_max_climb = 0.9f; - agent_max_slope = 45.0f; - region_min_size = 8.0f; - region_merge_size = 20.0f; - edge_max_length = 12.0f; - edge_max_error = 1.3f; - verts_per_poly = 6.0f; - detail_sample_distance = 6.0f; - detail_sample_max_error = 1.0f; - - partition_type = SAMPLE_PARTITION_WATERSHED; - parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES; - collision_mask = 0xFFFFFFFF; - source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN; - source_group_name = "navmesh"; - filter_low_hanging_obstacles = false; - filter_ledge_spans = false; - filter_walkable_low_height_spans = false; -} +NavigationMesh::NavigationMesh() {} diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index 6b9d1964f5..966221c7c6 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +54,7 @@ class NavigationMesh : public Resource { protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const; + virtual void _validate_property(PropertyInfo &property) const override; void _set_polygons(const Array &p_array); Array _get_polygons() const; @@ -82,30 +82,30 @@ public: }; protected: - float cell_size; - float cell_height; - float agent_height; - float agent_radius; - float agent_max_climb; - float agent_max_slope; - float region_min_size; - float region_merge_size; - float edge_max_length; - float edge_max_error; - float verts_per_poly; - float detail_sample_distance; - float detail_sample_max_error; - - SamplePartitionType partition_type; - ParsedGeometryType parsed_geometry_type; - uint32_t collision_mask; - - SourceGeometryMode source_geometry_mode; - StringName source_group_name; - - bool filter_low_hanging_obstacles; - bool filter_ledge_spans; - bool filter_walkable_low_height_spans; + float cell_size = 0.3f; + float cell_height = 0.2f; + float agent_height = 2.0f; + float agent_radius = 0.6f; + float agent_max_climb = 0.9f; + float agent_max_slope = 45.0f; + float region_min_size = 8.0f; + float region_merge_size = 20.0f; + float edge_max_length = 12.0f; + float edge_max_error = 1.3f; + float verts_per_poly = 6.0f; + float detail_sample_distance = 6.0f; + float detail_sample_max_error = 1.0f; + + SamplePartitionType partition_type = SAMPLE_PARTITION_WATERSHED; + ParsedGeometryType parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES; + uint32_t collision_mask = 0xFFFFFFFF; + + SourceGeometryMode source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN; + StringName source_group_name = "navmesh"; + + bool filter_low_hanging_obstacles = false; + bool filter_ledge_spans = false; + bool filter_walkable_low_height_spans = false; public: // Recast settings diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 058e89cf2e..5d351f51f7 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,10 +30,10 @@ #include "packed_scene.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h" #include "core/core_string_names.h" -#include "core/engine.h" #include "core/io/resource_loader.h" -#include "core/project_settings.h" #include "scene/2d/node_2d.h" #include "scene/3d/node_3d.h" #include "scene/gui/control.h" @@ -80,7 +80,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { Node **ret_nodes = (Node **)alloca(sizeof(Node *) * nc); - bool gen_node_path_cache = p_edit_state != GEN_EDIT_STATE_DISABLED && node_path_cache.empty(); + bool gen_node_path_cache = p_edit_state != GEN_EDIT_STATE_DISABLED && node_path_cache.is_empty(); Map<Ref<Resource>, Ref<Resource>> resources_local_to_scene; @@ -98,6 +98,9 @@ Node *SceneState::instance(GenEditState p_edit_state) const { } #endif parent = nparent; + } else { + // i == 0 is root node. Confirm that it doesn't have a parent defined. + ERR_FAIL_COND_V_MSG(n.parent != -1, nullptr, vformat("Invalid scene: root node %s cannot specify a parent node.", snames[n.name])); } Node *node = nullptr; @@ -466,6 +469,11 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map p_node->get_property_list(&plist); StringName type = p_node->get_class(); + Ref<Script> script = p_node->get_script(); + if (script.is_valid()) { + script->update_exports(); + } + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { continue; @@ -481,7 +489,6 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value)); } - Ref<Script> script = p_node->get_script(); if (!isdefault && script.is_valid() && script->get_property_default_value(name, default_value)) { isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value)); } @@ -600,7 +607,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map // Save the right type. If this node was created by an instance // then flag that the node should not be created but reused - if (pack_state_stack.empty()) { + if (pack_state_stack.is_empty()) { //this node is not part of an instancing process, so save the type nd.type = _nm_get_string(p_node->get_class(), name_map); } else { @@ -845,7 +852,7 @@ Error SceneState::pack(Node *p_scene) { Map<Node *, int> node_map; Map<Node *, int> nodepath_map; - //if using scene inheritance, pack the scene it inherits from + // If using scene inheritance, pack the scene it inherits from. if (scene->get_scene_inherited_state().is_valid()) { String path = scene->get_scene_inherited_state()->get_path(); Ref<PackedScene> instance = ResourceLoader::load(path); @@ -853,8 +860,8 @@ Error SceneState::pack(Node *p_scene) { base_scene_idx = _vm_get_variant(instance, variant_map); } } - //instanced, only direct sub-scnes are supported of course + // Instanced, only direct sub-scenes are supported of course. Error err = _parse_node(scene, scene, -1, name_map, variant_map, node_map, nodepath_map); if (err) { clear(); @@ -1346,7 +1353,7 @@ NodePath SceneState::get_node_path(int p_idx, bool p_for_parent) const { sub_path.insert(0, base_path.get_name(i)); } - if (sub_path.empty()) { + if (sub_path.is_empty()) { return NodePath("."); } @@ -1478,16 +1485,6 @@ int SceneState::add_name(const StringName &p_name) { return names.size() - 1; } -int SceneState::find_name(const StringName &p_name) const { - for (int i = 0; i < names.size(); i++) { - if (names[i] == p_name) { - return i; - } - } - - return -1; -} - int SceneState::add_value(const Variant &p_value) { variants.push_back(p_value); return variants.size() - 1; @@ -1596,8 +1593,6 @@ void SceneState::_bind_methods() { } SceneState::SceneState() { - base_scene_idx = -1; - last_modified_time = 0; } //////////////// @@ -1670,6 +1665,9 @@ void PackedScene::set_path(const String &p_path, bool p_take_over) { Resource::set_path(p_path, p_take_over); } +void PackedScene::reset_state() { + clear(); +} void PackedScene::_bind_methods() { ClassDB::bind_method(D_METHOD("pack", "path"), &PackedScene::pack); ClassDB::bind_method(D_METHOD("instance", "edit_state"), &PackedScene::instance, DEFVAL(GEN_EDIT_STATE_DISABLED)); diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 898d5ff11f..78a0aeaa9a 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef PACKED_SCENE_H #define PACKED_SCENE_H -#include "core/resource.h" +#include "core/io/resource.h" #include "scene/main/node.h" class SceneState : public Reference { @@ -44,7 +44,7 @@ class SceneState : public Reference { mutable HashMap<NodePath, int> node_path_cache; mutable Map<int, int> base_scene_node_remap; - int base_scene_idx; + int base_scene_idx = -1; enum { NO_PARENT_SAVED = 0x7FFFFFFF, @@ -53,16 +53,16 @@ class SceneState : public Reference { }; struct NodeData { - int parent; - int owner; - int type; - int name; - int instance; - int index; + int parent = 0; + int owner = 0; + int type = 0; + int name = 0; + int instance = 0; + int index = 0; struct Property { - int name; - int value; + int name = 0; + int value = 0; }; Vector<Property> properties; @@ -71,18 +71,17 @@ class SceneState : public Reference { struct PackState { Ref<SceneState> state; - int node; - PackState() { node = -1; } + int node = -1; }; Vector<NodeData> nodes; struct ConnectionData { - int from; - int to; - int signal; - int method; - int flags; + int from = 0; + int to = 0; + int signal = 0; + int method = 0; + int flags = 0; Vector<int> binds; }; @@ -93,7 +92,7 @@ class SceneState : public Reference { String path; - uint64_t last_modified_time; + uint64_t last_modified_time = 0; _FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const; @@ -172,7 +171,6 @@ public: //build API int add_name(const StringName &p_name); - int find_name(const StringName &p_name) const; int add_value(const Variant &p_value); int add_node_path(const NodePath &p_path); int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index); @@ -200,8 +198,9 @@ class PackedScene : public Resource { Dictionary _get_bundled_scene() const; protected: - virtual bool editor_can_reload_from_file() { return false; } // this is handled by editor better + virtual bool editor_can_reload_from_file() override { return false; } // this is handled by editor better static void _bind_methods(); + virtual void reset_state() override; public: enum GenEditState { @@ -220,9 +219,9 @@ public: void recreate_state(); void replace_state(Ref<SceneState> p_by); - virtual void set_path(const String &p_path, bool p_take_over = false); + virtual void set_path(const String &p_path, bool p_take_over = false) override; #ifdef TOOLS_ENABLED - virtual void set_last_modified_time(uint64_t p_time) { state->set_last_modified_time(p_time); } + virtual void set_last_modified_time(uint64_t p_time) override { state->set_last_modified_time(p_time); } #endif Ref<SceneState> get_state(); diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index fc92a721db..167540eb77 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,13 +91,16 @@ void ParticlesMaterial::init_shaders() { shader_names->emission_texture_normal = "emission_texture_normal"; shader_names->emission_texture_color = "emission_texture_color"; - shader_names->trail_divisor = "trail_divisor"; - shader_names->trail_size_modifier = "trail_size_modifier"; - shader_names->trail_color_modifier = "trail_color_modifier"; - shader_names->gravity = "gravity"; shader_names->lifetime_randomness = "lifetime_randomness"; + + shader_names->sub_emitter_frequency = "sub_emitter_frequency"; + shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end"; + shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity"; + + shader_names->collision_friction = "collision_friction"; + shader_names->collision_bounce = "collision_bounce"; } void ParticlesMaterial::finish_shaders() { @@ -136,6 +139,10 @@ void ParticlesMaterial::_update_shader() { String code = "shader_type particles;\n"; + if (collision_scale) { + code += "render_mode collision_use_scale;\n"; + } + code += "uniform vec3 direction;\n"; code += "uniform float spread;\n"; code += "uniform float flatness;\n"; @@ -192,9 +199,17 @@ void ParticlesMaterial::_update_shader() { } } - code += "uniform vec4 color_value : hint_color;\n"; + if (sub_emitter_mode != SUB_EMITTER_DISABLED) { + if (sub_emitter_mode == SUB_EMITTER_CONSTANT) { + code += "uniform float sub_emitter_frequency;\n"; + } + if (sub_emitter_mode == SUB_EMITTER_AT_END) { + code += "uniform int sub_emitter_amount_at_end;\n"; + } + code += "uniform bool sub_emitter_keep_velocity;\n"; + } - code += "uniform int trail_divisor;\n"; + code += "uniform vec4 color_value : hint_color;\n"; code += "uniform vec3 gravity;\n"; @@ -239,12 +254,9 @@ void ParticlesMaterial::_update_shader() { code += "uniform sampler2D anim_offset_texture;\n"; } - if (trail_size_modifier.is_valid()) { - code += "uniform sampler2D trail_size_modifier;\n"; - } - - if (trail_color_modifier.is_valid()) { - code += "uniform sampler2D trail_color_modifier;\n"; + if (collision_enabled) { + code += "uniform float collision_friction;\n"; + code += "uniform float collision_bounce;\n"; } //need a random function @@ -277,8 +289,8 @@ void ParticlesMaterial::_update_shader() { code += "}\n"; code += "\n"; - code += "void vertex() {\n"; - code += " uint base_number = NUMBER / uint(trail_divisor);\n"; + code += "void compute() {\n"; + code += " uint base_number = NUMBER;\n"; code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; code += " float angle_rand = rand_from_seed(alt_seed);\n"; code += " float scale_rand = rand_from_seed(alt_seed);\n"; @@ -293,17 +305,8 @@ void ParticlesMaterial::_update_shader() { code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n"; code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; } - code += " bool restart = false;\n"; - code += " if (CUSTOM.y > CUSTOM.w) {\n"; - code += " restart = true;\n"; - code += " }\n\n"; - code += " if (RESTART || restart) {\n"; - - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n"; - } else { - code += " float tex_linear_velocity = 0.0;\n"; - } + code += " float tv = 0.0;\n"; + code += " if (RESTART) {\n"; if (tex_parameters[PARAM_ANGLE].is_valid()) { code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n"; @@ -319,25 +322,34 @@ void ParticlesMaterial::_update_shader() { code += " float spread_rad = spread * degree_to_rad;\n"; - if (flags[FLAG_DISABLE_Z]) { - code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; - code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n"; - code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n"; - code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; + code += " if (RESTART_VELOCITY) {\n"; + + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n"; + } else { + code += " float tex_linear_velocity = 0.0;\n"; + } + + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; + code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n"; + code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n"; + code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; } else { //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 += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n"; - code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\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 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; - code += " vec_direction = normalize(vec_direction);\n"; - code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; + 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 += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n"; + code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\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 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; + code += " vec_direction = normalize(vec_direction);\n"; + code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; } + code += " }\n"; code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n"; code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle @@ -345,35 +357,38 @@ void ParticlesMaterial::_update_shader() { code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n"; code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1) + code += " if (RESTART_POSITION) {\n"; + switch (emission_shape) { case EMISSION_SHAPE_POINT: { - //do none + //do none, identity (will later be multiplied by emission transform) + code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n"; } break; case EMISSION_SHAPE_SPHERE: { - code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; - code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n"; - code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n"; - code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n"; + code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; + code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n"; + code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n"; + code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n"; } break; case EMISSION_SHAPE_BOX: { - code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n"; + code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n"; } break; case EMISSION_SHAPE_POINTS: case EMISSION_SHAPE_DIRECTED_POINTS: { - code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n"; + code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n"; if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { - if (flags[FLAG_DISABLE_Z]) { - code += " mat2 rotm;"; - code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n"; - code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n"; - code += " VELOCITY.xy = rotm * VELOCITY.xy;\n"; + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " mat2 rotm;"; + code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n"; + code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n"; + code += " if (RESTART_VELOCITY) 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.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"; + 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.0, 1.0, 0.0);\n"; + code += " vec3 tangent = normalize(cross(v0, normal));\n"; + code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; + code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n"; } } } break; @@ -381,81 +396,84 @@ void ParticlesMaterial::_update_shader() { break; } } - code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; - code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; - if (flags[FLAG_DISABLE_Z]) { - code += " VELOCITY.z = 0.0;\n"; - code += " TRANSFORM[3].z = 0.0;\n"; + + code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; + code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " VELOCITY.z = 0.0;\n"; + code += " TRANSFORM[3].z = 0.0;\n"; } + code += " }\n"; code += " } else {\n"; code += " CUSTOM.y += DELTA / LIFETIME;\n"; + code += " tv = CUSTOM.y / CUSTOM.w;\n"; if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_linear_velocity = 0.0;\n"; } - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { - code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_orbit_velocity = 0.0;\n"; } } if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { - code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_angular_velocity = 0.0;\n"; } if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) { - code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_linear_accel = 0.0;\n"; } if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) { - code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_radial_accel = 0.0;\n"; } if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { - code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_tangent_accel = 0.0;\n"; } if (tex_parameters[PARAM_DAMPING].is_valid()) { - code += " float tex_damping = textureLod(damping_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_damping = 0.0;\n"; } if (tex_parameters[PARAM_ANGLE].is_valid()) { - code += " float tex_angle = textureLod(angle_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_angle = 0.0;\n"; } if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) { - code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_anim_speed = 0.0;\n"; } if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) { - code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_anim_offset = 0.0;\n"; } code += " vec3 force = gravity;\n"; code += " vec3 pos = TRANSFORM[3].xyz;\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " pos.z = 0.0;\n"; } code += " // apply linear acceleration\n"; @@ -465,17 +483,21 @@ void ParticlesMaterial::_update_shader() { code += " vec3 diff = pos - org;\n"; code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n"; code += " // apply tangential acceleration;\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n"; } else { code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n"; code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n"; } + if (attractor_interaction_enabled) { + code += " force += ATTRACTOR_FORCE;\n\n"; + } + code += " // apply attractor forces\n"; code += " VELOCITY += force * DELTA;\n"; code += " // orbit velocity\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);\n"; code += " if (orbit_amount != 0.0) {\n"; code += " float ang = orbit_amount * DELTA * pi * 2.0;\n"; @@ -506,13 +528,13 @@ void ParticlesMaterial::_update_shader() { // apply color // apply hue rotation if (tex_parameters[PARAM_SCALE].is_valid()) { - code += " float tex_scale = textureLod(scale_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_scale = textureLod(scale_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_scale = 1.0;\n"; } if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) { - code += " float tex_hue_variation = textureLod(hue_variation_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_hue_variation = textureLod(hue_variation_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_hue_variation = 0.0;\n"; } @@ -533,22 +555,17 @@ void ParticlesMaterial::_update_shader() { code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n"; if (color_ramp.is_valid()) { - code += " COLOR = hue_rot_mat * textureLod(color_ramp, vec2(CUSTOM.y, 0.0), 0.0);\n"; + code += " COLOR = hue_rot_mat * textureLod(color_ramp, vec2(tv, 0.0), 0.0);\n"; } else { code += " COLOR = hue_rot_mat * color_value;\n"; } if (emission_color_texture.is_valid() && (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS)) { code += " COLOR *= texelFetch(emission_texture_color, emission_tex_ofs, 0);\n"; } - if (trail_color_modifier.is_valid()) { - code += " if (trail_divisor > 1) {\n"; - code += " COLOR *= textureLod(trail_color_modifier, vec2(float(int(NUMBER) % trail_divisor) / float(trail_divisor - 1), 0.0), 0.0);\n"; - code += " }\n"; - } code += "\n"; - if (flags[FLAG_DISABLE_Z]) { - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { code += " if (length(VELOCITY) > 0.0) {\n"; code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n"; code += " } else {\n"; @@ -564,7 +581,7 @@ void ParticlesMaterial::_update_shader() { } else { // orient particle Y towards velocity - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { code += " if (length(VELOCITY) > 0.0) {\n"; code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n"; code += " } else {\n"; @@ -583,7 +600,7 @@ void ParticlesMaterial::_update_shader() { code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n"; } // turn particle by rotation in Y - if (flags[FLAG_ROTATE_Y]) { + if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) { code += " TRANSFORM = TRANSFORM * mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } } @@ -592,19 +609,49 @@ void ParticlesMaterial::_update_shader() { code += " if (base_scale < 0.000001) {\n"; code += " base_scale = 0.000001;\n"; code += " }\n"; - if (trail_size_modifier.is_valid()) { - code += " if (trail_divisor > 1) {\n"; - code += " base_scale *= textureLod(trail_size_modifier, vec2(float(int(NUMBER) % trail_divisor) / float(trail_divisor - 1), 0.0), 0.0).r;\n"; - code += " }\n"; - } code += " TRANSFORM[0].xyz *= base_scale;\n"; code += " TRANSFORM[1].xyz *= base_scale;\n"; code += " TRANSFORM[2].xyz *= base_scale;\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " VELOCITY.z = 0.0;\n"; code += " TRANSFORM[3].z = 0.0;\n"; } + if (collision_enabled) { + code += " if (COLLIDED) {\n"; + code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n"; + code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n"; + code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n"; + code += " }\n"; + } + if (sub_emitter_mode != SUB_EMITTER_DISABLED) { + code += " int emit_count = 0;\n"; + switch (sub_emitter_mode) { + case SUB_EMITTER_CONSTANT: { + code += " float interval_from = CUSTOM.y * LIFETIME - DELTA;\n"; + code += " float interval_rem = sub_emitter_frequency - mod(interval_from,sub_emitter_frequency);\n"; + code += " if (DELTA >= interval_rem) emit_count = 1;\n"; + } break; + case SUB_EMITTER_AT_COLLISION: { + //not implemented yet + code += " if (COLLIDED) emit_count = 1;\n"; + } break; + case SUB_EMITTER_AT_END: { + //not implemented yet + code += " float unit_delta = DELTA/LIFETIME;\n"; + code += " float end_time = CUSTOM.w * 0.95;\n"; // if we do at the end we might miss it, as it can just get deactivated by emitter + code += " if (CUSTOM.y < end_time && (CUSTOM.y + unit_delta) >= end_time) emit_count = sub_emitter_amount_at_end;\n"; + } break; + default: { + } + } + code += " for(int i=0;i<emit_count;i++) {\n"; + code += " uint flags = FLAG_EMIT_POSITION|FLAG_EMIT_ROT_SCALE;\n"; + code += " if (sub_emitter_keep_velocity) flags|=FLAG_EMIT_VELOCITY;\n"; + code += " emit_subparticle(TRANSFORM,VELOCITY,vec4(0.0),vec4(0.0),flags);\n"; + code += " }"; + } + code += " if (CUSTOM.y > CUSTOM.w) {"; code += " ACTIVE = false;\n"; code += " }\n"; @@ -864,31 +911,31 @@ void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) { color_ramp = p_texture; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture); _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } Ref<Texture2D> ParticlesMaterial::get_color_ramp() const { return color_ramp; } -void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) { - ERR_FAIL_INDEX(p_flag, FLAG_MAX); - flags[p_flag] = p_enable; +void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { + ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); + particle_flags[p_particle_flag] = p_enable; _queue_shader_change(); - if (p_flag == FLAG_DISABLE_Z) { - _change_notify(); + if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) { + notify_property_list_changed(); } } -bool ParticlesMaterial::get_flag(Flags p_flag) const { - ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); - return flags[p_flag]; +bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const { + ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false); + return particle_flags[p_particle_flag]; } void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) { ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); emission_shape = p_shape; - _change_notify(); + notify_property_list_changed(); _queue_shader_change(); } @@ -951,41 +998,6 @@ int ParticlesMaterial::get_emission_point_count() const { return emission_point_count; } -void ParticlesMaterial::set_trail_divisor(int p_divisor) { - trail_divisor = p_divisor; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor); -} - -int ParticlesMaterial::get_trail_divisor() const { - return trail_divisor; -} - -void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier) { - trail_size_modifier = p_trail_size_modifier; - - Ref<CurveTexture> curve = trail_size_modifier; - if (curve.is_valid()) { - curve->ensure_default_setup(); - } - - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve); - _queue_shader_change(); -} - -Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const { - return trail_size_modifier; -} - -void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) { - trail_color_modifier = p_trail_color_modifier; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier); - _queue_shader_change(); -} - -Ref<GradientTexture> ParticlesMaterial::get_trail_color_modifier() const { - return trail_color_modifier; -} - void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) { gravity = p_gravity; Vector3 gset = gravity; @@ -1038,9 +1050,97 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { property.usage = 0; } - if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { + if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) { + property.usage = 0; + } + + if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) { property.usage = 0; } + + if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + property.usage = 0; + } +} + +void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) { + sub_emitter_mode = p_sub_emitter_mode; + _queue_shader_change(); + notify_property_list_changed(); +} + +ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const { + return sub_emitter_mode; +} + +void ParticlesMaterial::set_sub_emitter_frequency(float p_frequency) { + sub_emitter_frequency = p_frequency; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pas delta instead of frequency, since its easier to compute +} +float ParticlesMaterial::get_sub_emitter_frequency() const { + return sub_emitter_frequency; +} + +void ParticlesMaterial::set_sub_emitter_amount_at_end(int p_amount) { + sub_emitter_amount_at_end = p_amount; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_end, p_amount); +} + +int ParticlesMaterial::get_sub_emitter_amount_at_end() const { + return sub_emitter_amount_at_end; +} + +void ParticlesMaterial::set_sub_emitter_keep_velocity(bool p_enable) { + sub_emitter_keep_velocity = p_enable; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable); +} +bool ParticlesMaterial::get_sub_emitter_keep_velocity() const { + return sub_emitter_keep_velocity; +} + +void ParticlesMaterial::set_attractor_interaction_enabled(bool p_enable) { + attractor_interaction_enabled = p_enable; + _queue_shader_change(); +} + +bool ParticlesMaterial::is_attractor_interaction_enabled() const { + return attractor_interaction_enabled; +} + +void ParticlesMaterial::set_collision_enabled(bool p_enabled) { + collision_enabled = p_enabled; + _queue_shader_change(); +} + +bool ParticlesMaterial::is_collision_enabled() const { + return collision_enabled; +} + +void ParticlesMaterial::set_collision_use_scale(bool p_scale) { + collision_scale = p_scale; + _queue_shader_change(); +} + +bool ParticlesMaterial::is_collision_using_scale() const { + return collision_scale; +} + +void ParticlesMaterial::set_collision_friction(float p_friction) { + collision_friction = p_friction; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_friction, p_friction); +} + +float ParticlesMaterial::get_collision_friction() const { + return collision_friction; +} + +void ParticlesMaterial::set_collision_bounce(float p_bounce) { + collision_bounce = p_bounce; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_bounce, p_bounce); +} + +float ParticlesMaterial::get_collision_bounce() const { + return collision_bounce; } Shader::Mode ParticlesMaterial::get_shader_mode() const { @@ -1072,8 +1172,8 @@ void ParticlesMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp); ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp); - ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag); - ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag); + ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticlesMaterial::set_particle_flag); + ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticlesMaterial::get_particle_flag); ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape); ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape); @@ -1096,27 +1196,42 @@ void ParticlesMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count); ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count); - ClassDB::bind_method(D_METHOD("set_trail_divisor", "divisor"), &ParticlesMaterial::set_trail_divisor); - ClassDB::bind_method(D_METHOD("get_trail_divisor"), &ParticlesMaterial::get_trail_divisor); - - ClassDB::bind_method(D_METHOD("set_trail_size_modifier", "texture"), &ParticlesMaterial::set_trail_size_modifier); - ClassDB::bind_method(D_METHOD("get_trail_size_modifier"), &ParticlesMaterial::get_trail_size_modifier); - - ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture"), &ParticlesMaterial::set_trail_color_modifier); - ClassDB::bind_method(D_METHOD("get_trail_color_modifier"), &ParticlesMaterial::get_trail_color_modifier); - ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity); ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity); ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticlesMaterial::set_lifetime_randomness); ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticlesMaterial::get_lifetime_randomness); + ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticlesMaterial::get_sub_emitter_mode); + ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticlesMaterial::set_sub_emitter_mode); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticlesMaterial::get_sub_emitter_frequency); + ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticlesMaterial::set_sub_emitter_frequency); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticlesMaterial::get_sub_emitter_amount_at_end); + ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticlesMaterial::set_sub_emitter_amount_at_end); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticlesMaterial::get_sub_emitter_keep_velocity); + ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticlesMaterial::set_sub_emitter_keep_velocity); + + ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticlesMaterial::set_attractor_interaction_enabled); + ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticlesMaterial::is_attractor_interaction_enabled); + + ClassDB::bind_method(D_METHOD("set_collision_enabled", "enabled"), &ParticlesMaterial::set_collision_enabled); + ClassDB::bind_method(D_METHOD("is_collision_enabled"), &ParticlesMaterial::is_collision_enabled); + + ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticlesMaterial::set_collision_use_scale); + ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticlesMaterial::is_collision_using_scale); + + ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticlesMaterial::set_collision_friction); + ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticlesMaterial::get_collision_friction); + + ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticlesMaterial::set_collision_bounce); + ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticlesMaterial::get_collision_bounce); + ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness"); - ADD_GROUP("Trail", "trail_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier"); + ADD_GROUP("Emission Shape", "emission_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius"); @@ -1125,10 +1240,10 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_normal_texture", "get_emission_normal_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_color_texture", "get_emission_color_texture"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count"); - ADD_GROUP("Flags", "flag_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_flag", "get_flag", FLAG_DISABLE_Z); + ADD_GROUP("ParticleFlags", "particle_flag_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z); ADD_GROUP("Direction", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); @@ -1186,6 +1301,20 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); + ADD_GROUP("Sub Emitter", "sub_emitter_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,AtEnd,AtCollision"), "set_sub_emitter_mode", "get_sub_emitter_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_sub_emitter_frequency", "get_sub_emitter_frequency"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity"); + + ADD_GROUP("Attractor Interaction", "attractor_interaction_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled"); + ADD_GROUP("Collision", "collision_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_enabled"), "set_collision_enabled", "is_collision_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_scale"), "set_collision_use_scale", "is_collision_using_scale"); + BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); @@ -1200,10 +1329,10 @@ void ParticlesMaterial::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); BIND_ENUM_CONSTANT(PARAM_MAX); - 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(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); @@ -1211,6 +1340,12 @@ void ParticlesMaterial::_bind_methods() { BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX); + + BIND_ENUM_CONSTANT(SUB_EMITTER_DISABLED); + BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT); + BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END); + BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION); + BIND_ENUM_CONSTANT(SUB_EMITTER_MAX); } ParticlesMaterial::ParticlesMaterial() : @@ -1233,22 +1368,30 @@ ParticlesMaterial::ParticlesMaterial() : set_emission_shape(EMISSION_SHAPE_POINT); set_emission_sphere_radius(1); set_emission_box_extents(Vector3(1, 1, 1)); - set_trail_divisor(1); set_gravity(Vector3(0, -9.8, 0)); set_lifetime_randomness(0); - emission_point_count = 1; + + set_sub_emitter_mode(SUB_EMITTER_DISABLED); + set_sub_emitter_frequency(4); + set_sub_emitter_amount_at_end(1); + set_sub_emitter_keep_velocity(false); + + set_attractor_interaction_enabled(true); + set_collision_enabled(true); + set_collision_bounce(0.0); + set_collision_friction(0.0); + set_collision_use_scale(false); for (int i = 0; i < PARAM_MAX; i++) { set_param_randomness(Parameter(i), 0); } - for (int i = 0; i < FLAG_MAX; i++) { - flags[i] = false; + for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { + particle_flags[i] = false; } set_color(Color(1, 1, 1, 1)); - current_key.key = 0; current_key.invalid_key = 1; _queue_shader_change(); diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index a1a4c38842..3f874bd68c 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,18 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/rid.h" +#include "core/templates/rid.h" #include "scene/resources/material.h" #ifndef PARTICLES_MATERIAL_H #define PARTICLES_MATERIAL_H +/* + TODO: +-Path following +-Emitter positions deformable by bones +-Proper trails +*/ + class ParticlesMaterial : public Material { GDCLASS(ParticlesMaterial, Material); public: enum Parameter { - PARAM_INITIAL_LINEAR_VELOCITY, PARAM_ANGULAR_VELOCITY, PARAM_ORBIT_VELOCITY, @@ -55,11 +61,11 @@ public: PARAM_MAX }; - enum Flags { - FLAG_ALIGN_Y_TO_VELOCITY, - FLAG_ROTATE_Y, - FLAG_DISABLE_Z, - FLAG_MAX + enum ParticleFlags { + PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, + PARTICLE_FLAG_ROTATE_Y, + PARTICLE_FLAG_DISABLE_Z, + PARTICLE_FLAG_MAX }; enum EmissionShape { @@ -71,20 +77,30 @@ public: EMISSION_SHAPE_MAX }; + enum SubEmitterMode { + SUB_EMITTER_DISABLED, + SUB_EMITTER_CONSTANT, + SUB_EMITTER_AT_END, + SUB_EMITTER_AT_COLLISION, + SUB_EMITTER_MAX + }; + private: union MaterialKey { struct { uint32_t texture_mask : 16; uint32_t texture_color : 1; - uint32_t flags : 4; + uint32_t particle_flags : 4; uint32_t emission_shape : 2; - uint32_t trail_size_texture : 1; - uint32_t trail_color_texture : 1; uint32_t invalid_key : 1; uint32_t has_emission_color : 1; + uint32_t sub_emitter : 2; + uint32_t attractor_enabled : 1; + uint32_t collision_enabled : 1; + uint32_t collision_scale : 1; }; - uint32_t key; + uint32_t key = 0; bool operator<(const MaterialKey &p_key) const { return key < p_key.key; @@ -93,7 +109,7 @@ private: struct ShaderData { RID shader; - int users; + int users = 0; }; static Map<MaterialKey, ShaderData> shader_map; @@ -108,17 +124,19 @@ private: mk.texture_mask |= (1 << i); } } - for (int i = 0; i < FLAG_MAX; i++) { - if (flags[i]) { - mk.flags |= (1 << i); + for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { + if (particle_flags[i]) { + mk.particle_flags |= (1 << i); } } mk.texture_color = color_ramp.is_valid() ? 1 : 0; mk.emission_shape = emission_shape; - mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0; - mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0; mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid(); + mk.sub_emitter = sub_emitter_mode; + mk.collision_enabled = collision_enabled; + mk.attractor_enabled = attractor_interaction_enabled; + mk.collision_scale = collision_scale; return mk; } @@ -178,13 +196,16 @@ private: StringName emission_texture_normal; StringName emission_texture_color; - StringName trail_divisor; - StringName trail_size_modifier; - StringName trail_color_modifier; - StringName gravity; StringName lifetime_randomness; + + StringName sub_emitter_frequency; + StringName sub_emitter_amount_at_end; + StringName sub_emitter_keep_velocity; + + StringName collision_friction; + StringName collision_bounce; }; static ShaderNames *shader_names; @@ -206,7 +227,7 @@ private: Color color; Ref<Texture2D> color_ramp; - bool flags[FLAG_MAX]; + bool particle_flags[PARTICLE_FLAG_MAX]; EmissionShape emission_shape; float emission_sphere_radius; @@ -214,24 +235,29 @@ private: Ref<Texture2D> emission_point_texture; Ref<Texture2D> emission_normal_texture; Ref<Texture2D> emission_color_texture; - int emission_point_count; + int emission_point_count = 1; bool anim_loop; - int trail_divisor; - - Ref<CurveTexture> trail_size_modifier; - Ref<GradientTexture> trail_color_modifier; - Vector3 gravity; float lifetime_randomness; + SubEmitterMode sub_emitter_mode; + float sub_emitter_frequency; + int sub_emitter_amount_at_end; + bool sub_emitter_keep_velocity; //do not save emission points here + bool attractor_interaction_enabled; + bool collision_enabled; + bool collision_scale; + float collision_friction; + float collision_bounce; + protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const; + virtual void _validate_property(PropertyInfo &property) const override; public: void set_direction(Vector3 p_direction); @@ -258,8 +284,8 @@ public: void set_color_ramp(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_color_ramp() const; - void set_flag(Flags p_flag, bool p_enable); - bool get_flag(Flags p_flag) const; + void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable); + bool get_particle_flag(ParticleFlags p_particle_flag) const; void set_emission_shape(EmissionShape p_shape); void set_emission_sphere_radius(float p_radius); @@ -277,35 +303,54 @@ public: Ref<Texture2D> get_emission_color_texture() const; int get_emission_point_count() const; - void set_trail_divisor(int p_divisor); - int get_trail_divisor() const; - - void set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier); - Ref<CurveTexture> get_trail_size_modifier() const; - - void set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier); - Ref<GradientTexture> get_trail_color_modifier() const; - void set_gravity(const Vector3 &p_gravity); Vector3 get_gravity() const; void set_lifetime_randomness(float p_lifetime); float get_lifetime_randomness() const; + void set_attractor_interaction_enabled(bool p_enable); + bool is_attractor_interaction_enabled() const; + + void set_collision_enabled(bool p_enabled); + bool is_collision_enabled() const; + + void set_collision_use_scale(bool p_scale); + bool is_collision_using_scale() const; + + void set_collision_friction(float p_friction); + float get_collision_friction() const; + + void set_collision_bounce(float p_bounce); + float get_collision_bounce() const; + static void init_shaders(); static void finish_shaders(); static void flush_changes(); - RID get_shader_rid() const; + void set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode); + SubEmitterMode get_sub_emitter_mode() const; + + void set_sub_emitter_frequency(float p_frequency); + float get_sub_emitter_frequency() const; + + void set_sub_emitter_amount_at_end(int p_amount); + int get_sub_emitter_amount_at_end() const; + + void set_sub_emitter_keep_velocity(bool p_enable); + bool get_sub_emitter_keep_velocity() const; + + virtual RID get_shader_rid() const override; - virtual Shader::Mode get_shader_mode() const; + virtual Shader::Mode get_shader_mode() const override; ParticlesMaterial(); ~ParticlesMaterial(); }; VARIANT_ENUM_CAST(ParticlesMaterial::Parameter) -VARIANT_ENUM_CAST(ParticlesMaterial::Flags) +VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags) VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape) +VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode) #endif // PARTICLES_MATERIAL_H diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp index 2a5cd1101a..d65b0c8927 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,9 +43,9 @@ void PhysicsMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_absorbent", "absorbent"), &PhysicsMaterial::set_absorbent); ClassDB::bind_method(D_METHOD("is_absorbent"), &PhysicsMaterial::is_absorbent); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction"), "set_friction", "get_friction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rough"), "set_rough", "is_rough"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "absorbent"), "set_absorbent", "is_absorbent"); } diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h index 34aa7066df..d302800823 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef PHYSICS_MATERIAL_H #define PHYSICS_MATERIAL_H -#include "core/resource.h" +#include "core/io/resource.h" #include "servers/physics_server_3d.h" class PhysicsMaterial : public Resource { @@ -39,9 +39,9 @@ class PhysicsMaterial : public Resource { OBJ_SAVE_TYPE(PhysicsMaterial); RES_BASE_EXTENSION("phymat"); - real_t friction = 1; + real_t friction = 1.0; bool rough = false; - real_t bounce = 0; + real_t bounce = 0.0; bool absorbent = false; protected: diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index 0546c92948..f292140d6b 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 @@ /*************************************************************************/ #include "polygon_path_finder.h" -#include "core/math/geometry.h" +#include "core/math/geometry_2d.h" bool PolygonPathFinder::_is_point_inside(const Vector2 &p_point) const { int crosses = 0; @@ -40,7 +40,7 @@ bool PolygonPathFinder::_is_point_inside(const Vector2 &p_point) const { Vector2 a = points[e.points[0]].pos; Vector2 b = points[e.points[1]].pos; - if (Geometry::segment_intersects_segment_2d(a, b, p_point, outside_point, nullptr)) { + if (Geometry2D::segment_intersects_segment(a, b, p_point, outside_point, nullptr)) { crosses++; } } @@ -114,7 +114,7 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int> Vector2 a = points[e.points[0]].pos; Vector2 b = points[e.points[1]].pos; - if (Geometry::segment_intersects_segment_2d(a, b, from, to, nullptr)) { + if (Geometry2D::segment_intersects_segment(a, b, from, to, nullptr)) { valid = false; break; } @@ -147,7 +147,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector points[e.points[1]].pos }; - Vector2 closest = Geometry::get_closest_point_to_segment_2d(from, seg); + Vector2 closest = Geometry2D::get_closest_point_to_segment(from, seg); float d = from.distance_squared_to(closest); if (d < closest_dist) { @@ -171,7 +171,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector points[e.points[1]].pos }; - Vector2 closest = Geometry::get_closest_point_to_segment_2d(to, seg); + Vector2 closest = Geometry2D::get_closest_point_to_segment(to, seg); float d = to.distance_squared_to(closest); if (d < closest_dist) { @@ -200,7 +200,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector Vector2 a = points[e.points[0]].pos; Vector2 b = points[e.points[1]].pos; - if (Geometry::segment_intersects_segment_2d(a, b, from, to, nullptr)) { + if (Geometry2D::segment_intersects_segment(a, b, from, to, nullptr)) { can_see_eachother = false; break; } @@ -255,7 +255,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector e.points[1] != ignore_from_edge.points[1] && e.points[0] != ignore_from_edge.points[0] && e.points[1] != ignore_from_edge.points[0]) { - if (Geometry::segment_intersects_segment_2d(a, b, from, points[i].pos, nullptr)) { + if (Geometry2D::segment_intersects_segment(a, b, from, points[i].pos, nullptr)) { valid_a = false; } } @@ -266,7 +266,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector e.points[1] != ignore_to_edge.points[1] && e.points[0] != ignore_to_edge.points[0] && e.points[1] != ignore_to_edge.points[0]) { - if (Geometry::segment_intersects_segment_2d(a, b, to, points[i].pos, nullptr)) { + if (Geometry2D::segment_intersects_segment(a, b, to, points[i].pos, nullptr)) { valid_b = false; } } @@ -499,7 +499,7 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const { points[e.points[1]].pos }; - Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, seg); + Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, seg); float d = p_point.distance_squared_to(closest); if (d < closest_dist) { @@ -521,7 +521,7 @@ Vector<Vector2> PolygonPathFinder::get_intersections(const Vector2 &p_from, cons Vector2 b = points[E->get().points[1]].pos; Vector2 res; - if (Geometry::segment_intersects_segment_2d(a, b, p_from, p_to, &res)) { + if (Geometry2D::segment_intersects_segment(a, b, p_from, p_to, &res)) { inters.push_back(res); } } diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h index baee4dc20d..2f3cb634fb 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef POLYGON_PATH_FINDER_H #define POLYGON_PATH_FINDER_H -#include "core/resource.h" +#include "core/io/resource.h" class PolygonPathFinder : public Resource { GDCLASS(PolygonPathFinder, Resource); @@ -39,13 +39,13 @@ class PolygonPathFinder : public Resource { struct Point { Vector2 pos; Set<int> connections; - float distance; - float penalty; - int prev; + float distance = 0.0; + float penalty = 0.0; + int prev = 0; }; struct Edge { - int points[2]; + int points[2] = {}; _FORCE_INLINE_ bool operator<(const Edge &p_edge) const { if (points[0] == p_edge.points[0]) { diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 99edf26dc1..ba6c4591c9 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -148,7 +148,7 @@ Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const { uint32_t PrimitiveMesh::surface_get_format(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, 1, 0); - return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX | RS::ARRAY_COMPRESS_DEFAULT; + return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX; } Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const { @@ -204,7 +204,7 @@ void PrimitiveMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &PrimitiveMesh::set_flip_faces); ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D"), "set_material", "get_material"); ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces"); } @@ -214,7 +214,7 @@ void PrimitiveMesh::set_material(const Ref<Material> &p_material) { if (!pending_request) { // just apply it, else it'll happen when _update is called. RenderingServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid()); - _change_notify(); + notify_property_list_changed(); emit_changed(); }; } @@ -247,18 +247,7 @@ bool PrimitiveMesh::get_flip_faces() const { } PrimitiveMesh::PrimitiveMesh() { - flip_faces = false; - // defaults mesh = RenderingServer::get_singleton()->mesh_create(); - - // assume primitive triangles as the type, correct for all but one and it will change this :) - primitive_type = Mesh::PRIMITIVE_TRIANGLES; - - // make sure we do an update after we've finished constructing our object - pending_request = true; - - array_len = 0; - index_array_len = 0; } PrimitiveMesh::~PrimitiveMesh() { @@ -304,8 +293,8 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const { u = i; u /= radial_segments; - x = -sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + x = -sin(u * Math_TAU); + z = cos(u * Math_TAU); Vector3 p = Vector3(x * radius * w, y, -z * radius * w); points.push_back(p + Vector3(0.0, 0.5 * mid_height, 0.0)); @@ -343,8 +332,8 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const { u = i; u /= radial_segments; - x = -sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + x = -sin(u * Math_TAU); + z = cos(u * Math_TAU); Vector3 p = Vector3(x * radius, y, -z * radius); points.push_back(p); @@ -383,8 +372,8 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const { float u2 = i; u2 /= radial_segments; - x = -sin(u2 * (Math_PI * 2.0)); - z = cos(u2 * (Math_PI * 2.0)); + x = -sin(u2 * Math_TAU); + z = cos(u2 * Math_TAU); Vector3 p = Vector3(x * radius * w, y, -z * radius * w); points.push_back(p + Vector3(0.0, -0.5 * mid_height, 0.0)); @@ -468,19 +457,13 @@ int CapsuleMesh::get_rings() const { return rings; } -CapsuleMesh::CapsuleMesh() { - // defaults - radius = 1.0; - mid_height = 1.0; - radial_segments = 64; - rings = 8; -} +CapsuleMesh::CapsuleMesh() {} /** - CubeMesh + BoxMesh */ -void CubeMesh::_create_mesh_array(Array &p_arr) const { +void BoxMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, y, z; float onethird = 1.0 / 3.0; @@ -672,16 +655,16 @@ void CubeMesh::_create_mesh_array(Array &p_arr) const { p_arr[RS::ARRAY_INDEX] = indices; } -void CubeMesh::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_size", "size"), &CubeMesh::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &CubeMesh::get_size); +void BoxMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxMesh::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &BoxMesh::get_size); - ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &CubeMesh::set_subdivide_width); - ClassDB::bind_method(D_METHOD("get_subdivide_width"), &CubeMesh::get_subdivide_width); - ClassDB::bind_method(D_METHOD("set_subdivide_height", "divisions"), &CubeMesh::set_subdivide_height); - ClassDB::bind_method(D_METHOD("get_subdivide_height"), &CubeMesh::get_subdivide_height); - ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &CubeMesh::set_subdivide_depth); - ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth); + ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &BoxMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &BoxMesh::get_subdivide_width); + ClassDB::bind_method(D_METHOD("set_subdivide_height", "divisions"), &BoxMesh::set_subdivide_height); + ClassDB::bind_method(D_METHOD("get_subdivide_height"), &BoxMesh::get_subdivide_height); + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &BoxMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &BoxMesh::get_subdivide_depth); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); @@ -689,49 +672,43 @@ void CubeMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); } -void CubeMesh::set_size(const Vector3 &p_size) { +void BoxMesh::set_size(const Vector3 &p_size) { size = p_size; _request_update(); } -Vector3 CubeMesh::get_size() const { +Vector3 BoxMesh::get_size() const { return size; } -void CubeMesh::set_subdivide_width(const int p_divisions) { +void BoxMesh::set_subdivide_width(const int p_divisions) { subdivide_w = p_divisions > 0 ? p_divisions : 0; _request_update(); } -int CubeMesh::get_subdivide_width() const { +int BoxMesh::get_subdivide_width() const { return subdivide_w; } -void CubeMesh::set_subdivide_height(const int p_divisions) { +void BoxMesh::set_subdivide_height(const int p_divisions) { subdivide_h = p_divisions > 0 ? p_divisions : 0; _request_update(); } -int CubeMesh::get_subdivide_height() const { +int BoxMesh::get_subdivide_height() const { return subdivide_h; } -void CubeMesh::set_subdivide_depth(const int p_divisions) { +void BoxMesh::set_subdivide_depth(const int p_divisions) { subdivide_d = p_divisions > 0 ? p_divisions : 0; _request_update(); } -int CubeMesh::get_subdivide_depth() const { +int BoxMesh::get_subdivide_depth() const { return subdivide_d; } -CubeMesh::CubeMesh() { - // defaults - size = Vector3(2.0, 2.0, 2.0); - subdivide_w = 0; - subdivide_h = 0; - subdivide_d = 0; -} +BoxMesh::BoxMesh() {} /** CylinderMesh @@ -769,8 +746,8 @@ void CylinderMesh::_create_mesh_array(Array &p_arr) const { u = i; u /= radial_segments; - x = sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + x = sin(u * Math_TAU); + z = cos(u * Math_TAU); Vector3 p = Vector3(x * radius, y, z * radius); points.push_back(p); @@ -809,8 +786,8 @@ void CylinderMesh::_create_mesh_array(Array &p_arr) const { float r = i; r /= radial_segments; - x = sin(r * (Math_PI * 2.0)); - z = cos(r * (Math_PI * 2.0)); + x = sin(r * Math_TAU); + z = cos(r * Math_TAU); u = ((x + 1.0) * 0.25); v = 0.5 + ((z + 1.0) * 0.25); @@ -845,8 +822,8 @@ void CylinderMesh::_create_mesh_array(Array &p_arr) const { float r = i; r /= radial_segments; - x = sin(r * (Math_PI * 2.0)); - z = cos(r * (Math_PI * 2.0)); + x = sin(r * Math_TAU); + z = cos(r * Math_TAU); u = 0.5 + ((x + 1.0) * 0.25); v = 1.0 - ((z + 1.0) * 0.25); @@ -938,14 +915,7 @@ int CylinderMesh::get_rings() const { return rings; } -CylinderMesh::CylinderMesh() { - // defaults - top_radius = 1.0; - bottom_radius = 1.0; - height = 2.0; - radial_segments = 64; - rings = 4; -} +CylinderMesh::CylinderMesh() {} /** PlaneMesh @@ -1053,12 +1023,7 @@ int PlaneMesh::get_subdivide_depth() const { return subdivide_d; } -PlaneMesh::PlaneMesh() { - // defaults - size = Size2(2.0, 2.0); - subdivide_w = 0; - subdivide_d = 0; -} +PlaneMesh::PlaneMesh() {} /** PrismMesh @@ -1338,14 +1303,7 @@ int PrismMesh::get_subdivide_depth() const { return subdivide_d; } -PrismMesh::PrismMesh() { - // defaults - left_to_right = 0.5; - size = Vector3(2.0, 2.0, 2.0); - subdivide_w = 0; - subdivide_h = 0; - subdivide_d = 0; -} +PrismMesh::PrismMesh() {} /** QuadMesh @@ -1409,7 +1367,6 @@ void QuadMesh::_bind_methods() { QuadMesh::QuadMesh() { primitive_type = PRIMITIVE_TRIANGLES; - size = Size2(1.0, 1.0); } void QuadMesh::set_size(const Size2 &p_size) { @@ -1458,8 +1415,8 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const { float u = i; u /= radial_segments; - x = sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + x = sin(u * Math_TAU); + z = cos(u * Math_TAU); if (is_hemisphere && y < 0.0) { points.push_back(Vector3(x * radius * w, 0.0, z * radius * w)); @@ -1561,14 +1518,7 @@ bool SphereMesh::get_is_hemisphere() const { return is_hemisphere; } -SphereMesh::SphereMesh() { - // defaults - radius = 1.0; - height = 2.0; - radial_segments = 64; - rings = 32; - is_hemisphere = false; -} +SphereMesh::SphereMesh() {} /** PointMesh diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 3cffa44e3a..bb3df9d10e 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,17 +49,19 @@ private: mutable AABB aabb; AABB custom_aabb; - mutable int array_len; - mutable int index_array_len; + mutable int array_len = 0; + mutable int index_array_len = 0; Ref<Material> material; - bool flip_faces; + bool flip_faces = false; - mutable bool pending_request; + // make sure we do an update after we've finished constructing our object + mutable bool pending_request = true; void _update() const; protected: - Mesh::PrimitiveType primitive_type; + // assume primitive triangles as the type, correct for all but one and it will change this :) + Mesh::PrimitiveType primitive_type = Mesh::PRIMITIVE_TRIANGLES; static void _bind_methods(); @@ -67,20 +69,20 @@ protected: void _request_update(); public: - virtual int get_surface_count() const; - virtual int surface_get_array_len(int p_idx) const; - virtual int surface_get_array_index_len(int p_idx) const; - virtual Array surface_get_arrays(int p_surface) const; - virtual Array surface_get_blend_shape_arrays(int p_surface) const; - virtual Dictionary surface_get_lods(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; - virtual AABB get_aabb() const; - virtual RID get_rid() const; + virtual int get_surface_count() const override; + virtual int surface_get_array_len(int p_idx) const override; + virtual int surface_get_array_index_len(int p_idx) const override; + virtual Array surface_get_arrays(int p_surface) const override; + virtual Array surface_get_blend_shape_arrays(int p_surface) const override; + virtual Dictionary surface_get_lods(int p_surface) const override; + virtual uint32_t surface_get_format(int p_idx) const override; + virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const override; + virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) override; + virtual Ref<Material> surface_get_material(int p_idx) const override; + virtual int get_blend_shape_count() const override; + virtual StringName get_blend_shape_name(int p_index) const override; + virtual AABB get_aabb() const override; + virtual RID get_rid() const override; void set_material(const Ref<Material> &p_material); Ref<Material> get_material() const; @@ -104,14 +106,14 @@ class CapsuleMesh : public PrimitiveMesh { GDCLASS(CapsuleMesh, PrimitiveMesh); private: - float radius; - float mid_height; - int radial_segments; - int rings; + float radius = 1.0; + float mid_height = 1.0; + int radial_segments = 64; + int rings = 8; protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const; + virtual void _create_mesh_array(Array &p_arr) const override; public: void set_radius(const float p_radius); @@ -130,20 +132,20 @@ public: }; /** - Similar to test cube but with subdivision support and different texture coordinates + A box */ -class CubeMesh : public PrimitiveMesh { - GDCLASS(CubeMesh, PrimitiveMesh); +class BoxMesh : public PrimitiveMesh { + GDCLASS(BoxMesh, PrimitiveMesh); private: - Vector3 size; - int subdivide_w; - int subdivide_h; - int subdivide_d; + Vector3 size = Vector3(2.0, 2.0, 2.0); + int subdivide_w = 0; + int subdivide_h = 0; + int subdivide_d = 0; protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const; + virtual void _create_mesh_array(Array &p_arr) const override; public: void set_size(const Vector3 &p_size); @@ -158,7 +160,7 @@ public: void set_subdivide_depth(const int p_divisions); int get_subdivide_depth() const; - CubeMesh(); + BoxMesh(); }; /** @@ -169,15 +171,15 @@ class CylinderMesh : public PrimitiveMesh { GDCLASS(CylinderMesh, PrimitiveMesh); private: - float top_radius; - float bottom_radius; - float height; - int radial_segments; - int rings; + float top_radius = 1.0; + float bottom_radius = 1.0; + float height = 2.0; + int radial_segments = 64; + int rings = 4; protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const; + virtual void _create_mesh_array(Array &p_arr) const override; public: void set_top_radius(const float p_radius); @@ -205,13 +207,13 @@ class PlaneMesh : public PrimitiveMesh { GDCLASS(PlaneMesh, PrimitiveMesh); private: - Size2 size; - int subdivide_w; - int subdivide_d; + Size2 size = Size2(2.0, 2.0); + int subdivide_w = 0; + int subdivide_d = 0; protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const; + virtual void _create_mesh_array(Array &p_arr) const override; public: void set_size(const Size2 &p_size); @@ -233,15 +235,15 @@ class PrismMesh : public PrimitiveMesh { GDCLASS(PrismMesh, PrimitiveMesh); private: - float left_to_right; - Vector3 size; - int subdivide_w; - int subdivide_h; - int subdivide_d; + float left_to_right = 0.5; + Vector3 size = Vector3(2.0, 2.0, 2.0); + int subdivide_w = 0; + int subdivide_h = 0; + int subdivide_d = 0; protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const; + virtual void _create_mesh_array(Array &p_arr) const override; public: void set_left_to_right(const float p_left_to_right); @@ -270,11 +272,11 @@ class QuadMesh : public PrimitiveMesh { GDCLASS(QuadMesh, PrimitiveMesh); private: - Size2 size; + Size2 size = Size2(1.0, 1.0); protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const; + virtual void _create_mesh_array(Array &p_arr) const override; public: QuadMesh(); @@ -290,15 +292,15 @@ class SphereMesh : public PrimitiveMesh { GDCLASS(SphereMesh, PrimitiveMesh); private: - float radius; - float height; - int radial_segments; - int rings; - bool is_hemisphere; + float radius = 1.0; + float height = 2.0; + int radial_segments = 64; + int rings = 32; + bool is_hemisphere = false; protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const; + virtual void _create_mesh_array(Array &p_arr) const override; public: void set_radius(const float p_radius); @@ -327,7 +329,7 @@ class PointMesh : public PrimitiveMesh { GDCLASS(PointMesh, PrimitiveMesh) protected: - virtual void _create_mesh_array(Array &p_arr) const; + virtual void _create_mesh_array(Array &p_arr) const override; public: PointMesh(); diff --git a/scene/resources/ray_shape_2d.cpp b/scene/resources/ray_shape_2d.cpp new file mode 100644 index 0000000000..d2125445fa --- /dev/null +++ b/scene/resources/ray_shape_2d.cpp @@ -0,0 +1,103 @@ +/*************************************************************************/ +/* ray_shape_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "ray_shape_2d.h" + +#include "servers/physics_server_2d.h" +#include "servers/rendering_server.h" + +void RayShape2D::_update_shape() { + Dictionary d; + d["length"] = length; + d["slips_on_slope"] = slips_on_slope; + PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), d); + emit_changed(); +} + +void RayShape2D::draw(const RID &p_to_rid, const Color &p_color) { + Vector2 tip = Vector2(0, get_length()); + RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), tip, p_color, 3); + Vector<Vector2> pts; + float tsize = 4.0; + pts.push_back(tip + Vector2(0, tsize)); + pts.push_back(tip + Vector2(Math_SQRT12 * tsize, 0)); + pts.push_back(tip + Vector2(-Math_SQRT12 * tsize, 0)); + Vector<Color> cols; + for (int i = 0; i < 3; i++) { + cols.push_back(p_color); + } + RS::get_singleton()->canvas_item_add_primitive(p_to_rid, pts, cols, Vector<Point2>(), RID()); +} + +Rect2 RayShape2D::get_rect() const { + Rect2 rect; + rect.position = Vector2(); + rect.expand_to(Vector2(0, length)); + rect = rect.grow(Math_SQRT12 * 4); + return rect; +} + +real_t RayShape2D::get_enclosing_radius() const { + return length; +} + +void RayShape2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape2D::set_length); + ClassDB::bind_method(D_METHOD("get_length"), &RayShape2D::get_length); + + ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape2D::set_slips_on_slope); + ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape2D::get_slips_on_slope); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope"); +} + +void RayShape2D::set_length(real_t p_length) { + length = p_length; + _update_shape(); +} + +real_t RayShape2D::get_length() const { + return length; +} + +void RayShape2D::set_slips_on_slope(bool p_active) { + slips_on_slope = p_active; + _update_shape(); +} + +bool RayShape2D::get_slips_on_slope() const { + return slips_on_slope; +} + +RayShape2D::RayShape2D() : + Shape2D(PhysicsServer2D::get_singleton()->ray_shape_create()) { + _update_shape(); +} diff --git a/scene/resources/ray_shape_2d.h b/scene/resources/ray_shape_2d.h new file mode 100644 index 0000000000..56ecfa2722 --- /dev/null +++ b/scene/resources/ray_shape_2d.h @@ -0,0 +1,61 @@ +/*************************************************************************/ +/* ray_shape_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RAY_SHAPE_2D_H +#define RAY_SHAPE_2D_H + +#include "scene/resources/shape_2d.h" + +class RayShape2D : public Shape2D { + GDCLASS(RayShape2D, Shape2D); + + real_t length = 20.0; + bool slips_on_slope = false; + + void _update_shape(); + +protected: + static void _bind_methods(); + +public: + void set_length(real_t p_length); + real_t get_length() const; + + void set_slips_on_slope(bool p_active); + bool get_slips_on_slope() const; + + virtual void draw(const RID &p_to_rid, const Color &p_color) override; + virtual Rect2 get_rect() const override; + virtual real_t get_enclosing_radius() const override; + + RayShape2D(); +}; + +#endif // RAY_SHAPE_2D_H diff --git a/scene/resources/ray_shape_3d.cpp b/scene/resources/ray_shape_3d.cpp index 17205a500a..5446b4daab 100644 --- a/scene/resources/ray_shape_3d.cpp +++ b/scene/resources/ray_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "servers/physics_server_3d.h" -Vector<Vector3> RayShape3D::get_debug_mesh_lines() { +Vector<Vector3> RayShape3D::get_debug_mesh_lines() const { Vector<Vector3> points; points.push_back(Vector3()); points.push_back(Vector3(0, 0, get_length())); @@ -56,7 +56,6 @@ void RayShape3D::set_length(float p_length) { length = p_length; _update_shape(); notify_change_to_owners(); - _change_notify("length"); } float RayShape3D::get_length() const { @@ -67,7 +66,6 @@ void RayShape3D::set_slips_on_slope(bool p_active) { slips_on_slope = p_active; _update_shape(); notify_change_to_owners(); - _change_notify("slips_on_slope"); } bool RayShape3D::get_slips_on_slope() const { @@ -81,18 +79,13 @@ void RayShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape3D::set_slips_on_slope); ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape3D::get_slips_on_slope); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0,4096,0.001"), "set_length", "get_length"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope"); } RayShape3D::RayShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_RAY)) { - length = 1.0; - slips_on_slope = false; - /* Code copied from setters to prevent the use of uninitialized variables */ _update_shape(); notify_change_to_owners(); - _change_notify("length"); - _change_notify("slips_on_slope"); } diff --git a/scene/resources/ray_shape_3d.h b/scene/resources/ray_shape_3d.h index ef849d2dee..2da6311321 100644 --- a/scene/resources/ray_shape_3d.h +++ b/scene/resources/ray_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,12 @@ class RayShape3D : public Shape3D { GDCLASS(RayShape3D, Shape3D); - float length; - bool slips_on_slope; + float length = 1.0; + bool slips_on_slope = false; protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: void set_length(float p_length); @@ -48,8 +48,8 @@ public: void set_slips_on_slope(bool p_active); bool get_slips_on_slope() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override; RayShape3D(); }; diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index 949fddf2e7..dc4c6dc2d7 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,40 +33,58 @@ #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" void RectangleShape2D::_update_shape() { - PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), extents); + PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), size * 0.5); emit_changed(); } -void RectangleShape2D::set_extents(const Vector2 &p_extents) { - extents = p_extents; +void RectangleShape2D::set_size(const Vector2 &p_size) { + size = p_size; _update_shape(); } -Vector2 RectangleShape2D::get_extents() const { - return extents; +Vector2 RectangleShape2D::get_size() const { + return size; } void RectangleShape2D::draw(const RID &p_to_rid, const Color &p_color) { - RenderingServer::get_singleton()->canvas_item_add_rect(p_to_rid, Rect2(-extents, extents * 2.0), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_to_rid, Rect2(-size * 0.5, size), p_color); + if (is_collision_outline_enabled()) { + // Draw an outlined rectangle to make individual shapes easier to distinguish. + Vector<Vector2> stroke_points; + stroke_points.resize(5); + stroke_points.write[0] = -size * 0.5; + stroke_points.write[1] = Vector2(size.x, -size.y) * 0.5; + stroke_points.write[2] = size * 0.5; + stroke_points.write[3] = Vector2(-size.x, size.y) * 0.5; + stroke_points.write[4] = -size * 0.5; + + Vector<Color> stroke_colors; + stroke_colors.resize(5); + for (int i = 0; i < 5; i++) { + stroke_colors.write[i] = (p_color); + } + + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, stroke_points, stroke_colors); + } } Rect2 RectangleShape2D::get_rect() const { - return Rect2(-extents, extents * 2.0); + return Rect2(-size * 0.5, size); } real_t RectangleShape2D::get_enclosing_radius() const { - return extents.length(); + return size.length() / 2; } void RectangleShape2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_extents", "extents"), &RectangleShape2D::set_extents); - ClassDB::bind_method(D_METHOD("get_extents"), &RectangleShape2D::get_extents); + ClassDB::bind_method(D_METHOD("set_size", "size"), &RectangleShape2D::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &RectangleShape2D::get_size); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "extents"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); } RectangleShape2D::RectangleShape2D() : Shape2D(PhysicsServer2D::get_singleton()->rectangle_shape_create()) { - extents = Vector2(10, 10); + size = Vector2(20, 20); _update_shape(); } diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h index 68fc539085..8d747c86af 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,19 +36,19 @@ class RectangleShape2D : public Shape2D { GDCLASS(RectangleShape2D, Shape2D); - Vector2 extents; + Vector2 size; void _update_shape(); protected: static void _bind_methods(); public: - void set_extents(const Vector2 &p_extents); - Vector2 get_extents() const; + void set_size(const Vector2 &p_size); + Vector2 get_size() const; - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - virtual real_t get_enclosing_radius() const; + virtual void draw(const RID &p_to_rid, const Color &p_color) override; + virtual Rect2 get_rect() const override; + virtual real_t get_enclosing_radius() const override; RectangleShape2D(); }; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 93db8b725f..7ca532e1d6 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,9 +30,9 @@ #include "resource_format_text.h" +#include "core/config/project_settings.h" #include "core/io/resource_format_binary.h" #include "core/os/dir_access.h" -#include "core/project_settings.h" #include "core/version.h" //version 2: changed names for basis, aabb, Vectors, etc. @@ -114,23 +114,8 @@ Error ResourceLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, R } int index = token.value; - - if (use_nocache) { - r_res = int_resources[index]; - } else { - String path = local_path + "::" + itos(index); - - if (!ignore_resource_parsing) { - if (!ResourceCache::has(path)) { - r_err_str = "Can't load cached sub-resource: " + path; - return ERR_PARSE_ERROR; - } - - r_res = RES(ResourceCache::get(path)); - } else { - r_res = RES(); - } - } + ERR_FAIL_COND_V(!int_resources.has(index), ERR_INVALID_PARAMETER); + r_res = int_resources[index]; VariantParser::get_token(p_stream, token, line, r_err_str); if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { @@ -440,7 +425,7 @@ Error ResourceLoaderText::load() { er.type = type; if (use_sub_threads) { - Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, local_path); + Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, ResourceFormatLoader::CACHE_MODE_REUSE, local_path); if (err != OK) { if (ResourceLoader::get_abort_on_missing_resources()) { @@ -517,29 +502,44 @@ Error ResourceLoaderText::load() { //bool exists=ResourceCache::has(path); Ref<Resource> res; + bool do_assign = false; - if (use_nocache || !ResourceCache::has(path)) { //only if it doesn't exist - - Object *obj = ClassDB::instance(type); - if (!obj) { - error_text += "Can't create sub resource of type: " + type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; + if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) { + //reuse existing + Resource *r = ResourceCache::get(path); + if (r && r->get_class() == type) { + res = Ref<Resource>(r); + res->reset_state(); + do_assign = true; } + } - Resource *r = Object::cast_to<Resource>(obj); - if (!r) { - error_text += "Can't create sub resource of type, because not a resource: " + type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } + if (res.is_null()) { //not reuse + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist + //cached, do not assign + Resource *r = ResourceCache::get(path); + res = Ref<Resource>(r); + } else { + //create + + Object *obj = ClassDB::instance(type); + if (!obj) { + error_text += "Can't create sub resource of type: " + type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Resource *r = Object::cast_to<Resource>(obj); + if (!r) { + error_text += "Can't create sub resource of type, because not a resource: " + type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } - res = Ref<Resource>(r); - int_resources[id] = res; - if (!use_nocache) { - res->set_path(path); + res = Ref<Resource>(r); + do_assign = true; } } @@ -557,7 +557,7 @@ Error ResourceLoaderText::load() { } if (assign != String()) { - if (res.is_valid()) { + if (do_assign) { res->set(assign, value); } //it's assignment @@ -572,7 +572,12 @@ Error ResourceLoaderText::load() { } } - if (progress) { + int_resources[id] = res; //always assign int resources + if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); + } + + if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } } @@ -589,23 +594,33 @@ Error ResourceLoaderText::load() { return error; } - Object *obj = ClassDB::instance(res_type); - if (!obj) { - error_text += "Can't create sub resource of type: " + res_type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; + if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) { + Resource *r = ResourceCache::get(local_path); + if (r->get_class() == res_type) { + r->reset_state(); + resource = Ref<Resource>(r); + } } - Resource *r = Object::cast_to<Resource>(obj); - if (!r) { - error_text += "Can't create sub resource of type, because not a resource: " + res_type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } + if (!resource.is_valid()) { + Object *obj = ClassDB::instance(res_type); + if (!obj) { + error_text += "Can't create sub resource of type: " + res_type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Resource *r = Object::cast_to<Resource>(obj); + if (!r) { + error_text += "Can't create sub resource of type, because not a resource: " + res_type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } - resource = Ref<Resource>(r); + resource = Ref<Resource>(r); + } resource_current++; @@ -620,7 +635,7 @@ Error ResourceLoaderText::load() { _printerr(); } else { error = OK; - if (!use_nocache) { + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { if (!ResourceCache::has(res_path)) { resource->set_path(res_path); } @@ -640,7 +655,7 @@ Error ResourceLoaderText::load() { return error; } else { error = OK; - if (progress) { + if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } @@ -668,13 +683,13 @@ Error ResourceLoaderText::load() { error = OK; //get it here resource = packed_scene; - if (!use_nocache && !ResourceCache::has(res_path)) { + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && !ResourceCache::has(res_path)) { packed_scene->set_path(res_path); } resource_current++; - if (progress) { + if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } @@ -699,19 +714,7 @@ void ResourceLoaderText::set_translation_remapped(bool p_remapped) { translation_remapped = p_remapped; } -ResourceLoaderText::ResourceLoaderText() { - use_nocache = false; - - resources_total = 0; - resource_current = 0; - use_sub_threads = false; - - progress = nullptr; - lines = false; - translation_remapped = false; - use_sub_threads = false; - error = OK; -} +ResourceLoaderText::ResourceLoaderText() {} ResourceLoaderText::~ResourceLoaderText() { memdelete(f); @@ -838,6 +841,11 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p f->seek(tag_end); uint8_t c = f->get_8(); + if (c == '\n' && !f->eof_reached()) { + // Skip first newline character since we added one + c = f->get_8(); + } + while (!f->eof_reached()) { fw->store_8(c); c = f->get_8(); @@ -1248,7 +1256,7 @@ String ResourceLoaderText::recognize(FileAccess *p_f) { ///////////////////// -RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_CANT_OPEN; } @@ -1261,7 +1269,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina ResourceLoaderText loader; String path = p_original_path != "" ? p_original_path : p_path; - loader.use_nocache = p_no_cache; + loader.cache_mode = p_cache_mode; loader.use_sub_threads = p_use_sub_threads; loader.local_path = ProjectSettings::get_singleton()->localize_path(path); loader.progress = r_progress; @@ -1763,6 +1771,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } for (int i = 0; i < state->get_connection_count(); i++) { + if (i == 0) { + f->store_line(""); + } + String connstr = "[connection"; connstr += " signal=\"" + String(state->get_connection_signal(i)) + "\""; connstr += " from=\"" + String(state->get_connection_source(i).simplified()) + "\""; @@ -1786,7 +1798,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r Vector<NodePath> editable_instances = state->get_editable_instances(); for (int i = 0; i < editable_instances.size(); i++) { - f->store_line("\n[editable path=\"" + editable_instances[i].operator String() + "\"]"); + if (i == 0) { + f->store_line(""); + } + f->store_line("[editable path=\"" + editable_instances[i].operator String() + "\"]"); } } diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index cf522c9364..2dc683415d 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,16 +34,16 @@ #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/os/file_access.h" -#include "core/variant_parser.h" +#include "core/variant/variant_parser.h" #include "scene/resources/packed_scene.h" class ResourceLoaderText { - bool translation_remapped; + bool translation_remapped = false; String local_path; String res_path; String error_text; - FileAccess *f; + FileAccess *f = nullptr; VariantParser::StreamFile stream; @@ -53,28 +53,28 @@ class ResourceLoaderText { String type; }; - bool is_scene; + bool is_scene = false; String res_type; - bool ignore_resource_parsing; + bool ignore_resource_parsing = false; //Map<String,String> remaps; Map<int, ExtResource> ext_resources; Map<int, RES> int_resources; - int resources_total; - int resource_current; + int resources_total = 0; + int resource_current = 0; String resource_type; VariantParser::Tag next_tag; - bool use_nocache; + ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE; - bool use_sub_threads; - float *progress; + bool use_sub_threads = false; + float *progress = nullptr; - mutable int lines; + mutable int lines = 0; Map<String, String> remaps; //void _printerr(); @@ -107,7 +107,7 @@ class ResourceLoaderText { friend class ResourceFormatLoaderText; - Error error; + Error error = OK; RES resource; @@ -134,7 +134,7 @@ public: class ResourceFormatLoaderText : public ResourceFormatLoader { public: static ResourceFormatLoaderText *singleton; - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; @@ -152,11 +152,11 @@ class ResourceFormatSaverTextInstance { Ref<PackedScene> packed_scene; - bool takeover_paths; - bool relative_paths; - bool bundle_resources; - bool skip_editor; - FileAccess *f; + bool takeover_paths = false; + bool relative_paths = false; + bool bundle_resources = false; + bool skip_editor = false; + FileAccess *f = nullptr; struct NonPersistentKey { //for resource properties generated on the fly RES base; @@ -173,7 +173,7 @@ class ResourceFormatSaverTextInstance { struct ResourceSort { RES resource; - int index; + int index = 0; bool operator<(const ResourceSort &p_right) const { return index < p_right.index; } diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp index 7b409eebbb..35439634f8 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,12 +30,13 @@ #include "segment_shape_2d.h" +#include "core/math/geometry_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" bool SegmentShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { Vector2 l[2] = { a, b }; - Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l); + Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, l); return p_point.distance_to(closest) < p_tolerance; } @@ -97,77 +98,3 @@ SegmentShape2D::SegmentShape2D() : b = Vector2(0, 10); _update_shape(); } - -//////////////////////////////////////////////////////////// - -void RayShape2D::_update_shape() { - Dictionary d; - d["length"] = length; - d["slips_on_slope"] = slips_on_slope; - PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), d); - emit_changed(); -} - -void RayShape2D::draw(const RID &p_to_rid, const Color &p_color) { - Vector2 tip = Vector2(0, get_length()); - RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), tip, p_color, 3); - Vector<Vector2> pts; - float tsize = 4; - pts.push_back(tip + Vector2(0, tsize)); - pts.push_back(tip + Vector2(Math_SQRT12 * tsize, 0)); - pts.push_back(tip + Vector2(-Math_SQRT12 * tsize, 0)); - Vector<Color> cols; - for (int i = 0; i < 3; i++) { - cols.push_back(p_color); - } - - RS::get_singleton()->canvas_item_add_primitive(p_to_rid, pts, cols, Vector<Point2>(), RID()); -} - -Rect2 RayShape2D::get_rect() const { - Rect2 rect; - rect.position = Vector2(); - rect.expand_to(Vector2(0, length)); - rect = rect.grow(Math_SQRT12 * 4); - return rect; -} - -real_t RayShape2D::get_enclosing_radius() const { - return length; -} - -void RayShape2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape2D::set_length); - ClassDB::bind_method(D_METHOD("get_length"), &RayShape2D::get_length); - - ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape2D::set_slips_on_slope); - ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape2D::get_slips_on_slope); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length"), "set_length", "get_length"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope"); -} - -void RayShape2D::set_length(real_t p_length) { - length = p_length; - _update_shape(); -} - -real_t RayShape2D::get_length() const { - return length; -} - -void RayShape2D::set_slips_on_slope(bool p_active) { - slips_on_slope = p_active; - _update_shape(); -} - -bool RayShape2D::get_slips_on_slope() const { - return slips_on_slope; -} - -RayShape2D::RayShape2D() : - Shape2D(PhysicsServer2D::get_singleton()->ray_shape_create()) { - length = 20; - slips_on_slope = false; - _update_shape(); -} diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h index ca10c24f07..f218955061 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +45,7 @@ protected: static void _bind_methods(); public: - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override; void set_a(const Vector2 &p_a); void set_b(const Vector2 &p_b); @@ -53,36 +53,11 @@ public: Vector2 get_a() const; Vector2 get_b() const; - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - virtual real_t get_enclosing_radius() const; + virtual void draw(const RID &p_to_rid, const Color &p_color) override; + virtual Rect2 get_rect() const override; + virtual real_t get_enclosing_radius() const override; SegmentShape2D(); }; -class RayShape2D : public Shape2D { - GDCLASS(RayShape2D, Shape2D); - - real_t length; - bool slips_on_slope; - - void _update_shape(); - -protected: - static void _bind_methods(); - -public: - void set_length(real_t p_length); - real_t get_length() const; - - void set_slips_on_slope(bool p_active); - bool get_slips_on_slope() const; - - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - virtual real_t get_enclosing_radius() const; - - RayShape2D(); -}; - #endif // SEGMENT_SHAPE_2D_H diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 4ca8032d65..77c6199794 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "shader.h" + #include "core/os/file_access.h" #include "scene/scene_string_names.h" #include "servers/rendering/shader_language.h" @@ -80,7 +81,7 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const { params_cache[pi.name] = E->get().name; if (p_params) { //small little hack - if (pi.type == Variant::_RID) { + if (pi.type == Variant::RID) { pi.type = Variant::OBJECT; } p_params->push_back(pi); @@ -125,7 +126,7 @@ bool Shader::is_text_shader() const { } bool Shader::has_param(const StringName &p_param) const { - return params_cache.has(p_param); + return params_cache.has("shader_param/" + p_param); } void Shader::_update_shader() const { @@ -142,8 +143,6 @@ void Shader::_bind_methods() { ClassDB::bind_method(D_METHOD("has_param", "name"), &Shader::has_param); - //ClassDB::bind_method(D_METHOD("get_param_list"),&Shader::get_fragment_code); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_code", "get_code"); BIND_ENUM_CONSTANT(MODE_SPATIAL); @@ -153,9 +152,7 @@ void Shader::_bind_methods() { } Shader::Shader() { - mode = MODE_SPATIAL; shader = RenderingServer::get_singleton()->shader_create(); - params_cache_dirty = true; } Shader::~Shader() { @@ -164,7 +161,7 @@ Shader::~Shader() { //////////// -RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; } diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 2cdc2ec93f..6563181ca2 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,9 +31,9 @@ #ifndef SHADER_H #define SHADER_H +#include "core/io/resource.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/resource.h" #include "scene/resources/texture.h" class Shader : public Resource { @@ -42,7 +42,6 @@ class Shader : public Resource { public: enum Mode { - MODE_SPATIAL, MODE_CANVAS_ITEM, MODE_PARTICLES, @@ -52,12 +51,12 @@ public: private: RID shader; - Mode mode; + Mode mode = MODE_SPATIAL; // hack the name of performance // shaders keep a list of ShaderMaterial -> RenderingServer name translations, to make // conversion fast and save memory. - mutable bool params_cache_dirty; + mutable bool params_cache_dirty = true; mutable Map<StringName, StringName> params_cache; //map a shader param to a material param.. Map<StringName, Ref<Texture2D>> default_textures; @@ -93,7 +92,7 @@ public: return StringName(); } - virtual RID get_rid() const; + virtual RID get_rid() const override; Shader(); ~Shader(); @@ -103,7 +102,7 @@ VARIANT_ENUM_CAST(Shader::Mode); class ResourceFormatLoaderShader : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index 99e8020e34..013b1ef1a9 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,11 @@ /*************************************************************************/ #include "shape_2d.h" + +#include "core/config/engine.h" +#include "core/config/project_settings.h" #include "servers/physics_server_2d.h" + RID Shape2D::get_rid() const { return shape; } @@ -100,13 +104,22 @@ void Shape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("collide_with_motion", "local_xform", "local_motion", "with_shape", "shape_xform", "shape_motion"), &Shape2D::collide_with_motion); ClassDB::bind_method(D_METHOD("collide_and_get_contacts", "local_xform", "with_shape", "shape_xform"), &Shape2D::collide_and_get_contacts); ClassDB::bind_method(D_METHOD("collide_with_motion_and_get_contacts", "local_xform", "local_motion", "with_shape", "shape_xform", "shape_motion"), &Shape2D::collide_with_motion_and_get_contacts); + ClassDB::bind_method(D_METHOD("draw", "canvas_item", "color"), &Shape2D::draw); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias"); } +bool Shape2D::is_collision_outline_enabled() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return true; + } +#endif + return GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true); +} + Shape2D::Shape2D(const RID &p_rid) { shape = p_rid; - custom_bias = 0; } Shape2D::~Shape2D() { diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index e2933ec031..14bdd60e4b 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 +31,14 @@ #ifndef SHAPE_2D_H #define SHAPE_2D_H -#include "core/resource.h" +#include "core/io/resource.h" class Shape2D : public Resource { GDCLASS(Shape2D, Resource); OBJ_SAVE_TYPE(Shape2D); RID shape; - real_t custom_bias; + real_t custom_bias = 0.0; protected: static void _bind_methods(); @@ -60,7 +60,10 @@ public: virtual Rect2 get_rect() const { return Rect2(); } /// Returns the radius of a circle that fully enclose this shape virtual real_t get_enclosing_radius() const = 0; - virtual RID get_rid() const; + virtual RID get_rid() const override; + + static bool is_collision_outline_enabled(); + Shape2D(); ~Shape2D(); }; diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp index 59766f4f1f..5761a405ce 100644 --- a/scene/resources/shape_3d.cpp +++ b/scene/resources/shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -66,7 +66,7 @@ Ref<ArrayMesh> Shape3D::get_debug_mesh() { debug_mesh_cache = Ref<ArrayMesh>(memnew(ArrayMesh)); - if (!lines.empty()) { + if (!lines.is_empty()) { //make mesh Vector<Vector3> array; array.resize(lines.size()); diff --git a/scene/resources/shape_3d.h b/scene/resources/shape_3d.h index a83b2ed009..0644940fd4 100644 --- a/scene/resources/shape_3d.h +++ b/scene/resources/shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef SHAPE_3D_H #define SHAPE_3D_H -#include "core/resource.h" +#include "core/io/resource.h" class ArrayMesh; @@ -53,10 +53,10 @@ protected: virtual void _update_shape(); public: - virtual RID get_rid() const { return shape; } + virtual RID get_rid() const override { return shape; } Ref<ArrayMesh> get_debug_mesh(); - virtual Vector<Vector3> get_debug_mesh_lines() = 0; // { return Vector<Vector3>(); } + virtual Vector<Vector3> get_debug_mesh_lines() const = 0; // { return Vector<Vector3>(); } /// Returns the radius of a sphere that fully enclose this shape virtual real_t get_enclosing_radius() const = 0; diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp index e88841a531..fee8fdbde2 100644 --- a/scene/resources/skin.cpp +++ b/scene/resources/skin.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 @@ void Skin::set_bind_name(int p_index, const StringName &p_name) { binds_ptr[p_index].name = p_name; emit_changed(); if (notify_change) { - _change_notify(); + notify_property_list_changed(); } } @@ -81,6 +81,10 @@ void Skin::clear_binds() { emit_changed(); } +void Skin::reset_state() { + clear_binds(); +} + bool Skin::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; if (name == "bind_count") { @@ -153,6 +157,4 @@ void Skin::_bind_methods() { } Skin::Skin() { - bind_count = 0; - binds_ptr = nullptr; } diff --git a/scene/resources/skin.h b/scene/resources/skin.h index 57aaf1afd4..f5d64f96aa 100644 --- a/scene/resources/skin.h +++ b/scene/resources/skin.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef SKIN_H #define SKIN_H -#include "core/resource.h" +#include "core/io/resource.h" class Skin : public Resource { GDCLASS(Skin, Resource) @@ -44,14 +44,15 @@ class Skin : public Resource { Vector<Bind> binds; - Bind *binds_ptr; - int bind_count; + Bind *binds_ptr = nullptr; + int bind_count = 0; protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; static void _bind_methods(); public: diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp index 54b6cde8bd..71424ba8ac 100644 --- a/scene/resources/sky.cpp +++ b/scene/resources/sky.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -83,8 +83,8 @@ void Sky::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &Sky::get_material); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,PanoramaSkyMaterial,ProceduralSkyMaterial,PhysicalSkyMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Automatic,HighQuality,HighQualityIncremental,RealTime"), "set_process_mode", "get_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "32,64,128,256,512,1024,2048"), "set_radiance_size", "get_radiance_size"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "HighQuality,RealTime"), "set_process_mode", "get_process_mode"); BIND_ENUM_CONSTANT(RADIANCE_SIZE_32); BIND_ENUM_CONSTANT(RADIANCE_SIZE_64); @@ -95,16 +95,16 @@ void Sky::_bind_methods() { BIND_ENUM_CONSTANT(RADIANCE_SIZE_2048); BIND_ENUM_CONSTANT(RADIANCE_SIZE_MAX); + BIND_ENUM_CONSTANT(PROCESS_MODE_AUTOMATIC); BIND_ENUM_CONSTANT(PROCESS_MODE_QUALITY); + BIND_ENUM_CONSTANT(PROCESS_MODE_INCREMENTAL); BIND_ENUM_CONSTANT(PROCESS_MODE_REALTIME); } Sky::Sky() { - mode = PROCESS_MODE_QUALITY; - radiance_size = RADIANCE_SIZE_256; sky = RS::get_singleton()->sky_create(); } Sky::~Sky() { RS::get_singleton()->free(sky); -}
\ No newline at end of file +} diff --git a/scene/resources/sky.h b/scene/resources/sky.h index 37f0a589f9..f0226d321d 100644 --- a/scene/resources/sky.h +++ b/scene/resources/sky.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 +51,16 @@ public: }; enum ProcessMode { + PROCESS_MODE_AUTOMATIC, PROCESS_MODE_QUALITY, + PROCESS_MODE_INCREMENTAL, PROCESS_MODE_REALTIME }; private: RID sky; - ProcessMode mode; - RadianceSize radiance_size; + ProcessMode mode = PROCESS_MODE_AUTOMATIC; + RadianceSize radiance_size = RADIANCE_SIZE_256; Ref<Material> sky_material; protected: @@ -74,7 +76,7 @@ public: void set_material(const Ref<Material> &p_material); Ref<Material> get_material() const; - virtual RID get_rid() const; + virtual RID get_rid() const override; Sky(); ~Sky(); diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 69e8e0b5bd..b2efecb1cb 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -522,53 +522,59 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { code += "}\n\n"; code += "void fragment() {\n"; - code += "\tfloat zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );\n"; - code += "\tfloat sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;\n"; - code += "\tfloat sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);\n\n"; - - code += "\t// rayleigh coefficients\n"; - code += "\tfloat rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );\n"; - code += "\tvec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;\n"; - code += "\t// mie coefficients from Preetham\n"; - code += "\tvec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;\n\n"; - - code += "\t// optical length\n"; - code += "\tfloat zenith = acos(max(0.0, dot(UP, EYEDIR)));\n"; - code += "\tfloat optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(zenith), -1.253));\n"; - code += "\tfloat rayleigh_scatter = rayleigh_zenith_size * optical_mass;\n"; - code += "\tfloat mie_scatter = mie_zenith_size * optical_mass;\n\n"; - - code += "\t// light extinction based on thickness of atmosphere\n"; - code += "\tvec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));\n\n"; - - code += "\t// in scattering\n"; - code += "\tfloat cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));\n\n"; - - code += "\tfloat rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));\n"; - code += "\tvec3 betaRTheta = rayleigh_beta * rayleigh_phase;\n\n"; - - code += "\tfloat mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);\n"; - code += "\tvec3 betaMTheta = mie_beta * mie_phase;\n\n"; - - code += "\tvec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));\n"; - code += "\t// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js\n"; - code += "\tLin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0));\n\n"; - - code += "\t// Hack in the ground color\n"; - code += "\tLin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));\n\n"; - - code += "\t// Solar disk and out-scattering\n"; - code += "\tfloat sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);\n"; - code += "\tfloat sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5);\n"; - code += "\tfloat sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);\n"; - code += "\tvec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR;\n"; - code += "\tL0 += texture(night_sky, SKY_COORDS).xyz * extinction;\n\n"; - - code += "\tvec3 color = (Lin + L0) * 0.04;\n"; - code += "\tCOLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));\n"; - code += "\tCOLOR *= exposure;\n"; - code += "\t// Make optional, eliminates banding\n"; - code += "\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.008 * dither_strength;\n"; + code += "\tif (LIGHT0_ENABLED) {\n"; + code += "\t\tfloat zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );\n"; + code += "\t\tfloat sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;\n"; + code += "\t\tfloat sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);\n\n"; + + code += "\t\t// rayleigh coefficients\n"; + code += "\t\tfloat rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );\n"; + code += "\t\tvec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;\n"; + code += "\t\t// mie coefficients from Preetham\n"; + code += "\t\tvec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;\n\n"; + + code += "\t\t// optical length\n"; + code += "\t\tfloat zenith = acos(max(0.0, dot(UP, EYEDIR)));\n"; + code += "\t\tfloat optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(zenith), -1.253));\n"; + code += "\t\tfloat rayleigh_scatter = rayleigh_zenith_size * optical_mass;\n"; + code += "\t\tfloat mie_scatter = mie_zenith_size * optical_mass;\n\n"; + + code += "\t\t// light extinction based on thickness of atmosphere\n"; + code += "\t\tvec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));\n\n"; + + code += "\t\t// in scattering\n"; + code += "\t\tfloat cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));\n\n"; + + code += "\t\tfloat rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));\n"; + code += "\t\tvec3 betaRTheta = rayleigh_beta * rayleigh_phase;\n\n"; + + code += "\t\tfloat mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);\n"; + code += "\t\tvec3 betaMTheta = mie_beta * mie_phase;\n\n"; + + code += "\t\tvec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));\n"; + code += "\t\t// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js\n"; + code += "\t\tLin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0));\n\n"; + + code += "\t\t// Hack in the ground color\n"; + code += "\t\tLin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));\n\n"; + + code += "\t\t// Solar disk and out-scattering\n"; + code += "\t\tfloat sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);\n"; + code += "\t\tfloat sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5);\n"; + code += "\t\tfloat sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);\n"; + code += "\t\tvec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR;\n"; + code += "\t\tL0 += texture(night_sky, SKY_COORDS).xyz * extinction;\n\n"; + + code += "\t\tvec3 color = (Lin + L0) * 0.04;\n"; + code += "\t\tCOLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));\n"; + code += "\t\tCOLOR *= exposure;\n"; + code += "\t\t// Make optional, eliminates banding\n"; + code += "\t\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;\n"; + code += "\t} else {\n"; + code += "\t\t// There is no sun, so display night_sky and nothing else\n"; + code += "\t\tCOLOR = texture(night_sky, SKY_COORDS).xyz * 0.04;\n"; + code += "\t\tCOLOR *= exposure;\n"; + code += "\t}\n"; code += "}\n"; shader = RS::get_singleton()->shader_create(); @@ -591,5 +597,4 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { PhysicalSkyMaterial::~PhysicalSkyMaterial() { RS::get_singleton()->free(shader); - RS::get_singleton()->material_set_shader(_get_material(), RID()); } diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index e470137d9e..8fe015519d 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "core/rid.h" +#include "core/templates/rid.h" #include "scene/resources/material.h" #ifndef SKY_MATERIAL_H @@ -55,7 +55,7 @@ private: protected: static void _bind_methods(); - virtual bool _can_do_next_pass() const; + virtual bool _can_do_next_pass() const override; public: void set_sky_top_color(const Color &p_sky_top); @@ -88,8 +88,8 @@ public: void set_sun_curve(float p_curve); float get_sun_curve() const; - virtual Shader::Mode get_shader_mode() const; - RID get_shader_rid() const; + virtual Shader::Mode get_shader_mode() const override; + virtual RID get_shader_rid() const override; ProceduralSkyMaterial(); ~ProceduralSkyMaterial(); @@ -107,14 +107,14 @@ private: protected: static void _bind_methods(); - virtual bool _can_do_next_pass() const; + virtual bool _can_do_next_pass() const override; public: void set_panorama(const Ref<Texture2D> &p_panorama); Ref<Texture2D> get_panorama() const; - virtual Shader::Mode get_shader_mode() const; - RID get_shader_rid() const; + virtual Shader::Mode get_shader_mode() const override; + virtual RID get_shader_rid() const override; PanoramaSkyMaterial(); ~PanoramaSkyMaterial(); @@ -143,7 +143,7 @@ private: protected: static void _bind_methods(); - virtual bool _can_do_next_pass() const; + virtual bool _can_do_next_pass() const override; public: void set_rayleigh_coefficient(float p_rayleigh); @@ -179,8 +179,8 @@ public: void set_night_sky(const Ref<Texture2D> &p_night_sky); Ref<Texture2D> get_night_sky() const; - virtual Shader::Mode get_shader_mode() const; - RID get_shader_rid() const; + virtual Shader::Mode get_shader_mode() const override; + virtual RID get_shader_rid() const override; PhysicalSkyMaterial(); ~PhysicalSkyMaterial(); diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp index d24998ff18..e4b4398063 100644 --- a/scene/resources/sphere_shape_3d.cpp +++ b/scene/resources/sphere_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #include "sphere_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> SphereShape3D::get_debug_mesh_lines() { +Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const { float r = get_radius(); Vector<Vector3> points; @@ -66,7 +66,6 @@ void SphereShape3D::set_radius(float p_radius) { radius = p_radius; _update_shape(); notify_change_to_owners(); - _change_notify("radius"); } float SphereShape3D::get_radius() const { @@ -77,7 +76,7 @@ void SphereShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereShape3D::set_radius); ClassDB::bind_method(D_METHOD("get_radius"), &SphereShape3D::get_radius); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0,4096,0.001"), "set_radius", "get_radius"); } SphereShape3D::SphereShape3D() : diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h index ee31bb615c..eddd2a2132 100644 --- a/scene/resources/sphere_shape_3d.h +++ b/scene/resources/sphere_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 +40,14 @@ class SphereShape3D : public Shape3D { protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: void set_radius(float p_radius); float get_radius() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override; SphereShape3D(); }; diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index eb65f10ec9..9b80224c3f 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,26 +38,26 @@ bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const { return true; } -void StyleBox::set_default_margin(Margin p_margin, float p_value) { - ERR_FAIL_INDEX((int)p_margin, 4); +void StyleBox::set_default_margin(Side p_side, float p_value) { + ERR_FAIL_INDEX((int)p_side, 4); - margin[p_margin] = p_value; + margin[p_side] = p_value; emit_changed(); } -float StyleBox::get_default_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); +float StyleBox::get_default_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_margin]; + return margin[p_side]; } -float StyleBox::get_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); +float StyleBox::get_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - if (margin[p_margin] < 0) { - return get_style_margin(p_margin); + if (margin[p_side] < 0) { + return get_style_margin(p_side); } else { - return margin[p_margin]; + return margin[p_side]; } } @@ -66,11 +66,11 @@ CanvasItem *StyleBox::get_current_item_drawn() const { } Size2 StyleBox::get_minimum_size() const { - return Size2(get_margin(MARGIN_LEFT) + get_margin(MARGIN_RIGHT), get_margin(MARGIN_TOP) + get_margin(MARGIN_BOTTOM)); + return Size2(get_margin(SIDE_LEFT) + get_margin(SIDE_RIGHT), get_margin(SIDE_TOP) + get_margin(SIDE_BOTTOM)); } Point2 StyleBox::get_offset() const { - return Point2(get_margin(MARGIN_LEFT), get_margin(MARGIN_TOP)); + return Point2(get_margin(SIDE_LEFT), get_margin(SIDE_TOP)); } Size2 StyleBox::get_center_size() const { @@ -99,10 +99,10 @@ void StyleBox::_bind_methods() { ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw); ADD_GROUP("Content Margin", "content_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_BOTTOM); } StyleBox::StyleBox() { @@ -123,53 +123,33 @@ void StyleBoxTexture::set_texture(Ref<Texture2D> p_texture) { } emit_signal("texture_changed"); emit_changed(); - _change_notify("texture"); } Ref<Texture2D> StyleBoxTexture::get_texture() const { return texture; } -void StyleBoxTexture::set_normal_map(Ref<Texture2D> p_normal_map) { - if (normal_map == p_normal_map) { - return; - } - normal_map = p_normal_map; - emit_changed(); -} +void StyleBoxTexture::set_margin_size(Side p_side, float p_size) { + ERR_FAIL_INDEX((int)p_side, 4); -Ref<Texture2D> StyleBoxTexture::get_normal_map() const { - return normal_map; -} - -void StyleBoxTexture::set_margin_size(Margin p_margin, float p_size) { - ERR_FAIL_INDEX((int)p_margin, 4); - - margin[p_margin] = p_size; + margin[p_side] = p_size; emit_changed(); - static const char *margin_prop[4] = { - "content_margin_left", - "content_margin_top", - "content_margin_right", - "content_margin_bottom", - }; - _change_notify(margin_prop[p_margin]); } -float StyleBoxTexture::get_margin_size(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); +float StyleBoxTexture::get_margin_size(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_margin]; + return margin[p_side]; } -float StyleBoxTexture::get_style_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); +float StyleBoxTexture::get_style_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_margin]; + return margin[p_side]; } Rect2 StyleBoxTexture::get_draw_rect(const Rect2 &p_rect) const { - return p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); + return p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]); } void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const { @@ -182,17 +162,12 @@ void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const { texture->get_rect_region(rect, src_rect, rect, src_rect); - rect.position.x -= expand_margin[MARGIN_LEFT]; - rect.position.y -= expand_margin[MARGIN_TOP]; - rect.size.x += expand_margin[MARGIN_LEFT] + expand_margin[MARGIN_RIGHT]; - rect.size.y += expand_margin[MARGIN_TOP] + expand_margin[MARGIN_BOTTOM]; - - RID normal_rid; - if (normal_map.is_valid()) { - normal_rid = normal_map->get_rid(); - } + rect.position.x -= expand_margin[SIDE_LEFT]; + rect.position.y -= expand_margin[SIDE_TOP]; + rect.size.x += expand_margin[SIDE_LEFT] + expand_margin[SIDE_RIGHT]; + rect.size.y += expand_margin[SIDE_TOP] + expand_margin[SIDE_BOTTOM]; - RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[MARGIN_LEFT], margin[MARGIN_TOP]), Vector2(margin[MARGIN_RIGHT], margin[MARGIN_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate, normal_rid); + RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[SIDE_LEFT], margin[SIDE_TOP]), Vector2(margin[SIDE_RIGHT], margin[SIDE_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate); } void StyleBoxTexture::set_draw_center(bool p_enabled) { @@ -212,17 +187,17 @@ Size2 StyleBoxTexture::get_center_size() const { return region_rect.size - get_minimum_size(); } -void StyleBoxTexture::set_expand_margin_size(Margin p_expand_margin, float p_size) { - ERR_FAIL_INDEX((int)p_expand_margin, 4); - expand_margin[p_expand_margin] = p_size; +void StyleBoxTexture::set_expand_margin_size(Side p_side, float p_size) { + ERR_FAIL_INDEX((int)p_side, 4); + expand_margin[p_side] = p_size; emit_changed(); } void StyleBoxTexture::set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { - expand_margin[MARGIN_LEFT] = p_left; - expand_margin[MARGIN_TOP] = p_top; - expand_margin[MARGIN_RIGHT] = p_right; - expand_margin[MARGIN_BOTTOM] = p_bottom; + expand_margin[SIDE_LEFT] = p_left; + expand_margin[SIDE_TOP] = p_top; + expand_margin[SIDE_RIGHT] = p_right; + expand_margin[SIDE_BOTTOM] = p_bottom; emit_changed(); } @@ -233,9 +208,9 @@ void StyleBoxTexture::set_expand_margin_size_all(float p_expand_margin_size) { emit_changed(); } -float StyleBoxTexture::get_expand_margin_size(Margin p_expand_margin) const { - ERR_FAIL_INDEX_V((int)p_expand_margin, 4, 0); - return expand_margin[p_expand_margin]; +float StyleBoxTexture::get_expand_margin_size(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + return expand_margin[p_side]; } void StyleBoxTexture::set_region_rect(const Rect2 &p_region_rect) { @@ -287,9 +262,6 @@ void StyleBoxTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &StyleBoxTexture::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture); - ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &StyleBoxTexture::set_normal_map); - ClassDB::bind_method(D_METHOD("get_normal_map"), &StyleBoxTexture::get_normal_map); - ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size); ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size); @@ -316,18 +288,17 @@ void StyleBoxTexture::_bind_methods() { ADD_SIGNAL(MethodInfo("texture_changed")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map"); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); ADD_GROUP("Margin", "margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_BOTTOM); ADD_GROUP("Expand Margin", "expand_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_BOTTOM); ADD_GROUP("Axis Stretch", "axis_stretch_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode"); @@ -340,20 +311,9 @@ void StyleBoxTexture::_bind_methods() { BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE_FIT); } -StyleBoxTexture::StyleBoxTexture() { - for (int i = 0; i < 4; i++) { - margin[i] = 0; - expand_margin[i] = 0; - } - draw_center = true; - modulate = Color(1, 1, 1, 1); - - axis_h = AXIS_STRETCH_MODE_STRETCH; - axis_v = AXIS_STRETCH_MODE_STRETCH; -} +StyleBoxTexture::StyleBoxTexture() {} -StyleBoxTexture::~StyleBoxTexture() { -} +StyleBoxTexture::~StyleBoxTexture() {} //////////////// @@ -387,15 +347,15 @@ int StyleBoxFlat::get_border_width_min() const { return MIN(MIN(border_width[0], border_width[1]), MIN(border_width[2], border_width[3])); } -void StyleBoxFlat::set_border_width(Margin p_margin, int p_width) { - ERR_FAIL_INDEX((int)p_margin, 4); - border_width[p_margin] = p_width; +void StyleBoxFlat::set_border_width(Side p_side, int p_width) { + ERR_FAIL_INDEX((int)p_side, 4); + border_width[p_side] = p_width; emit_changed(); } -int StyleBoxFlat::get_border_width(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0); - return border_width[p_margin]; +int StyleBoxFlat::get_border_width(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + return border_width[p_side]; } void StyleBoxFlat::set_border_blend(bool p_blend) { @@ -415,25 +375,15 @@ void StyleBoxFlat::set_corner_radius_all(int radius) { emit_changed(); } -void StyleBoxFlat::set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_botton_right, const int radius_bottom_left) { +void StyleBoxFlat::set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left) { corner_radius[0] = radius_top_left; corner_radius[1] = radius_top_right; - corner_radius[2] = radius_botton_right; + corner_radius[2] = radius_bottom_right; corner_radius[3] = radius_bottom_left; emit_changed(); } -int StyleBoxFlat::get_corner_radius_min() const { - int smallest = corner_radius[0]; - for (int i = 1; i < 4; i++) { - if (smallest > corner_radius[i]) { - smallest = corner_radius[i]; - } - } - return smallest; -} - void StyleBoxFlat::set_corner_radius(const Corner p_corner, const int radius) { ERR_FAIL_INDEX((int)p_corner, 4); corner_radius[p_corner] = radius; @@ -445,17 +395,17 @@ int StyleBoxFlat::get_corner_radius(const Corner p_corner) const { return corner_radius[p_corner]; } -void StyleBoxFlat::set_expand_margin_size(Margin p_expand_margin, float p_size) { - ERR_FAIL_INDEX((int)p_expand_margin, 4); - expand_margin[p_expand_margin] = p_size; +void StyleBoxFlat::set_expand_margin_size(Side p_side, float p_size) { + ERR_FAIL_INDEX((int)p_side, 4); + expand_margin[p_side] = p_size; emit_changed(); } void StyleBoxFlat::set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { - expand_margin[MARGIN_LEFT] = p_left; - expand_margin[MARGIN_TOP] = p_top; - expand_margin[MARGIN_RIGHT] = p_right; - expand_margin[MARGIN_BOTTOM] = p_bottom; + expand_margin[SIDE_LEFT] = p_left; + expand_margin[SIDE_TOP] = p_top; + expand_margin[SIDE_RIGHT] = p_right; + expand_margin[SIDE_BOTTOM] = p_bottom; emit_changed(); } @@ -466,9 +416,9 @@ void StyleBoxFlat::set_expand_margin_size_all(float p_expand_margin_size) { emit_changed(); } -float StyleBoxFlat::get_expand_margin_size(Margin p_expand_margin) const { - ERR_FAIL_INDEX_V((int)p_expand_margin, 4, 0.0); - return expand_margin[p_expand_margin]; +float StyleBoxFlat::get_expand_margin_size(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); + return expand_margin[p_side]; } void StyleBoxFlat::set_draw_center(bool p_enabled) { @@ -606,8 +556,8 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<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; - float y = radius * (float)sin((double)corner_index * Math_PI / 2.0 + (double)detail / (double)adapted_corner_detail * Math_PI / 2.0 + Math_PI) + corner_point.y; + real_t x = radius * (real_t)cos((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.x; + real_t y = radius * (real_t)sin((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.y; verts.push_back(Vector2(x, y)); colors.push_back(color); } @@ -663,7 +613,7 @@ inline void adapt_values(int p_index_a, int p_index_b, int *adapted_values, cons } Rect2 StyleBoxFlat::get_draw_rect(const Rect2 &p_rect) const { - Rect2 draw_rect = p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); + Rect2 draw_rect = p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]); if (shadow_size > 0) { Rect2 shadow_rect = draw_rect.grow(shadow_size); @@ -682,7 +632,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { return; } - Rect2 style_rect = p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); + Rect2 style_rect = p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]); if (Math::is_zero_approx(style_rect.size.width) || Math::is_zero_approx(style_rect.size.height)) { return; } @@ -701,23 +651,23 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { int width = MAX(style_rect.size.width, 0); int height = MAX(style_rect.size.height, 0); int adapted_border[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; - adapt_values(MARGIN_TOP, MARGIN_BOTTOM, adapted_border, border_width, height, height, height); - adapt_values(MARGIN_LEFT, MARGIN_RIGHT, adapted_border, border_width, width, width, width); + adapt_values(SIDE_TOP, SIDE_BOTTOM, adapted_border, border_width, height, height, height); + adapt_values(SIDE_LEFT, SIDE_RIGHT, adapted_border, border_width, width, width, width); //adapt corners (prevent weird overlapping/glitchy drawings) int adapted_corner[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; - adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[MARGIN_BOTTOM], height - adapted_border[MARGIN_TOP]); - adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[MARGIN_BOTTOM], height - adapted_border[MARGIN_TOP]); - adapt_values(CORNER_TOP_LEFT, CORNER_TOP_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[MARGIN_RIGHT], width - adapted_border[MARGIN_LEFT]); - adapt_values(CORNER_BOTTOM_LEFT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[MARGIN_RIGHT], width - adapted_border[MARGIN_LEFT]); + adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]); + adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]); + adapt_values(CORNER_TOP_LEFT, CORNER_TOP_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]); + adapt_values(CORNER_BOTTOM_LEFT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]); - Rect2 infill_rect = style_rect.grow_individual(-adapted_border[MARGIN_LEFT], -adapted_border[MARGIN_TOP], -adapted_border[MARGIN_RIGHT], -adapted_border[MARGIN_BOTTOM]); + Rect2 infill_rect = style_rect.grow_individual(-adapted_border[SIDE_LEFT], -adapted_border[SIDE_TOP], -adapted_border[SIDE_RIGHT], -adapted_border[SIDE_BOTTOM]); Rect2 border_style_rect = style_rect; if (aa_on) { 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); + border_style_rect = border_style_rect.grow_side((Side)i, -aa_size_grow); } } } @@ -778,8 +728,8 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { } } - Rect2 infill_inner_rect = infill_rect.grow_individual(-aa_border_width[MARGIN_LEFT], -aa_border_width[MARGIN_TOP], - -aa_border_width[MARGIN_RIGHT], -aa_border_width[MARGIN_BOTTOM]); + Rect2 infill_inner_rect = infill_rect.grow_individual(-aa_border_width[SIDE_LEFT], -aa_border_width[SIDE_TOP], + -aa_border_width[SIDE_RIGHT], -aa_border_width[SIDE_BOTTOM]); if (draw_center) { if (!blend_on && draw_border) { @@ -789,8 +739,8 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { } if (!blend_on || !draw_border) { - Rect2 infill_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]); + Rect2 infill_aa_rect = infill_rect.grow_individual(aa_fill_width[SIDE_LEFT], aa_fill_width[SIDE_TOP], + aa_fill_width[SIDE_RIGHT], aa_fill_width[SIDE_BOTTOM]); Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0); @@ -826,9 +776,9 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors, uvs); } -float StyleBoxFlat::get_style_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); - return border_width[p_margin]; +float StyleBoxFlat::get_style_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); + return border_width[p_side]; } void StyleBoxFlat::_bind_methods() { @@ -884,10 +834,10 @@ void StyleBoxFlat::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled"); ADD_GROUP("Border Width", "border_width_"); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_BOTTOM); ADD_GROUP("Border", "border_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color"); @@ -903,14 +853,14 @@ void StyleBoxFlat::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail"); ADD_GROUP("Expand Margin", "expand_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM); 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::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "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_"); @@ -918,38 +868,9 @@ void StyleBoxFlat::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "1,5,1"), "set_aa_size", "get_aa_size"); } -StyleBoxFlat::StyleBoxFlat() { - bg_color = Color(0.6, 0.6, 0.6); - shadow_color = Color(0, 0, 0, 0.6); - 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; - - border_width[0] = 0; - border_width[1] = 0; - border_width[2] = 0; - border_width[3] = 0; - - expand_margin[0] = 0; - expand_margin[1] = 0; - expand_margin[2] = 0; - expand_margin[3] = 0; - - corner_radius[0] = 0; - corner_radius[1] = 0; - corner_radius[2] = 0; - corner_radius[3] = 0; -} +StyleBoxFlat::StyleBoxFlat() {} -StyleBoxFlat::~StyleBoxFlat() { -} +StyleBoxFlat::~StyleBoxFlat() {} void StyleBoxLine::set_color(const Color &p_color) { color = p_color; @@ -1015,9 +936,18 @@ void StyleBoxLine::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); } -float StyleBoxLine::get_style_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, thickness); - return thickness; +float StyleBoxLine::get_style_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + + if (vertical) { + if (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) { + return thickness / 2.0; + } + } else if (p_side == SIDE_TOP || p_side == SIDE_BOTTOM) { + return thickness / 2.0; + } + + return 0; } Size2 StyleBoxLine::get_center_size() const { @@ -1041,12 +971,6 @@ void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const { vs->canvas_item_add_rect(p_canvas_item, r, color); } -StyleBoxLine::StyleBoxLine() { - grow_begin = 1.0; - grow_end = 1.0; - thickness = 1; - color = Color(0.0, 0.0, 0.0); - vertical = false; -} +StyleBoxLine::StyleBoxLine() {} StyleBoxLine::~StyleBoxLine() {} diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 99adbe589a..8a273afbfd 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,7 @@ #ifndef STYLE_BOX_H #define STYLE_BOX_H -#include "core/resource.h" +#include "core/io/resource.h" #include "scene/resources/texture.h" #include "servers/rendering_server.h" @@ -44,15 +44,15 @@ class StyleBox : public Resource { float margin[4]; protected: - virtual float get_style_margin(Margin p_margin) const = 0; + virtual float get_style_margin(Side p_side) const = 0; static void _bind_methods(); public: virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const; - void set_default_margin(Margin p_margin, float p_value); - float get_default_margin(Margin p_margin) const; - float get_margin(Margin p_margin) const; + void set_default_margin(Side p_side, float p_value); + float get_default_margin(Side p_side) const; + float get_margin(Side p_side) const; virtual Size2 get_center_size() const; virtual Rect2 get_draw_rect(const Rect2 &p_rect) const; @@ -68,10 +68,10 @@ public: class StyleBoxEmpty : public StyleBox { GDCLASS(StyleBoxEmpty, StyleBox); - virtual float get_style_margin(Margin p_margin) const { return 0; } + virtual float get_style_margin(Side p_side) const override { return 0; } public: - virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const {} + virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override {} StyleBoxEmpty() {} }; @@ -86,28 +86,27 @@ public: }; private: - float expand_margin[4]; - float margin[4]; + float expand_margin[4] = {}; + float margin[4] = {}; Rect2 region_rect; Ref<Texture2D> texture; - Ref<Texture2D> normal_map; - bool draw_center; - Color modulate; - AxisStretchMode axis_h; - AxisStretchMode axis_v; + bool draw_center = true; + Color modulate = Color(1, 1, 1, 1); + AxisStretchMode axis_h = AXIS_STRETCH_MODE_STRETCH; + AxisStretchMode axis_v = AXIS_STRETCH_MODE_STRETCH; protected: - virtual float get_style_margin(Margin p_margin) const; + virtual float get_style_margin(Side p_side) const override; static void _bind_methods(); public: - void set_expand_margin_size(Margin p_expand_margin, float p_size); + void set_expand_margin_size(Side p_expand_side, float p_size); void set_expand_margin_size_all(float p_expand_margin_size); void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); - float get_expand_margin_size(Margin p_expand_margin) const; + float get_expand_margin_size(Side p_expand_side) const; - void set_margin_size(Margin p_margin, float p_size); - float get_margin_size(Margin p_margin) const; + void set_margin_size(Side p_side, float p_size); + float get_margin_size(Side p_side) const; void set_region_rect(const Rect2 &p_region_rect); Rect2 get_region_rect() const; @@ -115,12 +114,9 @@ public: void set_texture(Ref<Texture2D> p_texture); Ref<Texture2D> get_texture() const; - void set_normal_map(Ref<Texture2D> p_normal_map); - Ref<Texture2D> get_normal_map() const; - void set_draw_center(bool p_enabled); bool is_draw_center_enabled() const; - virtual Size2 get_center_size() const; + virtual Size2 get_center_size() const override; void set_h_axis_stretch_mode(AxisStretchMode p_mode); AxisStretchMode get_h_axis_stretch_mode() const; @@ -131,8 +127,8 @@ public: void set_modulate(const Color &p_modulate); Color get_modulate() const; - virtual Rect2 get_draw_rect(const Rect2 &p_rect) const; - virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const; + virtual Rect2 get_draw_rect(const Rect2 &p_rect) const override; + virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override; StyleBoxTexture(); ~StyleBoxTexture(); @@ -143,25 +139,25 @@ VARIANT_ENUM_CAST(StyleBoxTexture::AxisStretchMode) class StyleBoxFlat : public StyleBox { GDCLASS(StyleBoxFlat, StyleBox); - Color bg_color; - Color shadow_color; - Color border_color; + Color bg_color = Color(0.6, 0.6, 0.6); + Color shadow_color = Color(0, 0, 0, 0.6); + Color border_color = Color(0.8, 0.8, 0.8); - int border_width[4]; - int expand_margin[4]; - int corner_radius[4]; + int border_width[4] = {}; + int expand_margin[4] = {}; + int corner_radius[4] = {}; - bool draw_center; - bool blend_border; - bool anti_aliased; + bool draw_center = true; + bool blend_border = false; + bool anti_aliased = true; - int corner_detail; - int shadow_size; + int corner_detail = 8; + int shadow_size = 0; Point2 shadow_offset; - int aa_size; + int aa_size = 1; protected: - virtual float get_style_margin(Margin p_margin) const; + virtual float get_style_margin(Side p_side) const override; static void _bind_methods(); public: @@ -178,8 +174,8 @@ public: void set_border_width_all(int p_size); int get_border_width_min() const; - void set_border_width(Margin p_margin, int p_width); - int get_border_width(Margin p_margin) const; + void set_border_width(Side p_side, int p_width); + int get_border_width(Side p_side) const; //blend void set_border_blend(bool p_blend); @@ -187,8 +183,7 @@ public: //CORNER void set_corner_radius_all(int radius); - void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_botton_right, const int radius_bottom_left); - int get_corner_radius_min() const; + void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left); void set_corner_radius(Corner p_corner, const int radius); int get_corner_radius(Corner p_corner) const; @@ -197,10 +192,10 @@ public: int get_corner_detail() const; //EXPANDS - void set_expand_margin_size(Margin p_expand_margin, float p_size); + void set_expand_margin_size(Side p_expand_side, float p_size); void set_expand_margin_size_all(float p_expand_margin_size); void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); - float get_expand_margin_size(Margin p_expand_margin) const; + float get_expand_margin_size(Side p_expand_side) const; //DRAW CENTER void set_draw_center(bool p_enabled); @@ -223,10 +218,10 @@ public: void set_aa_size(const int &p_aa_size); int get_aa_size() const; - virtual Size2 get_center_size() const; + virtual Size2 get_center_size() const override; - virtual Rect2 get_draw_rect(const Rect2 &p_rect) const; - virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const; + virtual Rect2 get_draw_rect(const Rect2 &p_rect) const override; + virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override; StyleBoxFlat(); ~StyleBoxFlat(); @@ -236,13 +231,13 @@ public: class StyleBoxLine : public StyleBox { GDCLASS(StyleBoxLine, StyleBox); Color color; - int thickness; - bool vertical; - float grow_begin; - float grow_end; + int thickness = 1; + bool vertical = false; + float grow_begin = 1.0; + float grow_end = 1.0; protected: - virtual float get_style_margin(Margin p_margin) const; + virtual float get_style_margin(Side p_side) const override; static void _bind_methods(); public: @@ -261,9 +256,9 @@ public: void set_grow_end(float p_grow); float get_grow_end() const; - virtual Size2 get_center_size() const; + virtual Size2 get_center_size() const override; - virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const; + virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override; StyleBoxLine(); ~StyleBoxLine(); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 1a2dcc84bb..47933bd69a 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 @@ #include "surface_tool.h" -#include "core/method_bind_ext.gen.inc" - #define _VERTEX_SNAP 0.0001 #define EQ_VERTEX_DIST 0.00001 +SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr; +SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr; +SurfaceTool::SimplifyScaleFunc SurfaceTool::simplify_scale_func = nullptr; +SurfaceTool::SimplifySloppyFunc SurfaceTool::simplify_sloppy_func = nullptr; + bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const { if (vertex != p_vertex.vertex) { return false; @@ -76,6 +79,16 @@ bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const { } } + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { + if (custom[i] != p_vertex.custom[i]) { + return false; + } + } + + if (smooth_group != p_vertex.smooth_group) { + return false; + } + return true; } @@ -89,6 +102,8 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) { h = hash_djb2_buffer((const uint8_t *)&p_vtx.color, sizeof(real_t) * 4, h); h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h); h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h); + h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h); + h = hash_djb2_one_32(p_vtx.smooth_group, h); return h; } @@ -113,8 +128,13 @@ 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; + vtx.smooth_group = last_smooth_group; + + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { + vtx.custom[i] = last_custom[i]; + } - const int expected_vertices = 4; + const int expected_vertices = skin_weights == SKIN_8_WEIGHTS ? 8 : 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 @@ -140,7 +160,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) { //cap weights.resize(expected_vertices); //renormalize - float total = 0; + float total = 0.0; for (int i = 0; i < expected_vertices; i++) { total += weights[i].weight; } @@ -165,7 +185,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) { format |= Mesh::ARRAY_FORMAT_VERTEX; } -void SurfaceTool::add_color(Color p_color) { +void SurfaceTool::set_color(Color p_color) { ERR_FAIL_COND(!begun); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_COLOR)); @@ -174,7 +194,7 @@ void SurfaceTool::add_color(Color p_color) { last_color = p_color; } -void SurfaceTool::add_normal(const Vector3 &p_normal) { +void SurfaceTool::set_normal(const Vector3 &p_normal) { ERR_FAIL_COND(!begun); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_NORMAL)); @@ -183,7 +203,7 @@ void SurfaceTool::add_normal(const Vector3 &p_normal) { last_normal = p_normal; } -void SurfaceTool::add_tangent(const Plane &p_tangent) { +void SurfaceTool::set_tangent(const Plane &p_tangent) { ERR_FAIL_COND(!begun); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TANGENT)); @@ -191,7 +211,7 @@ void SurfaceTool::add_tangent(const Plane &p_tangent) { last_tangent = p_tangent; } -void SurfaceTool::add_uv(const Vector2 &p_uv) { +void SurfaceTool::set_uv(const Vector2 &p_uv) { ERR_FAIL_COND(!begun); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TEX_UV)); @@ -199,7 +219,7 @@ void SurfaceTool::add_uv(const Vector2 &p_uv) { last_uv = p_uv; } -void SurfaceTool::add_uv2(const Vector2 &p_uv2) { +void SurfaceTool::set_uv2(const Vector2 &p_uv2) { ERR_FAIL_COND(!begun); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TEX_UV2)); @@ -207,29 +227,45 @@ void SurfaceTool::add_uv2(const Vector2 &p_uv2) { last_uv2 = p_uv2; } -void SurfaceTool::add_bones(const Vector<int> &p_bones) { +void SurfaceTool::set_custom(int p_index, const Color &p_custom) { + ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT); + ERR_FAIL_COND(!begun); + ERR_FAIL_COND(last_custom_format[p_index] == CUSTOM_MAX); + static const uint32_t mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 }; + static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT }; + ERR_FAIL_COND(!first && !(format & mask[p_index])); + + if (first) { + format |= mask[p_index]; + format |= last_custom_format[p_index] << shift[p_index]; + } + last_custom[p_index] = p_custom; +} + +void SurfaceTool::set_bones(const Vector<int> &p_bones) { ERR_FAIL_COND(!begun); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_BONES)); format |= Mesh::ARRAY_FORMAT_BONES; + if (skin_weights == SKIN_8_WEIGHTS) { + format |= Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS; + } last_bones = p_bones; } -void SurfaceTool::add_weights(const Vector<float> &p_weights) { +void SurfaceTool::set_weights(const Vector<float> &p_weights) { ERR_FAIL_COND(!begun); ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_WEIGHTS)); format |= Mesh::ARRAY_FORMAT_WEIGHTS; + if (skin_weights == SKIN_8_WEIGHTS) { + format |= Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS; + } last_weights = p_weights; } -void SurfaceTool::add_smooth_group(bool p_smooth) { - ERR_FAIL_COND(!begun); - if (index_array.size()) { - smooth_groups[index_array.size()] = p_smooth; - } else { - smooth_groups[vertex_array.size()] = p_smooth; - } +void SurfaceTool::set_smooth_group(uint32_t p_group) { + last_smooth_group = p_group; } 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) { @@ -240,15 +276,15 @@ void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vect #define ADD_POINT(n) \ { \ if (p_colors.size() > n) \ - add_color(p_colors[n]); \ + set_color(p_colors[n]); \ if (p_uvs.size() > n) \ - add_uv(p_uvs[n]); \ + set_uv(p_uvs[n]); \ if (p_uv2s.size() > n) \ - add_uv2(p_uv2s[n]); \ + set_uv2(p_uv2s[n]); \ if (p_normals.size() > n) \ - add_normal(p_normals[n]); \ + set_normal(p_normals[n]); \ if (p_tangents.size() > n) \ - add_tangent(p_tangents[n]); \ + set_tangent(p_tangents[n]); \ add_vertex(p_vertices[n]); \ } @@ -263,6 +299,7 @@ void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vect void SurfaceTool::add_index(int p_index) { ERR_FAIL_COND(!begun); + ERR_FAIL_COND(p_index < 0); format |= Mesh::ARRAY_FORMAT_INDEX; index_array.push_back(p_index); @@ -286,9 +323,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len); Vector3 *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; switch (i) { case Mesh::ARRAY_VERTEX: { @@ -310,9 +346,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len); Vector2 *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; switch (i) { case Mesh::ARRAY_TEX_UV: { @@ -331,9 +366,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 4); float *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; w[idx + 0] = v.tangent.x; w[idx + 1] = v.tangent.y; @@ -352,27 +386,165 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len); Color *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + w[idx] = v.color; } a[i] = array; } break; + case Mesh::ARRAY_CUSTOM0: + case Mesh::ARRAY_CUSTOM1: + case Mesh::ARRAY_CUSTOM2: + case Mesh::ARRAY_CUSTOM3: { + int fmt = i - Mesh::ARRAY_CUSTOM0; + switch (last_custom_format[fmt]) { + case CUSTOM_RGBA8_UNORM: { + Vector<uint8_t> array; + array.resize(varr_len * 4); + uint8_t *w = array.ptrw(); + + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + const Color &c = v.custom[idx]; + w[idx * 4 + 0] = CLAMP(int32_t(c.r * 255.0), 0, 255); + w[idx * 4 + 1] = CLAMP(int32_t(c.g * 255.0), 0, 255); + w[idx * 4 + 2] = CLAMP(int32_t(c.b * 255.0), 0, 255); + w[idx * 4 + 3] = CLAMP(int32_t(c.a * 255.0), 0, 255); + } + + a[i] = array; + } break; + case CUSTOM_RGBA8_SNORM: { + Vector<uint8_t> array; + array.resize(varr_len * 4); + uint8_t *w = array.ptrw(); + + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + const Color &c = v.custom[idx]; + w[idx * 4 + 0] = uint8_t(int8_t(CLAMP(int32_t(c.r * 127.0), -128, 127))); + w[idx * 4 + 1] = uint8_t(int8_t(CLAMP(int32_t(c.g * 127.0), -128, 127))); + w[idx * 4 + 2] = uint8_t(int8_t(CLAMP(int32_t(c.b * 127.0), -128, 127))); + w[idx * 4 + 3] = uint8_t(int8_t(CLAMP(int32_t(c.a * 127.0), -128, 127))); + } + + a[i] = array; + } break; + case CUSTOM_RG_HALF: { + Vector<uint8_t> array; + array.resize(varr_len * 4); + uint16_t *w = (uint16_t *)array.ptrw(); + + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + const Color &c = v.custom[idx]; + w[idx * 2 + 0] = Math::make_half_float(c.r); + w[idx * 2 + 1] = Math::make_half_float(c.g); + } + + a[i] = array; + } break; + case CUSTOM_RGBA_HALF: { + Vector<uint8_t> array; + array.resize(varr_len * 8); + uint16_t *w = (uint16_t *)array.ptrw(); + + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + const Color &c = v.custom[idx]; + w[idx * 4 + 0] = Math::make_half_float(c.r); + w[idx * 4 + 1] = Math::make_half_float(c.g); + w[idx * 4 + 2] = Math::make_half_float(c.b); + w[idx * 4 + 3] = Math::make_half_float(c.a); + } + + a[i] = array; + } break; + case CUSTOM_R_FLOAT: { + Vector<float> array; + array.resize(varr_len); + float *w = (float *)array.ptrw(); + + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + const Color &c = v.custom[idx]; + w[idx] = c.r; + } + + a[i] = array; + } break; + case CUSTOM_RG_FLOAT: { + Vector<float> array; + array.resize(varr_len * 2); + float *w = (float *)array.ptrw(); + + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + const Color &c = v.custom[idx]; + w[idx * 2 + 0] = c.r; + w[idx * 2 + 1] = c.g; + } + + a[i] = array; + } break; + case CUSTOM_RGB_FLOAT: { + Vector<float> array; + array.resize(varr_len * 3); + float *w = (float *)array.ptrw(); + + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + const Color &c = v.custom[idx]; + w[idx * 3 + 0] = c.r; + w[idx * 3 + 1] = c.g; + w[idx * 3 + 2] = c.b; + } + + a[i] = array; + } break; + case CUSTOM_RGBA_FLOAT: { + Vector<float> array; + array.resize(varr_len * 4); + float *w = (float *)array.ptrw(); + + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + const Color &c = v.custom[idx]; + w[idx * 4 + 0] = c.r; + w[idx * 4 + 1] = c.g; + w[idx * 4 + 2] = c.b; + w[idx * 4 + 3] = c.a; + } + + a[i] = array; + } break; + default: { + } //unreachable but compiler warning anyway + } + } break; case Mesh::ARRAY_BONES: { + int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4; Vector<int> array; - array.resize(varr_len * 4); + array.resize(varr_len * count); int *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; - ERR_CONTINUE(v.bones.size() != 4); + ERR_CONTINUE(v.bones.size() != count); - for (int j = 0; j < 4; j++) { - w[idx + j] = v.bones[j]; + for (int j = 0; j < count; j++) { + w[idx * count + j] = v.bones[j]; } } @@ -381,16 +553,18 @@ Array SurfaceTool::commit_to_arrays() { } break; case Mesh::ARRAY_WEIGHTS: { Vector<float> array; - array.resize(varr_len * 4); + int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4; + + array.resize(varr_len * count); float *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) { - const Vertex &v = E->get(); - ERR_CONTINUE(v.weights.size() != 4); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + + ERR_CONTINUE(v.weights.size() != count); - for (int j = 0; j < 4; j++) { - w[idx + j] = v.weights[j]; + for (int j = 0; j < count; j++) { + w[idx * count + j] = v.weights[j]; } } @@ -404,9 +578,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(index_array.size()); int *w = array.ptrw(); - int idx = 0; - for (List<int>::Element *E = index_array.front(); E; E = E->next(), idx++) { - w[idx] = E->get(); + for (uint32_t idx = 0; idx < index_array.size(); idx++) { + w[idx] = index_array[idx]; } a[i] = array; @@ -453,15 +626,16 @@ void SurfaceTool::index() { } HashMap<Vertex, int, VertexHasher> indices; - List<Vertex> new_vertices; + LocalVector<Vertex> old_vertex_array = vertex_array; + vertex_array.clear(); - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) { - int *idxptr = indices.getptr(E->get()); + for (uint32_t i = 0; i < old_vertex_array.size(); i++) { + int *idxptr = indices.getptr(old_vertex_array[i]); int idx; if (!idxptr) { idx = indices.size(); - new_vertices.push_back(E->get()); - indices[E->get()] = idx; + vertex_array.push_back(old_vertex_array[i]); + indices[old_vertex_array[i]] = idx; } else { idx = *idxptr; } @@ -469,9 +643,6 @@ void SurfaceTool::index() { index_array.push_back(idx); } - vertex_array.clear(); - vertex_array = new_vertices; - format |= Mesh::ARRAY_FORMAT_INDEX; } @@ -479,29 +650,26 @@ void SurfaceTool::deindex() { if (index_array.size() == 0) { return; //nothing to deindex } - Vector<Vertex> varr; - varr.resize(vertex_array.size()); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) { - varr.write[idx++] = E->get(); - } + + LocalVector<Vertex> old_vertex_array = vertex_array; vertex_array.clear(); - for (List<int>::Element *E = index_array.front(); E; E = E->next()) { - ERR_FAIL_INDEX(E->get(), varr.size()); - vertex_array.push_back(varr[E->get()]); + for (uint32_t i = 0; i < index_array.size(); i++) { + uint32_t index = index_array[i]; + ERR_FAIL_COND(index >= old_vertex_array.size()); + vertex_array.push_back(old_vertex_array[index]); } format &= ~Mesh::ARRAY_FORMAT_INDEX; index_array.clear(); } -void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) { +void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) { Array arr = p_existing->surface_get_arrays(p_surface); ERR_FAIL_COND(arr.size() != RS::ARRAY_MAX); _create_list_from_arrays(arr, r_vertex, r_index, lformat); } -Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays) { - Vector<SurfaceTool::Vertex> ret; +void SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector<SurfaceTool::Vertex> &ret, uint32_t *r_format) { + ret.clear(); Vector<Vector3> varr = p_arrays[RS::ARRAY_VERTEX]; Vector<Vector3> narr = p_arrays[RS::ARRAY_NORMAL]; @@ -511,10 +679,14 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array Vector<Vector2> uv2arr = p_arrays[RS::ARRAY_TEX_UV2]; Vector<int> barr = p_arrays[RS::ARRAY_BONES]; Vector<float> warr = p_arrays[RS::ARRAY_WEIGHTS]; + Vector<float> custom_float[RS::ARRAY_CUSTOM_COUNT]; int vc = varr.size(); if (vc == 0) { - return ret; + if (r_format) { + *r_format = 0; + } + return; } int lformat = 0; @@ -536,100 +708,40 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array if (uv2arr.size()) { lformat |= RS::ARRAY_FORMAT_TEX_UV2; } - if (barr.size()) { + int wcount = 0; + if (barr.size() && warr.size()) { lformat |= RS::ARRAY_FORMAT_BONES; - } - if (warr.size()) { lformat |= RS::ARRAY_FORMAT_WEIGHTS; - } - for (int i = 0; i < vc; i++) { - Vertex v; - if (lformat & RS::ARRAY_FORMAT_VERTEX) { - v.vertex = varr[i]; - } - if (lformat & RS::ARRAY_FORMAT_NORMAL) { - v.normal = narr[i]; - } - if (lformat & RS::ARRAY_FORMAT_TANGENT) { - Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]); - v.tangent = p.normal; - v.binormal = p.normal.cross(v.tangent).normalized() * p.d; + wcount = barr.size() / varr.size(); + if (wcount == 8) { + lformat |= RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS; } - if (lformat & RS::ARRAY_FORMAT_COLOR) { - v.color = carr[i]; - } - if (lformat & RS::ARRAY_FORMAT_TEX_UV) { - v.uv = uvarr[i]; - } - if (lformat & RS::ARRAY_FORMAT_TEX_UV2) { - v.uv2 = uv2arr[i]; - } - if (lformat & RS::ARRAY_FORMAT_BONES) { - Vector<int> b; - b.resize(4); - b.write[0] = barr[i * 4 + 0]; - b.write[1] = barr[i * 4 + 1]; - b.write[2] = barr[i * 4 + 2]; - b.write[3] = barr[i * 4 + 3]; - v.bones = b; - } - if (lformat & RS::ARRAY_FORMAT_WEIGHTS) { - Vector<float> w; - w.resize(4); - w.write[0] = warr[i * 4 + 0]; - w.write[1] = warr[i * 4 + 1]; - w.write[2] = warr[i * 4 + 2]; - w.write[3] = warr[i * 4 + 3]; - v.weights = w; - } - - ret.push_back(v); } - return ret; -} - -void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) { - Vector<Vector3> varr = arr[RS::ARRAY_VERTEX]; - Vector<Vector3> narr = arr[RS::ARRAY_NORMAL]; - Vector<float> tarr = arr[RS::ARRAY_TANGENT]; - Vector<Color> carr = arr[RS::ARRAY_COLOR]; - Vector<Vector2> uvarr = arr[RS::ARRAY_TEX_UV]; - Vector<Vector2> uv2arr = arr[RS::ARRAY_TEX_UV2]; - Vector<int> barr = arr[RS::ARRAY_BONES]; - Vector<float> warr = arr[RS::ARRAY_WEIGHTS]; - - int vc = varr.size(); - if (vc == 0) { - return; - } - - lformat = 0; - if (varr.size()) { - lformat |= RS::ARRAY_FORMAT_VERTEX; - } - if (narr.size()) { - lformat |= RS::ARRAY_FORMAT_NORMAL; - } - if (tarr.size()) { - lformat |= RS::ARRAY_FORMAT_TANGENT; - } - if (carr.size()) { - lformat |= RS::ARRAY_FORMAT_COLOR; - } - if (uvarr.size()) { - lformat |= RS::ARRAY_FORMAT_TEX_UV; - } - if (uv2arr.size()) { - lformat |= RS::ARRAY_FORMAT_TEX_UV2; - } - if (barr.size()) { - lformat |= RS::ARRAY_FORMAT_BONES; - } if (warr.size()) { lformat |= RS::ARRAY_FORMAT_WEIGHTS; } + static const uint32_t custom_mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 }; + static const uint32_t custom_shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT }; + + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { + ERR_CONTINUE_MSG(p_arrays[RS::ARRAY_CUSTOM0 + i].get_type() == Variant::PACKED_BYTE_ARRAY, "Extracting Byte/Half formats is not supported"); + if (p_arrays[RS::ARRAY_CUSTOM0 + i].get_type() == Variant::PACKED_FLOAT32_ARRAY) { + lformat |= custom_mask[i]; + custom_float[i] = p_arrays[RS::ARRAY_CUSTOM0 + i]; + int fmt = custom_float[i].size() / varr.size(); + if (fmt == 1) { + lformat |= CUSTOM_R_FLOAT << custom_shift[i]; + } else if (fmt == 2) { + lformat |= CUSTOM_RG_FLOAT << custom_shift[i]; + } else if (fmt == 3) { + lformat |= CUSTOM_RGB_FLOAT << custom_shift[i]; + } else if (fmt == 4) { + lformat |= CUSTOM_RGBA_FLOAT << custom_shift[i]; + } + } + } for (int i = 0; i < vc; i++) { Vertex v; @@ -655,27 +767,44 @@ void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, Li } if (lformat & RS::ARRAY_FORMAT_BONES) { Vector<int> b; - b.resize(4); - b.write[0] = barr[i * 4 + 0]; - b.write[1] = barr[i * 4 + 1]; - b.write[2] = barr[i * 4 + 2]; - b.write[3] = barr[i * 4 + 3]; + b.resize(wcount); + for (int j = 0; j < wcount; j++) { + b.write[j] = barr[i * wcount + j]; + } v.bones = b; } if (lformat & RS::ARRAY_FORMAT_WEIGHTS) { Vector<float> w; - w.resize(4); - w.write[0] = warr[i * 4 + 0]; - w.write[1] = warr[i * 4 + 1]; - w.write[2] = warr[i * 4 + 2]; - w.write[3] = warr[i * 4 + 3]; + w.resize(wcount); + for (int j = 0; j < wcount; j++) { + w.write[j] = warr[i * wcount + j]; + } v.weights = w; } - r_vertex->push_back(v); + for (int j = 0; j < RS::ARRAY_CUSTOM_COUNT; j++) { + if (lformat & custom_mask[j]) { + int cc = custom_float[j].size() / varr.size(); + for (int k = 0; k < cc; k++) { + v.custom[j][k] = custom_float[j][i * cc + k]; + } + } + } + + ret.push_back(v); + } + + if (r_format) { + *r_format = lformat; } +} + +void SurfaceTool::_create_list_from_arrays(Array arr, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) { + create_vertex_array_from_triangle_arrays(arr, *r_vertex, &lformat); + ERR_FAIL_COND(r_vertex->size() == 0); //indices + r_index->clear(); Vector<int> idx = arr[RS::ARRAY_INDEX]; int is = idx.size(); @@ -727,15 +856,15 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const format = 0; } - int nformat; - List<Vertex> nvertices; - List<int> nindices; + uint32_t nformat; + LocalVector<Vertex> nvertices; + LocalVector<int> nindices; _create_list(p_existing, p_surface, &nvertices, &nindices, nformat); format |= nformat; int vfrom = vertex_array.size(); - for (List<Vertex>::Element *E = nvertices.front(); E; E = E->next()) { - Vertex v = E->get(); + for (uint32_t vi = 0; vi < nvertices.size(); vi++) { + Vertex v = nvertices[vi]; v.vertex = p_xform.xform(v.vertex); if (nformat & RS::ARRAY_FORMAT_NORMAL) { v.normal = p_xform.basis.xform(v.normal); @@ -748,8 +877,8 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const vertex_array.push_back(v); } - for (List<int>::Element *E = nindices.front(); E; E = E->next()) { - int dst_index = E->get() + vfrom; + for (uint32_t i = 0; i < nindices.size(); i++) { + int dst_index = nindices[i] + vfrom; index_array.push_back(dst_index); } if (index_array.size() % 3) { @@ -760,18 +889,18 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const //mikktspace callbacks namespace { struct TangentGenerationContextUserData { - Vector<List<SurfaceTool::Vertex>::Element *> vertices; - Vector<List<int>::Element *> indices; + LocalVector<SurfaceTool::Vertex> *vertices; + LocalVector<int> *indices; }; } // namespace int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext *pContext) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); - if (triangle_data.indices.size() > 0) { - return triangle_data.indices.size() / 3; + if (triangle_data.indices->size() > 0) { + return triangle_data.indices->size() / 3; } else { - return triangle_data.vertices.size() / 3; + return triangle_data.vertices->size() / 3; } } @@ -782,13 +911,13 @@ int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, c void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); Vector3 v; - if (triangle_data.indices.size() > 0) { - int index = triangle_data.indices[iFace * 3 + iVert]->get(); - if (index < triangle_data.vertices.size()) { - v = triangle_data.vertices[index]->get().vertex; + if (triangle_data.indices->size() > 0) { + uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert); + if (index < triangle_data.vertices->size()) { + v = triangle_data.vertices->operator[](index).vertex; } } else { - v = triangle_data.vertices[iFace * 3 + iVert]->get().vertex; + v = triangle_data.vertices->operator[](iFace * 3 + iVert).vertex; } fvPosOut[0] = v.x; @@ -799,13 +928,13 @@ void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvP void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); Vector3 v; - if (triangle_data.indices.size() > 0) { - int index = triangle_data.indices[iFace * 3 + iVert]->get(); - if (index < triangle_data.vertices.size()) { - v = triangle_data.vertices[index]->get().normal; + if (triangle_data.indices->size() > 0) { + uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert); + if (index < triangle_data.vertices->size()) { + v = triangle_data.vertices->operator[](index).normal; } } else { - v = triangle_data.vertices[iFace * 3 + iVert]->get().normal; + v = triangle_data.vertices->operator[](iFace * 3 + iVert).normal; } fvNormOut[0] = v.x; @@ -816,13 +945,13 @@ void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNor void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); Vector2 v; - if (triangle_data.indices.size() > 0) { - int index = triangle_data.indices[iFace * 3 + iVert]->get(); - if (index < triangle_data.vertices.size()) { - v = triangle_data.vertices[index]->get().uv; + if (triangle_data.indices->size() > 0) { + uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert); + if (index < triangle_data.vertices->size()) { + v = triangle_data.vertices->operator[](index).uv; } } else { - v = triangle_data.vertices[iFace * 3 + iVert]->get().uv; + v = triangle_data.vertices->operator[](iFace * 3 + iVert).uv; } fvTexcOut[0] = v.x; @@ -833,13 +962,13 @@ void SurfaceTool::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, cons const tbool bIsOrientationPreserving, const int iFace, const int iVert) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); Vertex *vtx = nullptr; - if (triangle_data.indices.size() > 0) { - int index = triangle_data.indices[iFace * 3 + iVert]->get(); - if (index < triangle_data.vertices.size()) { - vtx = &triangle_data.vertices[index]->get(); + if (triangle_data.indices->size() > 0) { + uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert); + if (index < triangle_data.vertices->size()) { + vtx = &triangle_data.vertices->operator[](index); } } else { - vtx = &triangle_data.vertices[iFace * 3 + iVert]->get(); + vtx = &triangle_data.vertices->operator[](iFace * 3 + iVert); } if (vtx != nullptr) { @@ -865,18 +994,12 @@ void SurfaceTool::generate_tangents() { msc.m_pInterface = &mkif; TangentGenerationContextUserData triangle_data; - triangle_data.vertices.resize(vertex_array.size()); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) { - triangle_data.vertices.write[idx++] = E; - E->get().binormal = Vector3(); - E->get().tangent = Vector3(); - } - triangle_data.indices.resize(index_array.size()); - idx = 0; - for (List<int>::Element *E = index_array.front(); E; E = E->next()) { - triangle_data.indices.write[idx++] = E; + triangle_data.vertices = &vertex_array; + for (uint32_t i = 0; i < vertex_array.size(); i++) { + vertex_array[i].binormal = Vector3(); + vertex_array[i].tangent = Vector3(); } + triangle_data.indices = &index_array; msc.m_pUserData = &triangle_data; bool res = genTangSpaceDefault(&msc); @@ -892,66 +1015,36 @@ void SurfaceTool::generate_normals(bool p_flip) { deindex(); - HashMap<Vertex, Vector3, VertexHasher> vertex_hash; + ERR_FAIL_COND((vertex_array.size() % 3) != 0); - int count = 0; - bool smooth = false; - if (smooth_groups.has(0)) { - smooth = smooth_groups[0]; - } + HashMap<Vertex, Vector3, VertexHasher> vertex_hash; - List<Vertex>::Element *B = vertex_array.front(); - for (List<Vertex>::Element *E = B; E;) { - List<Vertex>::Element *v[3]; - v[0] = E; - v[1] = v[0]->next(); - ERR_FAIL_COND(!v[1]); - v[2] = v[1]->next(); - ERR_FAIL_COND(!v[2]); - E = v[2]->next(); + for (uint32_t vi = 0; vi < vertex_array.size(); vi += 3) { + Vertex *v = &vertex_array[vi]; Vector3 normal; if (!p_flip) { - normal = Plane(v[0]->get().vertex, v[1]->get().vertex, v[2]->get().vertex).normal; + normal = Plane(v[0].vertex, v[1].vertex, v[2].vertex).normal; } else { - normal = Plane(v[2]->get().vertex, v[1]->get().vertex, v[0]->get().vertex).normal; + normal = Plane(v[2].vertex, v[1].vertex, v[0].vertex).normal; } - if (smooth) { - for (int i = 0; i < 3; i++) { - Vector3 *lv = vertex_hash.getptr(v[i]->get()); - if (!lv) { - vertex_hash.set(v[i]->get(), normal); - } else { - (*lv) += normal; - } - } - } else { - for (int i = 0; i < 3; i++) { - v[i]->get().normal = normal; - } - } - count += 3; - - if (smooth_groups.has(count) || !E) { - if (vertex_hash.size()) { - while (B != E) { - Vector3 *lv = vertex_hash.getptr(B->get()); - if (lv) { - B->get().normal = lv->normalized(); - } - - B = B->next(); - } - + for (int i = 0; i < 3; i++) { + Vector3 *lv = vertex_hash.getptr(v[i]); + if (!lv) { + vertex_hash.set(v[i], normal); } else { - B = E; + (*lv) += normal; } + } + } - vertex_hash.clear(); - if (E) { - smooth = smooth_groups[count]; - } + for (uint32_t vi = 0; vi < vertex_array.size(); vi++) { + Vector3 *lv = vertex_hash.getptr(vertex_array[vi]); + if (!lv) { + vertex_array[vi].normal = Vector3(); + } else { + vertex_array[vi].normal = lv->normalized(); } } @@ -959,7 +1052,6 @@ void SurfaceTool::generate_normals(bool p_flip) { if (was_indexed) { index(); - smooth_groups.clear(); } } @@ -975,22 +1067,97 @@ void SurfaceTool::clear() { last_weights.clear(); index_array.clear(); vertex_array.clear(); - smooth_groups.clear(); material.unref(); + last_smooth_group = 0; + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { + last_custom_format[i] = CUSTOM_MAX; + } + skin_weights = SKIN_4_WEIGHTS; +} + +void SurfaceTool::set_skin_weight_count(SkinWeightCount p_weights) { + ERR_FAIL_COND(begun); + skin_weights = p_weights; +} +SurfaceTool::SkinWeightCount SurfaceTool::get_skin_weight_count() const { + return skin_weights; +} + +void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) { + ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT); + ERR_FAIL_COND(begun); + last_custom_format[p_index] = p_format; +} +SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const { + ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX); + return last_custom_format[p_index]; +} +void SurfaceTool::optimize_indices_for_cache() { + ERR_FAIL_COND(optimize_vertex_cache_func == nullptr); + ERR_FAIL_COND(index_array.size() == 0); + + LocalVector old_index_array = index_array; + zeromem(index_array.ptr(), index_array.size() * sizeof(int)); + optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size()); +} + +float SurfaceTool::get_max_axis_length() const { + ERR_FAIL_COND_V(vertex_array.size() == 0, 0); + + AABB aabb; + for (uint32_t i = 0; i < vertex_array.size(); i++) { + if (i == 0) { + aabb.position = vertex_array[i].vertex; + } else { + aabb.expand_to(vertex_array[i].vertex); + } + } + + return aabb.get_longest_axis_size(); +} +Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_count) { + Vector<int> lod; + + ERR_FAIL_COND_V(simplify_func == nullptr, lod); + ERR_FAIL_COND_V(vertex_array.size() == 0, lod); + ERR_FAIL_COND_V(index_array.size() == 0, lod); + + lod.resize(index_array.size()); + LocalVector<float> vertices; //uses floats + vertices.resize(vertex_array.size() * 3); + for (uint32_t i = 0; i < vertex_array.size(); i++) { + vertices[i * 3 + 0] = vertex_array[i].vertex.x; + vertices[i * 3 + 1] = vertex_array[i].vertex.y; + vertices[i * 3 + 2] = vertex_array[i].vertex.z; + } + + float error; + uint32_t index_count = simplify_func((unsigned int *)lod.ptrw(), (unsigned int *)index_array.ptr(), index_array.size(), vertices.ptr(), vertex_array.size(), sizeof(float) * 3, p_target_index_count, p_threshold, &error); + ERR_FAIL_COND_V(index_count == 0, lod); + lod.resize(index_count); + + return lod; } void SurfaceTool::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count); + ClassDB::bind_method(D_METHOD("get_skin_weight_count"), &SurfaceTool::get_skin_weight_count); + + ClassDB::bind_method(D_METHOD("set_custom_format", "index", "format"), &SurfaceTool::set_custom_format); + ClassDB::bind_method(D_METHOD("get_custom_format", "index"), &SurfaceTool::get_custom_format); + ClassDB::bind_method(D_METHOD("begin", "primitive"), &SurfaceTool::begin); ClassDB::bind_method(D_METHOD("add_vertex", "vertex"), &SurfaceTool::add_vertex); - ClassDB::bind_method(D_METHOD("add_color", "color"), &SurfaceTool::add_color); - ClassDB::bind_method(D_METHOD("add_normal", "normal"), &SurfaceTool::add_normal); - ClassDB::bind_method(D_METHOD("add_tangent", "tangent"), &SurfaceTool::add_tangent); - ClassDB::bind_method(D_METHOD("add_uv", "uv"), &SurfaceTool::add_uv); - ClassDB::bind_method(D_METHOD("add_uv2", "uv2"), &SurfaceTool::add_uv2); - ClassDB::bind_method(D_METHOD("add_bones", "bones"), &SurfaceTool::add_bones); - 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("set_color", "color"), &SurfaceTool::set_color); + ClassDB::bind_method(D_METHOD("set_normal", "normal"), &SurfaceTool::set_normal); + ClassDB::bind_method(D_METHOD("set_tangent", "tangent"), &SurfaceTool::set_tangent); + ClassDB::bind_method(D_METHOD("set_uv", "uv"), &SurfaceTool::set_uv); + ClassDB::bind_method(D_METHOD("set_uv2", "uv2"), &SurfaceTool::set_uv2); + ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones); + ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights); + ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom); + ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group); 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>())); @@ -1001,6 +1168,11 @@ 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("optimize_indices_for_cache"), &SurfaceTool::optimize_indices_for_cache); + + ClassDB::bind_method(D_METHOD("get_max_axis_length"), &SurfaceTool::get_max_axis_length); + ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3)); + ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material); ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear); @@ -1008,13 +1180,24 @@ void SurfaceTool::_bind_methods() { 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", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(0)); ClassDB::bind_method(D_METHOD("commit_to_arrays"), &SurfaceTool::commit_to_arrays); + + BIND_ENUM_CONSTANT(CUSTOM_RGBA8_UNORM); + BIND_ENUM_CONSTANT(CUSTOM_RGBA8_SNORM); + BIND_ENUM_CONSTANT(CUSTOM_RG_HALF); + BIND_ENUM_CONSTANT(CUSTOM_RGBA_HALF); + BIND_ENUM_CONSTANT(CUSTOM_R_FLOAT); + BIND_ENUM_CONSTANT(CUSTOM_RG_FLOAT); + BIND_ENUM_CONSTANT(CUSTOM_RGB_FLOAT); + BIND_ENUM_CONSTANT(CUSTOM_RGBA_FLOAT); + BIND_ENUM_CONSTANT(CUSTOM_MAX); + BIND_ENUM_CONSTANT(SKIN_4_WEIGHTS); + BIND_ENUM_CONSTANT(SKIN_8_WEIGHTS); } SurfaceTool::SurfaceTool() { - first = false; - begun = false; - primitive = Mesh::PRIMITIVE_LINES; - format = 0; + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { + last_custom_format[i] = CUSTOM_MAX; + } } diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index d7b255e695..17efdcba71 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,8 +31,8 @@ #ifndef SURFACE_TOOL_H #define SURFACE_TOOL_H +#include "core/templates/local_vector.h" #include "scene/resources/mesh.h" - #include "thirdparty/misc/mikktspace.h" class SurfaceTool : public Reference { @@ -49,34 +49,61 @@ public: Vector2 uv2; Vector<int> bones; Vector<float> weights; + Color custom[RS::ARRAY_CUSTOM_COUNT]; + uint32_t smooth_group = 0; bool operator==(const Vertex &p_vertex) const; Vertex() {} }; + enum CustomFormat { + CUSTOM_RGBA8_UNORM = RS::ARRAY_CUSTOM_RGBA8_UNORM, + CUSTOM_RGBA8_SNORM = RS::ARRAY_CUSTOM_RGBA8_SNORM, + CUSTOM_RG_HALF = RS::ARRAY_CUSTOM_RG_HALF, + CUSTOM_RGBA_HALF = RS::ARRAY_CUSTOM_RGBA_HALF, + CUSTOM_R_FLOAT = RS::ARRAY_CUSTOM_R_FLOAT, + CUSTOM_RG_FLOAT = RS::ARRAY_CUSTOM_RG_FLOAT, + CUSTOM_RGB_FLOAT = RS::ARRAY_CUSTOM_RGB_FLOAT, + CUSTOM_RGBA_FLOAT = RS::ARRAY_CUSTOM_RGBA_FLOAT, + CUSTOM_MAX = RS::ARRAY_CUSTOM_MAX + }; + + enum SkinWeightCount { + SKIN_4_WEIGHTS, + SKIN_8_WEIGHTS + }; + + typedef void (*OptimizeVertexCacheFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count); + static OptimizeVertexCacheFunc optimize_vertex_cache_func; + typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *r_error); + static SimplifyFunc simplify_func; + typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride); + static SimplifyScaleFunc simplify_scale_func; + typedef size_t (*SimplifySloppyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *out_result_error); + static SimplifySloppyFunc simplify_sloppy_func; + private: struct VertexHasher { static _FORCE_INLINE_ uint32_t hash(const Vertex &p_vtx); }; struct WeightSort { - int index; - float weight; + int index = 0; + float weight = 0.0; bool operator<(const WeightSort &p_right) const { return weight < p_right.weight; } }; - bool begun; - bool first; - Mesh::PrimitiveType primitive; - int format; + bool begun = false; + bool first = false; + Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_LINES; + uint32_t format = 0; Ref<Material> material; //arrays - List<Vertex> vertex_array; - List<int> index_array; - Map<int, bool> smooth_groups; + LocalVector<Vertex> vertex_array; + LocalVector<int> index_array; //memory Color last_color; @@ -86,9 +113,16 @@ private: Vector<int> last_bones; Vector<float> last_weights; Plane last_tangent; + uint32_t last_smooth_group = 0; + + SkinWeightCount skin_weights = SKIN_4_WEIGHTS; - void _create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat); - void _create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat); + Color last_custom[RS::ARRAY_CUSTOM_COUNT]; + + CustomFormat last_custom_format[RS::ARRAY_CUSTOM_COUNT]; + + void _create_list_from_arrays(Array arr, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat); + void _create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat); //mikktspace callbacks static int mikktGetNumFaces(const SMikkTSpaceContext *pContext); @@ -103,17 +137,25 @@ protected: static void _bind_methods(); public: + void set_skin_weight_count(SkinWeightCount p_weights); + SkinWeightCount get_skin_weight_count() const; + + void set_custom_format(int p_index, CustomFormat p_format); + CustomFormat get_custom_format(int p_index) const; + void begin(Mesh::PrimitiveType p_primitive); + void set_color(Color p_color); + void set_normal(const Vector3 &p_normal); + void set_tangent(const Plane &p_tangent); + void set_uv(const Vector2 &p_uv); + void set_uv2(const Vector2 &p_uv2); + void set_custom(int p_index, const Color &p_custom); + void set_bones(const Vector<int> &p_bones); + void set_weights(const Vector<float> &p_weights); + void set_smooth_group(uint32_t p_group); + void add_vertex(const Vector3 &p_vertex); - void add_color(Color p_color); - void add_normal(const Vector3 &p_normal); - void add_tangent(const Plane &p_tangent); - void add_uv(const Vector2 &p_uv); - void add_uv2(const Vector2 &p_uv2); - void add_bones(const Vector<int> &p_bones); - void add_weights(const Vector<float> &p_weights); - void add_smooth_group(bool p_smooth); 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>()); @@ -124,21 +166,28 @@ public: void generate_normals(bool p_flip = false); void generate_tangents(); + void optimize_indices_for_cache(); + float get_max_axis_length() const; + Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3); + void set_material(const Ref<Material> &p_material); void clear(); - List<Vertex> &get_vertex_array() { return vertex_array; } + LocalVector<Vertex> &get_vertex_array() { return vertex_array; } void create_from_triangle_arrays(const Array &p_arrays); - static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays); + static void create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector<Vertex> &ret, uint32_t *r_format = nullptr); 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); + Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = 0); SurfaceTool(); }; +VARIANT_ENUM_CAST(SurfaceTool::CustomFormat) +VARIANT_ENUM_CAST(SurfaceTool::SkinWeightCount) + #endif diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp new file mode 100644 index 0000000000..9dd00849f4 --- /dev/null +++ b/scene/resources/syntax_highlighter.cpp @@ -0,0 +1,640 @@ +/*************************************************************************/ +/* syntax_highlighter.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "syntax_highlighter.h" + +#include "core/object/script_language.h" +#include "scene/gui/text_edit.h" + +Dictionary SyntaxHighlighter::get_line_syntax_highlighting(int p_line) { + if (highlighting_cache.has(p_line)) { + return highlighting_cache[p_line]; + } + + Dictionary color_map; + if (text_edit == nullptr) { + return color_map; + } + + ScriptInstance *si = get_script_instance(); + if (si && si->has_method("_get_line_syntax_highlighting")) { + color_map = si->call("_get_line_syntax_highlighting", p_line); + } else { + color_map = _get_line_syntax_highlighting(p_line); + } + highlighting_cache[p_line] = color_map; + return color_map; +} + +void SyntaxHighlighter::_lines_edited_from(int p_from_line, int p_to_line) { + if (highlighting_cache.size() < 1) { + return; + } + + int cache_size = highlighting_cache.back()->key(); + for (int i = MIN(p_from_line, p_to_line) - 1; i <= cache_size; i++) { + if (highlighting_cache.has(i)) { + highlighting_cache.erase(i); + } + } +} + +void SyntaxHighlighter::clear_highlighting_cache() { + highlighting_cache.clear(); + + ScriptInstance *si = get_script_instance(); + if (si && si->has_method("_clear_highlighting_cache")) { + si->call("_clear_highlighting_cache"); + return; + } + _clear_highlighting_cache(); +} + +void SyntaxHighlighter::update_cache() { + clear_highlighting_cache(); + + if (text_edit == nullptr) { + return; + } + ScriptInstance *si = get_script_instance(); + if (si && si->has_method("_update_cache")) { + si->call("_update_cache"); + return; + } + _update_cache(); +} + +void SyntaxHighlighter::set_text_edit(TextEdit *p_text_edit) { + if (text_edit && ObjectDB::get_instance(text_edit_instance_id)) { + text_edit->disconnect("lines_edited_from", callable_mp(this, &SyntaxHighlighter::_lines_edited_from)); + } + + text_edit = p_text_edit; + if (p_text_edit == nullptr) { + return; + } + text_edit_instance_id = text_edit->get_instance_id(); + text_edit->connect("lines_edited_from", callable_mp(this, &SyntaxHighlighter::_lines_edited_from)); + update_cache(); +} + +TextEdit *SyntaxHighlighter::get_text_edit() { + return text_edit; +} + +void SyntaxHighlighter::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_line_syntax_highlighting", "line"), &SyntaxHighlighter::get_line_syntax_highlighting); + ClassDB::bind_method(D_METHOD("update_cache"), &SyntaxHighlighter::update_cache); + ClassDB::bind_method(D_METHOD("clear_highlighting_cache"), &SyntaxHighlighter::clear_highlighting_cache); + ClassDB::bind_method(D_METHOD("get_text_edit"), &SyntaxHighlighter::get_text_edit); + + BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_line_syntax_highlighting", PropertyInfo(Variant::INT, "line"))); + BIND_VMETHOD(MethodInfo("_clear_highlighting_cache")); + BIND_VMETHOD(MethodInfo("_update_cache")); +} + +//////////////////////////////////////////////////////////////////////////////// + +static bool _is_char(char32_t c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; +} + +static bool _is_hex_symbol(char32_t c) { + return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +} + +Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) { + Dictionary color_map; + + bool prev_is_char = false; + bool prev_is_number = false; + bool in_keyword = false; + bool in_word = false; + bool in_function_name = false; + bool in_member_variable = false; + bool is_hex_notation = false; + Color keyword_color; + Color color; + + color_region_cache[p_line] = -1; + int in_region = -1; + if (p_line != 0) { + int prev_region_line = p_line - 1; + while (prev_region_line > 0 && !color_region_cache.has(prev_region_line)) { + prev_region_line--; + } + for (int i = prev_region_line; i < p_line - 1; i++) { + get_line_syntax_highlighting(i); + } + if (!color_region_cache.has(p_line - 1)) { + get_line_syntax_highlighting(p_line - 1); + } + in_region = color_region_cache[p_line - 1]; + } + + const String &str = text_edit->get_line(p_line); + const int line_length = str.length(); + Color prev_color; + + if (in_region != -1 && str.length() == 0) { + color_region_cache[p_line] = in_region; + } + for (int j = 0; j < line_length; j++) { + Dictionary highlighter_info; + + color = font_color; + bool is_char = !is_symbol(str[j]); + bool is_a_symbol = is_symbol(str[j]); + bool is_number = (str[j] >= '0' && str[j] <= '9'); + + /* color regions */ + if (is_a_symbol || in_region != -1) { + int from = j; + for (; from < line_length; from++) { + if (str[from] == '\\') { + from++; + continue; + } + break; + } + + if (from != line_length) { + /* check if we are in entering a region */ + if (in_region == -1) { + for (int c = 0; c < color_regions.size(); c++) { + /* check there is enough room */ + int chars_left = line_length - from; + int start_key_length = color_regions[c].start_key.length(); + int end_key_length = color_regions[c].end_key.length(); + if (chars_left < start_key_length) { + continue; + } + + /* search the line */ + bool match = true; + const char32_t *start_key = color_regions[c].start_key.get_data(); + for (int k = 0; k < start_key_length; k++) { + if (start_key[k] != str[from + k]) { + match = false; + break; + } + } + if (!match) { + continue; + } + in_region = c; + from += start_key_length; + + /* check if it's the whole line */ + if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) { + prev_color = color_regions[in_region].color; + highlighter_info["color"] = color_regions[c].color; + color_map[j] = highlighter_info; + + j = line_length; + if (!color_regions[c].line_only) { + color_region_cache[p_line] = c; + } + } + break; + } + + if (j == line_length) { + continue; + } + } + + /* if we are in one find the end key */ + if (in_region != -1) { + /* search the line */ + int region_end_index = -1; + int end_key_length = color_regions[in_region].end_key.length(); + const char32_t *end_key = color_regions[in_region].end_key.get_data(); + for (; from < line_length; from++) { + if (line_length - from < end_key_length) { + break; + } + + if (!is_symbol(str[from])) { + continue; + } + + if (str[from] == '\\') { + from++; + continue; + } + + region_end_index = from; + for (int k = 0; k < end_key_length; k++) { + if (end_key[k] != str[from + k]) { + region_end_index = -1; + break; + } + } + + if (region_end_index != -1) { + break; + } + } + + prev_color = color_regions[in_region].color; + highlighter_info["color"] = color_regions[in_region].color; + color_map[j] = highlighter_info; + + j = from + (end_key_length - 1); + if (region_end_index == -1) { + color_region_cache[p_line] = in_region; + } + + in_region = -1; + prev_is_char = false; + prev_is_number = false; + continue; + } + } + } + + // Allow ABCDEF in hex notation. + if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) { + is_number = true; + } else { + is_hex_notation = false; + } + + // Check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation. + if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'f' || str[j] == 'e') && !in_word && prev_is_number && !is_number) { + is_number = true; + is_a_symbol = false; + is_char = false; + + if (str[j] == 'x' && str[j - 1] == '0') { + is_hex_notation = true; + } + } + + if (!in_word && _is_char(str[j]) && !is_number) { + in_word = true; + } + + if ((in_keyword || in_word) && !is_hex_notation) { + is_number = false; + } + + if (is_a_symbol && str[j] != '.' && in_word) { + in_word = false; + } + + if (!is_char) { + in_keyword = false; + } + + if (!in_keyword && is_char && !prev_is_char) { + int to = j; + while (to < line_length && !is_symbol(str[to])) { + to++; + } + + String word = str.substr(j, to - j); + Color col = Color(); + if (keywords.has(word)) { + col = keywords[word]; + } else if (member_keywords.has(word)) { + col = member_keywords[word]; + for (int k = j - 1; k >= 0; k--) { + if (str[k] == '.') { + col = Color(); //member indexing not allowed + break; + } else if (str[k] > 32) { + break; + } + } + } + + if (col != Color()) { + in_keyword = true; + keyword_color = col; + } + } + + if (!in_function_name && in_word && !in_keyword) { + int k = j; + while (k < line_length && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { + k++; + } + + // Check for space between name and bracket. + while (k < line_length && (str[k] == '\t' || str[k] == ' ')) { + k++; + } + + if (str[k] == '(') { + in_function_name = true; + } + } + + if (!in_function_name && !in_member_variable && !in_keyword && !is_number && in_word) { + int k = j; + while (k > 0 && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { + k--; + } + + if (str[k] == '.') { + in_member_variable = true; + } + } + + if (is_a_symbol) { + in_function_name = false; + in_member_variable = false; + } + + if (in_keyword) { + color = keyword_color; + } else if (in_member_variable) { + color = member_color; + } else if (in_function_name) { + color = function_color; + } else if (is_a_symbol) { + color = symbol_color; + } else if (is_number) { + color = number_color; + } + + prev_is_char = is_char; + prev_is_number = is_number; + + if (color != prev_color) { + prev_color = color; + highlighter_info["color"] = color; + color_map[j] = highlighter_info; + } + } + + return color_map; +} + +void CodeHighlighter::_clear_highlighting_cache() { + color_region_cache.clear(); +} + +void CodeHighlighter::_update_cache() { + font_color = text_edit->get_theme_color("font_color"); +} + +void CodeHighlighter::add_keyword_color(const String &p_keyword, const Color &p_color) { + keywords[p_keyword] = p_color; + clear_highlighting_cache(); +} + +void CodeHighlighter::remove_keyword_color(const String &p_keyword) { + keywords.erase(p_keyword); + clear_highlighting_cache(); +} + +bool CodeHighlighter::has_keyword_color(const String &p_keyword) const { + return keywords.has(p_keyword); +} + +Color CodeHighlighter::get_keyword_color(const String &p_keyword) const { + ERR_FAIL_COND_V(!keywords.has(p_keyword), Color()); + return keywords[p_keyword]; +} + +void CodeHighlighter::set_keyword_colors(const Dictionary p_keywords) { + keywords.clear(); + keywords = p_keywords; + clear_highlighting_cache(); +} + +void CodeHighlighter::clear_keyword_colors() { + keywords.clear(); + clear_highlighting_cache(); +} + +Dictionary CodeHighlighter::get_keyword_colors() const { + return keywords; +} + +void CodeHighlighter::add_member_keyword_color(const String &p_member_keyword, const Color &p_color) { + member_keywords[p_member_keyword] = p_color; + clear_highlighting_cache(); +} + +void CodeHighlighter::remove_member_keyword_color(const String &p_member_keyword) { + member_keywords.erase(p_member_keyword); + clear_highlighting_cache(); +} + +bool CodeHighlighter::has_member_keyword_color(const String &p_member_keyword) const { + return member_keywords.has(p_member_keyword); +} + +Color CodeHighlighter::get_member_keyword_color(const String &p_member_keyword) const { + ERR_FAIL_COND_V(!member_keywords.has(p_member_keyword), Color()); + return member_keywords[p_member_keyword]; +} + +void CodeHighlighter::set_member_keyword_colors(const Dictionary &p_member_keywords) { + member_keywords.clear(); + member_keywords = p_member_keywords; + clear_highlighting_cache(); +} + +void CodeHighlighter::clear_member_keyword_colors() { + member_keywords.clear(); + clear_highlighting_cache(); +} + +Dictionary CodeHighlighter::get_member_keyword_colors() const { + return member_keywords; +} + +void CodeHighlighter::add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only) { + for (int i = 0; i < p_start_key.length(); i++) { + ERR_FAIL_COND_MSG(!is_symbol(p_start_key[i]), "color regions must start with a symbol"); + } + + if (p_end_key.length() > 0) { + for (int i = 0; i < p_end_key.length(); i++) { + ERR_FAIL_COND_MSG(!is_symbol(p_end_key[i]), "color regions must end with a symbol"); + } + } + + int at = 0; + for (int i = 0; i < color_regions.size(); i++) { + ERR_FAIL_COND_MSG(color_regions[i].start_key == p_start_key, "color region with start key '" + p_start_key + "' already exists."); + if (p_start_key.length() < color_regions[i].start_key.length()) { + at++; + } + } + + ColorRegion color_region; + color_region.color = p_color; + color_region.start_key = p_start_key; + color_region.end_key = p_end_key; + color_region.line_only = p_line_only || p_end_key == ""; + color_regions.insert(at, color_region); + clear_highlighting_cache(); +} + +void CodeHighlighter::remove_color_region(const String &p_start_key) { + for (int i = 0; i < color_regions.size(); i++) { + if (color_regions[i].start_key == p_start_key) { + color_regions.remove(i); + break; + } + } + clear_highlighting_cache(); +} + +bool CodeHighlighter::has_color_region(const String &p_start_key) const { + for (int i = 0; i < color_regions.size(); i++) { + if (color_regions[i].start_key == p_start_key) { + return true; + } + } + return false; +} + +void CodeHighlighter::set_color_regions(const Dictionary &p_color_regions) { + color_regions.clear(); + + List<Variant> keys; + p_color_regions.get_key_list(&keys); + + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { + String key = E->get(); + + String start_key = key.get_slice(" ", 0); + String end_key = key.get_slice_count(" ") > 1 ? key.get_slice(" ", 1) : String(); + + add_color_region(start_key, end_key, p_color_regions[key], end_key == ""); + } + clear_highlighting_cache(); +} + +void CodeHighlighter::clear_color_regions() { + color_regions.clear(); + clear_highlighting_cache(); +} + +Dictionary CodeHighlighter::get_color_regions() const { + Dictionary r_color_regions; + for (int i = 0; i < color_regions.size(); i++) { + ColorRegion region = color_regions[i]; + r_color_regions[region.start_key + (region.end_key.is_empty() ? "" : " " + region.end_key)] = region.color; + } + return r_color_regions; +} + +void CodeHighlighter::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_keyword_color", "keyword", "color"), &CodeHighlighter::add_keyword_color); + ClassDB::bind_method(D_METHOD("remove_keyword_color", "keyword"), &CodeHighlighter::remove_keyword_color); + ClassDB::bind_method(D_METHOD("has_keyword_color", "keyword"), &CodeHighlighter::has_keyword_color); + ClassDB::bind_method(D_METHOD("get_keyword_color", "keyword"), &CodeHighlighter::get_keyword_color); + + ClassDB::bind_method(D_METHOD("set_keyword_colors", "keywords"), &CodeHighlighter::set_keyword_colors); + ClassDB::bind_method(D_METHOD("clear_keyword_colors"), &CodeHighlighter::clear_keyword_colors); + ClassDB::bind_method(D_METHOD("get_keyword_colors"), &CodeHighlighter::get_keyword_colors); + + ClassDB::bind_method(D_METHOD("add_member_keyword_color", "member_keyword", "color"), &CodeHighlighter::add_member_keyword_color); + ClassDB::bind_method(D_METHOD("remove_member_keyword_color", "member_keyword"), &CodeHighlighter::remove_member_keyword_color); + ClassDB::bind_method(D_METHOD("has_member_keyword_color", "member_keyword"), &CodeHighlighter::has_member_keyword_color); + ClassDB::bind_method(D_METHOD("get_member_keyword_color", "member_keyword"), &CodeHighlighter::get_member_keyword_color); + + ClassDB::bind_method(D_METHOD("set_member_keyword_colors", "member_keyword"), &CodeHighlighter::set_member_keyword_colors); + ClassDB::bind_method(D_METHOD("clear_member_keyword_colors"), &CodeHighlighter::clear_member_keyword_colors); + ClassDB::bind_method(D_METHOD("get_member_keyword_colors"), &CodeHighlighter::get_member_keyword_colors); + + ClassDB::bind_method(D_METHOD("add_color_region", "start_key", "end_key", "color", "line_only"), &CodeHighlighter::add_color_region, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("remove_color_region", "start_key"), &CodeHighlighter::remove_color_region); + ClassDB::bind_method(D_METHOD("has_color_region", "start_key"), &CodeHighlighter::has_color_region); + + ClassDB::bind_method(D_METHOD("set_color_regions", "color_regions"), &CodeHighlighter::set_color_regions); + ClassDB::bind_method(D_METHOD("clear_color_regions"), &CodeHighlighter::clear_color_regions); + ClassDB::bind_method(D_METHOD("get_color_regions"), &CodeHighlighter::get_color_regions); + + ClassDB::bind_method(D_METHOD("set_function_color", "color"), &CodeHighlighter::set_function_color); + ClassDB::bind_method(D_METHOD("get_function_color"), &CodeHighlighter::get_function_color); + + ClassDB::bind_method(D_METHOD("set_number_color", "color"), &CodeHighlighter::set_number_color); + ClassDB::bind_method(D_METHOD("get_number_color"), &CodeHighlighter::get_number_color); + + ClassDB::bind_method(D_METHOD("set_symbol_color", "color"), &CodeHighlighter::set_symbol_color); + ClassDB::bind_method(D_METHOD("get_symbol_color"), &CodeHighlighter::get_symbol_color); + + ClassDB::bind_method(D_METHOD("set_member_variable_color", "color"), &CodeHighlighter::set_member_variable_color); + ClassDB::bind_method(D_METHOD("get_member_variable_color"), &CodeHighlighter::get_member_variable_color); + + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "number_color"), "set_number_color", "get_number_color"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "symbol_color"), "set_symbol_color", "get_symbol_color"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "function_color"), "set_function_color", "get_function_color"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "member_variable_color"), "set_member_variable_color", "get_member_variable_color"); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "keyword_colors"), "set_keyword_colors", "get_keyword_colors"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "member_keyword_colors"), "set_member_keyword_colors", "get_member_keyword_colors"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "color_regions"), "set_color_regions", "get_color_regions"); +} + +void CodeHighlighter::set_number_color(Color p_color) { + number_color = p_color; + clear_highlighting_cache(); +} + +Color CodeHighlighter::get_number_color() const { + return number_color; +} + +void CodeHighlighter::set_symbol_color(Color p_color) { + symbol_color = p_color; + clear_highlighting_cache(); +} + +Color CodeHighlighter::get_symbol_color() const { + return symbol_color; +} + +void CodeHighlighter::set_function_color(Color p_color) { + function_color = p_color; + clear_highlighting_cache(); +} + +Color CodeHighlighter::get_function_color() const { + return function_color; +} + +void CodeHighlighter::set_member_variable_color(Color p_color) { + member_color = p_color; + clear_highlighting_cache(); +} + +Color CodeHighlighter::get_member_variable_color() const { + return member_color; +} diff --git a/scene/resources/syntax_highlighter.h b/scene/resources/syntax_highlighter.h new file mode 100644 index 0000000000..f3964b0c8f --- /dev/null +++ b/scene/resources/syntax_highlighter.h @@ -0,0 +1,140 @@ +/*************************************************************************/ +/* syntax_highlighter.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SYNTAX_HIGHLIGHTER_H +#define SYNTAX_HIGHLIGHTER_H + +#include "core/io/resource.h" + +class TextEdit; + +class SyntaxHighlighter : public Resource { + GDCLASS(SyntaxHighlighter, Resource) + +private: + Map<int, Dictionary> highlighting_cache; + void _lines_edited_from(int p_from_line, int p_to_line); + +protected: + ObjectID text_edit_instance_id; // For validity check + TextEdit *text_edit = nullptr; + + static void _bind_methods(); + +public: + Dictionary get_line_syntax_highlighting(int p_line); + virtual Dictionary _get_line_syntax_highlighting(int p_line) { return Dictionary(); } + + void clear_highlighting_cache(); + virtual void _clear_highlighting_cache() {} + + void update_cache(); + virtual void _update_cache() {} + + void set_text_edit(TextEdit *p_text_edit); + TextEdit *get_text_edit(); + + SyntaxHighlighter() {} + virtual ~SyntaxHighlighter() {} +}; + +/////////////////////////////////////////////////////////////////////////////// + +class CodeHighlighter : public SyntaxHighlighter { + GDCLASS(CodeHighlighter, SyntaxHighlighter) + +private: + struct ColorRegion { + Color color; + String start_key; + String end_key; + bool line_only = false; + }; + Vector<ColorRegion> color_regions; + Map<int, int> color_region_cache; + + Dictionary keywords; + Dictionary member_keywords; + + Color font_color; + Color member_color; + Color function_color; + Color symbol_color; + Color number_color; + +protected: + static void _bind_methods(); + +public: + virtual Dictionary _get_line_syntax_highlighting(int p_line) override; + + virtual void _clear_highlighting_cache() override; + virtual void _update_cache() override; + + void add_keyword_color(const String &p_keyword, const Color &p_color); + void remove_keyword_color(const String &p_keyword); + bool has_keyword_color(const String &p_keyword) const; + Color get_keyword_color(const String &p_keyword) const; + + void set_keyword_colors(const Dictionary p_keywords); + void clear_keyword_colors(); + Dictionary get_keyword_colors() const; + + void add_member_keyword_color(const String &p_member_keyword, const Color &p_color); + void remove_member_keyword_color(const String &p_member_keyword); + bool has_member_keyword_color(const String &p_member_keyword) const; + Color get_member_keyword_color(const String &p_member_keyword) const; + + void set_member_keyword_colors(const Dictionary &p_color_regions); + void clear_member_keyword_colors(); + Dictionary get_member_keyword_colors() const; + + void add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only = false); + void remove_color_region(const String &p_start_key); + bool has_color_region(const String &p_start_key) const; + + void set_color_regions(const Dictionary &p_member_keyword); + void clear_color_regions(); + Dictionary get_color_regions() const; + + void set_number_color(Color p_color); + Color get_number_color() const; + + void set_symbol_color(Color p_color); + Color get_symbol_color() const; + + void set_function_color(Color p_color); + Color get_function_color() const; + + void set_member_variable_color(Color p_color); + Color get_member_variable_color() const; +}; + +#endif diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp index e3bd5ce0ae..cf07003720 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 356b070ea0..005075a218 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +45,7 @@ public: virtual bool has_text() const; virtual String get_text() const; virtual void set_text(const String &p_code); - virtual void reload_from_file(); + virtual void reload_from_file() override; void set_file_path(const String &p_path) { path = p_path; } Error load_text(const String &p_path); diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp new file mode 100644 index 0000000000..925867a1f2 --- /dev/null +++ b/scene/resources/text_line.cpp @@ -0,0 +1,370 @@ +/*************************************************************************/ +/* text_line.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "text_line.h" + +void TextLine::_bind_methods() { + ClassDB::bind_method(D_METHOD("clear"), &TextLine::clear); + + ClassDB::bind_method(D_METHOD("set_direction", "direction"), &TextLine::set_direction); + ClassDB::bind_method(D_METHOD("get_direction"), &TextLine::get_direction); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "direction", PROPERTY_HINT_ENUM, "Auto,Light-to-right,Right-to-left"), "set_direction", "get_direction"); + + ClassDB::bind_method(D_METHOD("set_orientation", "orientation"), &TextLine::set_orientation); + ClassDB::bind_method(D_METHOD("get_orientation"), &TextLine::get_orientation); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Horizontal,Orientation"), "set_orientation", "get_orientation"); + + ClassDB::bind_method(D_METHOD("set_preserve_invalid", "enabled"), &TextLine::set_preserve_invalid); + ClassDB::bind_method(D_METHOD("get_preserve_invalid"), &TextLine::get_preserve_invalid); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "preserve_invalid"), "set_preserve_invalid", "get_preserve_invalid"); + + ClassDB::bind_method(D_METHOD("set_preserve_control", "enabled"), &TextLine::set_preserve_control); + ClassDB::bind_method(D_METHOD("get_preserve_control"), &TextLine::get_preserve_control); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "preserve_control"), "set_preserve_control", "get_preserve_control"); + + ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::_set_bidi_override); + + ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextLine::add_string, DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(VALIGN_CENTER)); + + ClassDB::bind_method(D_METHOD("set_width", "width"), &TextLine::set_width); + ClassDB::bind_method(D_METHOD("get_width"), &TextLine::get_width); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width"), "set_width", "get_width"); + + ClassDB::bind_method(D_METHOD("set_align", "align"), &TextLine::set_align); + ClassDB::bind_method(D_METHOD("get_align"), &TextLine::get_align); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align"); + + ClassDB::bind_method(D_METHOD("tab_align", "tab_stops"), &TextLine::tab_align); + + ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextLine::set_flags); + ClassDB::bind_method(D_METHOD("get_flags"), &TextLine::get_flags); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida justification,Word justification,Trim edge spaces after justification,Justification only after last tab"), "set_flags", "get_flags"); + + ClassDB::bind_method(D_METHOD("get_objects"), &TextLine::get_objects); + ClassDB::bind_method(D_METHOD("get_object_rect", "key"), &TextLine::get_object_rect); + + ClassDB::bind_method(D_METHOD("get_size"), &TextLine::get_size); + + ClassDB::bind_method(D_METHOD("get_rid"), &TextLine::get_rid); + + ClassDB::bind_method(D_METHOD("get_line_ascent"), &TextLine::get_line_ascent); + ClassDB::bind_method(D_METHOD("get_line_descent"), &TextLine::get_line_descent); + ClassDB::bind_method(D_METHOD("get_line_width"), &TextLine::get_line_width); + ClassDB::bind_method(D_METHOD("get_line_underline_position"), &TextLine::get_line_underline_position); + ClassDB::bind_method(D_METHOD("get_line_underline_thickness"), &TextLine::get_line_underline_thickness); + + ClassDB::bind_method(D_METHOD("draw", "canvas", "pos", "color"), &TextLine::draw, DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "pos", "outline_size", "color"), &TextLine::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1))); + + ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextLine::hit_test); +} + +void TextLine::_shape() { + if (dirty) { + if (!tab_stops.is_empty()) { + TS->shaped_text_tab_align(rid, tab_stops); + } + if (align == HALIGN_FILL) { + TS->shaped_text_fit_to_width(rid, width, flags); + } + dirty = false; + } +} + +RID TextLine::get_rid() const { + return rid; +} + +void TextLine::clear() { + TS->shaped_text_clear(rid); + spacing_top = 0; + spacing_bottom = 0; +} + +void TextLine::set_preserve_invalid(bool p_enabled) { + TS->shaped_text_set_preserve_invalid(rid, p_enabled); + dirty = true; +} + +bool TextLine::get_preserve_invalid() const { + return TS->shaped_text_get_preserve_invalid(rid); +} + +void TextLine::set_preserve_control(bool p_enabled) { + TS->shaped_text_set_preserve_control(rid, p_enabled); + dirty = true; +} + +bool TextLine::get_preserve_control() const { + return TS->shaped_text_get_preserve_control(rid); +} + +void TextLine::set_direction(TextServer::Direction p_direction) { + TS->shaped_text_set_direction(rid, p_direction); + dirty = true; +} + +TextServer::Direction TextLine::get_direction() const { + return TS->shaped_text_get_direction(rid); +} + +void TextLine::set_orientation(TextServer::Orientation p_orientation) { + TS->shaped_text_set_orientation(rid, p_orientation); + dirty = true; +} + +TextServer::Orientation TextLine::get_orientation() const { + return TS->shaped_text_get_orientation(rid); +} + +void TextLine::_set_bidi_override(const Array &p_override) { + Vector<Vector2i> overrides; + for (int i = 0; i < p_override.size(); i++) { + overrides.push_back(p_override[i]); + } + set_bidi_override(overrides); +} + +void TextLine::set_bidi_override(const Vector<Vector2i> &p_override) { + TS->shaped_text_set_bidi_override(rid, p_override); + dirty = true; +} + +bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { + ERR_FAIL_COND_V(p_fonts.is_null(), false); + bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); + spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); + dirty = true; + return res; +} + +bool TextLine::add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) { + bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length); + dirty = true; + return res; +} + +bool TextLine::resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align) { + const_cast<TextLine *>(this)->_shape(); + return TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align); +} + +Array TextLine::get_objects() const { + return TS->shaped_text_get_objects(rid); +} + +Rect2 TextLine::get_object_rect(Variant p_key) const { + return TS->shaped_text_get_object_rect(rid, p_key); +} + +void TextLine::set_align(HAlign p_align) { + if (align != p_align) { + if (align == HALIGN_FILL || p_align == HALIGN_FILL) { + align = p_align; + dirty = true; + } else { + align = p_align; + } + } +} + +HAlign TextLine::get_align() const { + return align; +} + +void TextLine::tab_align(const Vector<float> &p_tab_stops) { + tab_stops = p_tab_stops; + dirty = true; +} + +void TextLine::set_flags(uint8_t p_flags) { + if (flags != p_flags) { + flags = p_flags; + dirty = true; + } +} + +uint8_t TextLine::get_flags() const { + return flags; +} + +void TextLine::set_width(float p_width) { + width = p_width; + if (align == HALIGN_FILL) { + dirty = true; + } +} + +float TextLine::get_width() const { + return width; +} + +Size2 TextLine::get_size() const { + const_cast<TextLine *>(this)->_shape(); + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom); + } else { + return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y); + } +} + +float TextLine::get_line_ascent() const { + const_cast<TextLine *>(this)->_shape(); + return TS->shaped_text_get_ascent(rid) + spacing_top; +} + +float TextLine::get_line_descent() const { + const_cast<TextLine *>(this)->_shape(); + return TS->shaped_text_get_descent(rid) + spacing_bottom; +} + +float TextLine::get_line_width() const { + const_cast<TextLine *>(this)->_shape(); + return TS->shaped_text_get_width(rid); +} + +float TextLine::get_line_underline_position() const { + const_cast<TextLine *>(this)->_shape(); + return TS->shaped_text_get_underline_position(rid); +} + +float TextLine::get_line_underline_thickness() const { + const_cast<TextLine *>(this)->_shape(); + return TS->shaped_text_get_underline_thickness(rid); +} + +void TextLine::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const { + const_cast<TextLine *>(this)->_shape(); + + Vector2 ofs = p_pos; + + float length = TS->shaped_text_get_width(rid); + if (width > 0) { + switch (align) { + case HALIGN_FILL: + case HALIGN_LEFT: + break; + case HALIGN_CENTER: { + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += Math::floor((width - length) / 2.0); + } else { + ofs.y += Math::floor((width - length) / 2.0); + } + } break; + case HALIGN_RIGHT: { + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += width - length; + } else { + ofs.y += width - length; + } + } break; + } + } + + float clip_l; + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top; + clip_l = MAX(0, p_pos.x - ofs.x); + } else { + ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top; + clip_l = MAX(0, p_pos.y - ofs.y); + } + return TS->shaped_text_draw(rid, p_canvas, ofs, clip_l, clip_l + width, p_color); +} + +void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const { + const_cast<TextLine *>(this)->_shape(); + + Vector2 ofs = p_pos; + + float length = TS->shaped_text_get_width(rid); + if (width > 0) { + switch (align) { + case HALIGN_FILL: + case HALIGN_LEFT: + break; + case HALIGN_CENTER: { + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += Math::floor((width - length) / 2.0); + } else { + ofs.y += Math::floor((width - length) / 2.0); + } + } break; + case HALIGN_RIGHT: { + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += width - length; + } else { + ofs.y += width - length; + } + } break; + } + } + + float clip_l; + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top; + clip_l = MAX(0, p_pos.x - ofs.x); + } else { + ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top; + clip_l = MAX(0, p_pos.y - ofs.y); + } + return TS->shaped_text_draw_outline(rid, p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color); +} + +int TextLine::hit_test(float p_coords) const { + const_cast<TextLine *>(this)->_shape(); + + return TS->shaped_text_hit_test_position(rid, p_coords); +} + +TextLine::TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) { + rid = TS->create_shaped_text(p_direction, p_orientation); + spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); + spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); + TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); +} + +TextLine::TextLine() { + rid = TS->create_shaped_text(); +} + +TextLine::~TextLine() { + TS->free(rid); +} diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h new file mode 100644 index 0000000000..74d4f2c32c --- /dev/null +++ b/scene/resources/text_line.h @@ -0,0 +1,116 @@ +/*************************************************************************/ +/* text_line.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEXT_LINE_H +#define TEXT_LINE_H + +#include "scene/resources/font.h" +#include "servers/text_server.h" + +/*************************************************************************/ + +class TextLine : public Reference { + GDCLASS(TextLine, Reference); + + RID rid; + int spacing_top = 0; + int spacing_bottom = 0; + + bool dirty = true; + + float width = -1.0; + uint8_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA; + HAlign align = HALIGN_LEFT; + + Vector<float> tab_stops; + +protected: + static void _bind_methods(); + + void _shape(); + +public: + RID get_rid() const; + + void clear(); + + void set_direction(TextServer::Direction p_direction); + TextServer::Direction get_direction() const; + + void set_bidi_override(const Vector<Vector2i> &p_override); + + void set_orientation(TextServer::Orientation p_orientation); + TextServer::Orientation get_orientation() const; + + void set_preserve_invalid(bool p_enabled); + bool get_preserve_invalid() const; + + void set_preserve_control(bool p_enabled); + bool get_preserve_control() const; + + bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); + bool add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1); + bool resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER); + + void set_align(HAlign p_align); + HAlign get_align() const; + + void tab_align(const Vector<float> &p_tab_stops); + + void set_flags(uint8_t p_flags); + uint8_t get_flags() const; + + void set_width(float p_width); + float get_width() const; + + Array get_objects() const; + Rect2 get_object_rect(Variant p_key) const; + + Size2 get_size() const; + + float get_line_ascent() const; + float get_line_descent() const; + float get_line_width() const; + float get_line_underline_position() const; + float get_line_underline_thickness() const; + + void draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1)) const; + void draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + + int hit_test(float p_coords) const; + + void _set_bidi_override(const Array &p_override); + + TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL); + TextLine(); + ~TextLine(); +}; + +#endif // TEXT_LINE_H diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp new file mode 100644 index 0000000000..444a4bb22a --- /dev/null +++ b/scene/resources/text_paragraph.cpp @@ -0,0 +1,725 @@ +/*************************************************************************/ +/* text_paragraph.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "scene/resources/text_paragraph.h" + +void TextParagraph::_bind_methods() { + ClassDB::bind_method(D_METHOD("clear"), &TextParagraph::clear); + + ClassDB::bind_method(D_METHOD("set_direction", "direction"), &TextParagraph::set_direction); + ClassDB::bind_method(D_METHOD("get_direction"), &TextParagraph::get_direction); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "direction", PROPERTY_HINT_ENUM, "Auto,Light-to-right,Right-to-left"), "set_direction", "get_direction"); + + ClassDB::bind_method(D_METHOD("set_orientation", "orientation"), &TextParagraph::set_orientation); + ClassDB::bind_method(D_METHOD("get_orientation"), &TextParagraph::get_orientation); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Horizontal,Orientation"), "set_orientation", "get_orientation"); + + ClassDB::bind_method(D_METHOD("set_preserve_invalid", "enabled"), &TextParagraph::set_preserve_invalid); + ClassDB::bind_method(D_METHOD("get_preserve_invalid"), &TextParagraph::get_preserve_invalid); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "preserve_invalid"), "set_preserve_invalid", "get_preserve_invalid"); + + ClassDB::bind_method(D_METHOD("set_preserve_control", "enabled"), &TextParagraph::set_preserve_control); + ClassDB::bind_method(D_METHOD("get_preserve_control"), &TextParagraph::get_preserve_control); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "preserve_control"), "set_preserve_control", "get_preserve_control"); + + ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextParagraph::_set_bidi_override); + + ClassDB::bind_method(D_METHOD("set_dropcap", "text", "fonts", "size", "dropcap_margins", "opentype_features", "language"), &TextParagraph::set_dropcap, DEFVAL(Rect2()), DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap); + + ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextParagraph::add_string, DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(VALIGN_CENTER)); + + ClassDB::bind_method(D_METHOD("set_align", "align"), &TextParagraph::set_align); + ClassDB::bind_method(D_METHOD("get_align"), &TextParagraph::get_align); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align"); + + ClassDB::bind_method(D_METHOD("tab_align", "tab_stops"), &TextParagraph::tab_align); + + ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextParagraph::set_flags); + ClassDB::bind_method(D_METHOD("get_flags"), &TextParagraph::get_flags); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida justification,Word justification,Trim edge spaces after justification,Justification only after last tab,Break mandatory,Break words,Break graphemes"), "set_flags", "get_flags"); + + ClassDB::bind_method(D_METHOD("set_width", "width"), &TextParagraph::set_width); + ClassDB::bind_method(D_METHOD("get_width"), &TextParagraph::get_width); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width"), "set_width", "get_width"); + + ClassDB::bind_method(D_METHOD("get_non_wraped_size"), &TextParagraph::get_non_wraped_size); + ClassDB::bind_method(D_METHOD("get_size"), &TextParagraph::get_size); + + ClassDB::bind_method(D_METHOD("get_rid"), &TextParagraph::get_rid); + ClassDB::bind_method(D_METHOD("get_line_rid", "line"), &TextParagraph::get_line_rid); + ClassDB::bind_method(D_METHOD("get_dropcap_rid"), &TextParagraph::get_dropcap_rid); + + ClassDB::bind_method(D_METHOD("get_line_count"), &TextParagraph::get_line_count); + + ClassDB::bind_method(D_METHOD("get_line_objects", "line"), &TextParagraph::get_line_objects); + ClassDB::bind_method(D_METHOD("get_line_object_rect", "line", "key"), &TextParagraph::get_line_object_rect); + ClassDB::bind_method(D_METHOD("get_line_size", "line"), &TextParagraph::get_line_size); + ClassDB::bind_method(D_METHOD("get_line_range", "line"), &TextParagraph::get_line_range); + ClassDB::bind_method(D_METHOD("get_line_ascent", "line"), &TextParagraph::get_line_ascent); + ClassDB::bind_method(D_METHOD("get_line_descent", "line"), &TextParagraph::get_line_descent); + ClassDB::bind_method(D_METHOD("get_line_width", "line"), &TextParagraph::get_line_width); + ClassDB::bind_method(D_METHOD("get_line_underline_position", "line"), &TextParagraph::get_line_underline_position); + ClassDB::bind_method(D_METHOD("get_line_underline_thickness", "line"), &TextParagraph::get_line_underline_thickness); + + ClassDB::bind_method(D_METHOD("get_dropcap_size"), &TextParagraph::get_dropcap_size); + ClassDB::bind_method(D_METHOD("get_dropcap_lines"), &TextParagraph::get_dropcap_lines); + + ClassDB::bind_method(D_METHOD("draw", "canvas", "pos", "color", "dc_color"), &TextParagraph::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "pos", "outline_size", "color", "dc_color"), &TextParagraph::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(Color(1, 1, 1))); + + ClassDB::bind_method(D_METHOD("draw_line", "canvas", "pos", "line", "color"), &TextParagraph::draw_line, DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_line_outline", "canvas", "pos", "line", "outline_size", "color"), &TextParagraph::draw_line_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1))); + + ClassDB::bind_method(D_METHOD("draw_dropcap", "canvas", "pos", "color"), &TextParagraph::draw_dropcap, DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_dropcap_outline", "canvas", "pos", "outline_size", "color"), &TextParagraph::draw_dropcap_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1))); + + ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextParagraph::hit_test); +} + +void TextParagraph::_shape_lines() { + if (dirty_lines) { + for (int i = 0; i < lines.size(); i++) { + TS->free(lines[i]); + } + lines.clear(); + + if (!tab_stops.is_empty()) { + TS->shaped_text_tab_align(rid, tab_stops); + } + + float h_offset = 0.f; + float v_offset = 0.f; + int start = 0; + dropcap_lines = 0; + + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + v_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + v_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } + + if (h_offset > 0) { + // Dropcap, flow around. + Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(rid, width - h_offset, 0, flags); + for (int i = 0; i < line_breaks.size(); i++) { + RID line = TS->shaped_text_substr(rid, line_breaks[i].x, line_breaks[i].y - line_breaks[i].x); + float h = (TS->shaped_text_get_orientation(line) == TextServer::ORIENTATION_HORIZONTAL) ? TS->shaped_text_get_size(line).y : TS->shaped_text_get_size(line).x; + if (v_offset < h) { + TS->free(line); + break; + } + if (!tab_stops.is_empty()) { + TS->shaped_text_tab_align(line, tab_stops); + } + if (align == HALIGN_FILL && (line_breaks.size() == 1 || i < line_breaks.size() - 1)) { + TS->shaped_text_fit_to_width(line, width - h_offset, flags); + } + dropcap_lines++; + v_offset -= h; + start = line_breaks[i].y; + lines.push_back(line); + } + } + // Use fixed for the rest of lines. + Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(rid, width, start, flags); + for (int i = 0; i < line_breaks.size(); i++) { + RID line = TS->shaped_text_substr(rid, line_breaks[i].x, line_breaks[i].y - line_breaks[i].x); + if (!tab_stops.is_empty()) { + TS->shaped_text_tab_align(line, tab_stops); + } + if (align == HALIGN_FILL && (line_breaks.size() == 1 || i < line_breaks.size() - 1)) { + TS->shaped_text_fit_to_width(line, width, flags); + } + lines.push_back(line); + } + dirty_lines = false; + } +} + +RID TextParagraph::get_rid() const { + return rid; +} + +RID TextParagraph::get_line_rid(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), RID()); + return lines[p_line]; +} + +RID TextParagraph::get_dropcap_rid() const { + return dropcap_rid; +} + +void TextParagraph::clear() { + spacing_top = 0; + spacing_bottom = 0; + for (int i = 0; i < lines.size(); i++) { + TS->free(lines[i]); + } + lines.clear(); + TS->shaped_text_clear(rid); + TS->shaped_text_clear(dropcap_rid); +} + +void TextParagraph::set_preserve_invalid(bool p_enabled) { + TS->shaped_text_set_preserve_invalid(rid, p_enabled); + TS->shaped_text_set_preserve_invalid(dropcap_rid, p_enabled); + dirty_lines = true; +} + +bool TextParagraph::get_preserve_invalid() const { + return TS->shaped_text_get_preserve_invalid(rid); +} + +void TextParagraph::set_preserve_control(bool p_enabled) { + TS->shaped_text_set_preserve_control(rid, p_enabled); + TS->shaped_text_set_preserve_control(dropcap_rid, p_enabled); + dirty_lines = true; +} + +bool TextParagraph::get_preserve_control() const { + return TS->shaped_text_get_preserve_control(rid); +} + +void TextParagraph::set_direction(TextServer::Direction p_direction) { + TS->shaped_text_set_direction(rid, p_direction); + TS->shaped_text_set_direction(dropcap_rid, p_direction); + dirty_lines = true; +} + +TextServer::Direction TextParagraph::get_direction() const { + const_cast<TextParagraph *>(this)->_shape_lines(); + return TS->shaped_text_get_direction(rid); +} + +void TextParagraph::set_orientation(TextServer::Orientation p_orientation) { + TS->shaped_text_set_orientation(rid, p_orientation); + TS->shaped_text_set_orientation(dropcap_rid, p_orientation); + dirty_lines = true; +} + +TextServer::Orientation TextParagraph::get_orientation() const { + const_cast<TextParagraph *>(this)->_shape_lines(); + return TS->shaped_text_get_orientation(rid); +} + +bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) { + ERR_FAIL_COND_V(p_fonts.is_null(), false); + TS->shaped_text_clear(dropcap_rid); + dropcap_margins = p_dropcap_margins; + bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + dirty_lines = true; + return res; +} + +void TextParagraph::clear_dropcap() { + dropcap_margins = Rect2(); + TS->shaped_text_clear(dropcap_rid); + dirty_lines = true; +} + +bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { + ERR_FAIL_COND_V(p_fonts.is_null(), false); + bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); + spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); + dirty_lines = true; + return res; +} + +void TextParagraph::_set_bidi_override(const Array &p_override) { + Vector<Vector2i> overrides; + for (int i = 0; i < p_override.size(); i++) { + overrides.push_back(p_override[i]); + } + set_bidi_override(overrides); +} + +void TextParagraph::set_bidi_override(const Vector<Vector2i> &p_override) { + TS->shaped_text_set_bidi_override(rid, p_override); + dirty_lines = true; +} + +bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) { + bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length); + dirty_lines = true; + return res; +} + +bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align) { + bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align); + dirty_lines = true; + return res; +} + +void TextParagraph::set_align(HAlign p_align) { + if (align != p_align) { + if (align == HALIGN_FILL || p_align == HALIGN_FILL) { + align = p_align; + dirty_lines = true; + } else { + align = p_align; + } + } +} + +HAlign TextParagraph::get_align() const { + return align; +} + +void TextParagraph::tab_align(const Vector<float> &p_tab_stops) { + tab_stops = p_tab_stops; + dirty_lines = true; +} + +void TextParagraph::set_flags(uint8_t p_flags) { + if (flags != p_flags) { + flags = p_flags; + dirty_lines = true; + } +} + +uint8_t TextParagraph::get_flags() const { + return flags; +} + +void TextParagraph::set_width(float p_width) { + if (width != p_width) { + width = p_width; + dirty_lines = true; + } +} + +float TextParagraph::get_width() const { + return width; +} + +Size2 TextParagraph::get_non_wraped_size() const { + const_cast<TextParagraph *>(this)->_shape_lines(); + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom); + } else { + return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y); + } +} + +Size2 TextParagraph::get_size() const { + const_cast<TextParagraph *>(this)->_shape_lines(); + Size2 size; + for (int i = 0; i < lines.size(); i++) { + Size2 lsize = TS->shaped_text_get_size(lines[i]); + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + size.x = MAX(size.x, lsize.x); + size.y += lsize.y + spacing_top + spacing_bottom; + } else { + size.x += lsize.x + spacing_top + spacing_bottom; + size.y = MAX(size.y, lsize.y); + } + } + return size; +} + +int TextParagraph::get_line_count() const { + const_cast<TextParagraph *>(this)->_shape_lines(); + return lines.size(); +} + +Array TextParagraph::get_line_objects(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Array()); + return TS->shaped_text_get_objects(lines[p_line]); +} + +Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Rect2()); + Rect2 xrect = TS->shaped_text_get_object_rect(lines[p_line], p_key); + for (int i = 0; i < p_line; i++) { + Size2 lsize = TS->shaped_text_get_size(lines[i]); + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + xrect.position.y += lsize.y + spacing_top + spacing_bottom; + } else { + xrect.position.x += lsize.x + spacing_top + spacing_bottom; + } + } + return xrect; +} + +Size2 TextParagraph::get_line_size(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Size2()); + if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) { + return Size2(TS->shaped_text_get_size(lines[p_line]).x, TS->shaped_text_get_size(lines[p_line]).y + spacing_top + spacing_bottom); + } else { + return Size2(TS->shaped_text_get_size(lines[p_line]).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(lines[p_line]).y); + } +} + +Vector2i TextParagraph::get_line_range(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Vector2i()); + return TS->shaped_text_get_range(lines[p_line]); +} + +float TextParagraph::get_line_ascent(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f); + return TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; +} + +float TextParagraph::get_line_descent(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f); + return TS->shaped_text_get_descent(lines[p_line]) + spacing_bottom; +} + +float TextParagraph::get_line_width(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f); + return TS->shaped_text_get_width(lines[p_line]); +} + +float TextParagraph::get_line_underline_position(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f); + return TS->shaped_text_get_underline_position(lines[p_line]); +} + +float TextParagraph::get_line_underline_thickness(int p_line) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f); + return TS->shaped_text_get_underline_thickness(lines[p_line]); +} + +Size2 TextParagraph::get_dropcap_size() const { + return TS->shaped_text_get_size(dropcap_rid) + dropcap_margins.size + dropcap_margins.position; +} + +int TextParagraph::get_dropcap_lines() const { + return dropcap_lines; +} + +void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color, const Color &p_dc_color) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + Vector2 ofs = p_pos; + float h_offset = 0.f; + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } + + if (h_offset > 0) { + // Draw dropcap. + Vector2 dc_off = ofs; + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_RTL) { + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + dc_off.x += width - h_offset; + } else { + dc_off.y += width - h_offset; + } + } + TS->shaped_text_draw(dropcap_rid, p_canvas, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color); + } + + for (int i = 0; i < lines.size(); i++) { + float l_width = width; + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x = p_pos.x; + ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top; + if (i <= dropcap_lines) { + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) { + ofs.x -= h_offset; + } + l_width -= h_offset; + } + } else { + ofs.y = p_pos.y; + ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top; + if (i <= dropcap_lines) { + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) { + ofs.x -= h_offset; + } + l_width -= h_offset; + } + } + float length = TS->shaped_text_get_width(lines[i]); + if (width > 0) { + switch (align) { + case HALIGN_FILL: + case HALIGN_LEFT: + break; + case HALIGN_CENTER: { + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += Math::floor((l_width - length) / 2.0); + } else { + ofs.y += Math::floor((l_width - length) / 2.0); + } + } break; + case HALIGN_RIGHT: { + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += l_width - length; + } else { + ofs.y += l_width - length; + } + } break; + } + } + float clip_l; + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + clip_l = MAX(0, p_pos.x - ofs.x); + } else { + clip_l = MAX(0, p_pos.y - ofs.y); + } + TS->shaped_text_draw(lines[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color); + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x = p_pos.x; + ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; + } else { + ofs.y = p_pos.y; + ofs.x += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; + } + } +} + +void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color, const Color &p_dc_color) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + Vector2 ofs = p_pos; + + float h_offset = 0.f; + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } + + if (h_offset > 0) { + // Draw dropcap. + Vector2 dc_off = ofs; + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_RTL) { + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + dc_off.x += width - h_offset; + } else { + dc_off.y += width - h_offset; + } + } + TS->shaped_text_draw_outline(dropcap_rid, p_canvas, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color); + } + + for (int i = 0; i < lines.size(); i++) { + float l_width = width; + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x = p_pos.x; + ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top; + if (i <= dropcap_lines) { + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) { + ofs.x -= h_offset; + } + l_width -= h_offset; + } + } else { + ofs.y = p_pos.y; + ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top; + if (i <= dropcap_lines) { + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) { + ofs.x -= h_offset; + } + l_width -= h_offset; + } + } + float length = TS->shaped_text_get_width(lines[i]); + if (width > 0) { + switch (align) { + case HALIGN_FILL: + case HALIGN_LEFT: + break; + case HALIGN_CENTER: { + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += Math::floor((l_width - length) / 2.0); + } else { + ofs.y += Math::floor((l_width - length) / 2.0); + } + } break; + case HALIGN_RIGHT: { + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += l_width - length; + } else { + ofs.y += l_width - length; + } + } break; + } + } + float clip_l; + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + clip_l = MAX(0, p_pos.x - ofs.x); + } else { + clip_l = MAX(0, p_pos.y - ofs.y); + } + TS->shaped_text_draw_outline(lines[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color); + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x = p_pos.x; + ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; + } else { + ofs.y = p_pos.y; + ofs.x += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; + } + } +} + +int TextParagraph::hit_test(const Point2 &p_coords) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + Vector2 ofs; + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + if (ofs.y < 0) + return 0; + } else { + if (ofs.x < 0) + return 0; + } + for (int i = 0; i < lines.size(); i++) { + if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { + if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines[i]).y)) { + return TS->shaped_text_hit_test_position(lines[i], p_coords.x); + } + ofs.y += TS->shaped_text_get_size(lines[i]).y + spacing_bottom + spacing_top; + } else { + if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(lines[i]).x)) { + return TS->shaped_text_hit_test_position(lines[i], p_coords.y); + } + ofs.y += TS->shaped_text_get_size(lines[i]).x + spacing_bottom + spacing_top; + } + } + return TS->shaped_text_get_range(rid).y; +} + +void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const { + Vector2 ofs = p_pos; + float h_offset = 0.f; + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } + + if (h_offset > 0) { + // Draw dropcap. + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_RTL) { + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += width - h_offset; + } else { + ofs.y += width - h_offset; + } + } + TS->shaped_text_draw(dropcap_rid, p_canvas, ofs + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_color); + } +} + +void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const { + Vector2 ofs = p_pos; + float h_offset = 0.f; + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } + + if (h_offset > 0) { + // Draw dropcap. + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_RTL) { + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += width - h_offset; + } else { + ofs.y += width - h_offset; + } + } + TS->shaped_text_draw_outline(dropcap_rid, p_canvas, ofs + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_color); + } +} + +void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND(p_line < 0 || p_line >= lines.size()); + + Vector2 ofs = p_pos; + + if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; + } else { + ofs.x += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; + } + return TS->shaped_text_draw(lines[p_line], p_canvas, ofs, -1, -1, p_color); +} + +void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size, const Color &p_color) const { + const_cast<TextParagraph *>(this)->_shape_lines(); + ERR_FAIL_COND(p_line < 0 || p_line >= lines.size()); + + Vector2 ofs = p_pos; + if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; + } else { + ofs.x += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; + } + return TS->shaped_text_draw_outline(lines[p_line], p_canvas, ofs, -1, -1, p_outline_size, p_color); +} + +TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) { + rid = TS->create_shaped_text(p_direction, p_orientation); + TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); + spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); + width = p_width; +} + +TextParagraph::TextParagraph() { + rid = TS->create_shaped_text(); + dropcap_rid = TS->create_shaped_text(); +} + +TextParagraph::~TextParagraph() { + for (int i = 0; i < lines.size(); i++) { + TS->free(lines[i]); + } + lines.clear(); + TS->free(rid); + TS->free(dropcap_rid); +} diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h new file mode 100644 index 0000000000..a16fa8c3c4 --- /dev/null +++ b/scene/resources/text_paragraph.h @@ -0,0 +1,140 @@ +/*************************************************************************/ +/* text_paragraph.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEXT_PARAGRAPH_H +#define TEXT_PARAGRAPH_H + +#include "scene/resources/font.h" +#include "servers/text_server.h" + +/*************************************************************************/ + +class TextParagraph : public Reference { + GDCLASS(TextParagraph, Reference); + + RID dropcap_rid; + int dropcap_lines = 0; + Rect2 dropcap_margins; + + RID rid; + Vector<RID> lines; + int spacing_top = 0; + int spacing_bottom = 0; + + bool dirty_lines = true; + + float width = -1.0; + uint8_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA; + HAlign align = HALIGN_LEFT; + + Vector<float> tab_stops; + +protected: + static void _bind_methods(); + + void _shape_lines(); + +public: + RID get_rid() const; + RID get_line_rid(int p_line) const; + RID get_dropcap_rid() const; + + void clear(); + + void set_direction(TextServer::Direction p_direction); + TextServer::Direction get_direction() const; + + void set_orientation(TextServer::Orientation p_orientation); + TextServer::Orientation get_orientation() const; + + void set_preserve_invalid(bool p_enabled); + bool get_preserve_invalid() const; + + void set_preserve_control(bool p_enabled); + bool get_preserve_control() const; + + void set_bidi_override(const Vector<Vector2i> &p_override); + + bool set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); + void clear_dropcap(); + + bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); + bool add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1); + bool resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER); + + void set_align(HAlign p_align); + HAlign get_align() const; + + void tab_align(const Vector<float> &p_tab_stops); + + void set_flags(uint8_t p_flags); + uint8_t get_flags() const; + + void set_width(float p_width); + float get_width() const; + + Size2 get_non_wraped_size() const; + + Size2 get_size() const; + + int get_line_count() const; + + Array get_line_objects(int p_line) const; + Rect2 get_line_object_rect(int p_line, Variant p_key) const; + Size2 get_line_size(int p_line) const; + float get_line_ascent(int p_line) const; + float get_line_descent(int p_line) const; + float get_line_width(int p_line) const; + Vector2i get_line_range(int p_line) const; + float get_line_underline_position(int p_line) const; + float get_line_underline_thickness(int p_line) const; + + Size2 get_dropcap_size() const; + int get_dropcap_lines() const; + + void draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1), const Color &p_dc_color = Color(1, 1, 1)) const; + void draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1), const Color &p_dc_color = Color(1, 1, 1)) const; + + void draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color = Color(1, 1, 1)) const; + void draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + + void draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1)) const; + void draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + + int hit_test(const Point2 &p_coords) const; + + void _set_bidi_override(const Array &p_override); + + TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL); + TextParagraph(); + ~TextParagraph(); +}; + +#endif // TEXT_PARAGRAPH_H diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 331cffed5d..8cccf81659 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,6 @@ #include "core/core_string_names.h" #include "core/io/image_loader.h" -#include "core/method_bind_ext.gen.inc" #include "core/os/os.h" #include "mesh.h" #include "scene/resources/bit_map.h" @@ -46,28 +45,21 @@ bool Texture2D::is_pixel_opaque(int p_x, int p_y) const { return true; } -void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); +void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose); } -void Texture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); +void Texture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose); } -void Texture2D::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<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat); +void Texture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, p_clip_uv); } bool Texture2D::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; } @@ -76,9 +68,9 @@ void Texture2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_height"), &Texture2D::get_height); ClassDB::bind_method(D_METHOD("get_size"), &Texture2D::get_size); ClassDB::bind_method(D_METHOD("has_alpha"), &Texture2D::has_alpha); - ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat"), &Texture2D::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT)); - ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT)); - ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose"), &Texture2D::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_data"), &Texture2D::get_data); ADD_GROUP("", ""); @@ -102,7 +94,7 @@ void ImageTexture::reload_from_file() { create_from_image(img); } else { Resource::reload_from_file(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } } @@ -154,12 +146,12 @@ void ImageTexture::_reload_hook(const RID &p_hook) { RID new_texture = RenderingServer::get_singleton()->texture_2d_create(img); RenderingServer::get_singleton()->texture_replace(texture, new_texture); - _change_notify(); + notify_property_list_changed(); emit_changed(); } void ImageTexture::create_from_image(const Ref<Image> &p_image) { - ERR_FAIL_COND(p_image.is_null()); + ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image"); w = p_image->get_width(); h = p_image->get_height(); format = p_image->get_format(); @@ -171,7 +163,7 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image) { RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_image); RenderingServer::get_singleton()->texture_replace(texture, new_texture); } - _change_notify(); + notify_property_list_changed(); emit_changed(); image_stored = true; @@ -182,11 +174,14 @@ Image::Format ImageTexture::get_format() const { } void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) { - ERR_FAIL_COND(p_image.is_null()); - ERR_FAIL_COND(texture.is_null()); - ERR_FAIL_COND(p_image->get_width() != w || p_image->get_height() != h); - ERR_FAIL_COND(p_image->get_format() != format); - ERR_FAIL_COND(mipmaps != p_image->has_mipmaps()); + ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image"); + ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized."); + ERR_FAIL_COND_MSG(p_image->get_width() != w || p_image->get_height() != h, + "The new image dimensions must match the texture size."); + ERR_FAIL_COND_MSG(p_image->get_format() != format, + "The new image format must match the texture's image format."); + ERR_FAIL_COND_MSG(mipmaps != p_image->has_mipmaps(), + "The new image mipmaps configuration must match the texture's image mipmaps configuration"); if (p_immediate) { RenderingServer::get_singleton()->texture_2d_update_immediate(texture, p_image); @@ -194,7 +189,7 @@ void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) { RenderingServer::get_singleton()->texture_2d_update(texture, p_image); } - _change_notify(); + notify_property_list_changed(); emit_changed(); alpha_cache.unref(); @@ -233,31 +228,25 @@ bool ImageTexture::has_alpha() const { return (format == Image::FORMAT_LA8 || format == Image::FORMAT_RGBA8); } -void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose); } -void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose); } -void ImageTexture::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<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv); } bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const { @@ -321,12 +310,7 @@ void ImageTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("_reload_hook", "rid"), &ImageTexture::_reload_hook); } -ImageTexture::ImageTexture() { - w = h = 0; - image_stored = false; - mipmaps = false; - format = Image::FORMAT_L8; -} +ImageTexture::ImageTexture() {} ImageTexture::~ImageTexture() { if (texture.is_valid()) { @@ -382,8 +366,8 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit img = Image::lossy_unpacker(pv); } - if (img.is_null() || img->empty()) { - ERR_FAIL_COND_V(img.is_null() || img->empty(), Ref<Image>()); + if (img.is_null() || img->is_empty()) { + ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>()); } if (first) { @@ -512,7 +496,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &t ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER); FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); @@ -559,7 +543,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &t memdelete(f); - if (image.is_null() || image->empty()) { + if (image.is_null() || image->is_empty()) { return ERR_CANT_OPEN; } @@ -628,7 +612,7 @@ Error StreamTexture2D::load(const String &p_path) { } #endif - _change_notify(); + notify_property_list_changed(); emit_changed(); return OK; } @@ -652,31 +636,25 @@ RID StreamTexture2D::get_rid() const { return texture; } -void StreamTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void StreamTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose); } -void StreamTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void StreamTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose); } -void StreamTexture2D::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<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void StreamTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { if ((w | h) == 0) { return; } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv); } bool StreamTexture2D::has_alpha() const { @@ -750,11 +728,7 @@ void StreamTexture2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); } -StreamTexture2D::StreamTexture2D() { - format = Image::FORMAT_MAX; - w = 0; - h = 0; -} +StreamTexture2D::StreamTexture2D() {} StreamTexture2D::~StreamTexture2D() { if (texture.is_valid()) { @@ -762,7 +736,7 @@ StreamTexture2D::~StreamTexture2D() { } } -RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<StreamTexture2D> st; st.instance(); Error err = st->load(p_path); @@ -791,8 +765,306 @@ String ResourceFormatLoaderStreamTexture2D::get_resource_type(const String &p_pa return ""; } +//////////////////////////////////// + +TypedArray<Image> Texture3D::_get_data() const { + Vector<Ref<Image>> data = get_data(); + + TypedArray<Image> ret; + ret.resize(data.size()); + for (int i = 0; i < data.size(); i++) { + ret[i] = data[i]; + } + return ret; +} + +void Texture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_format"), &Texture3D::get_format); + ClassDB::bind_method(D_METHOD("get_width"), &Texture3D::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &Texture3D::get_height); + ClassDB::bind_method(D_METHOD("get_depth"), &Texture3D::get_depth); + ClassDB::bind_method(D_METHOD("has_mipmaps"), &Texture3D::has_mipmaps); + ClassDB::bind_method(D_METHOD("get_data"), &Texture3D::_get_data); +} ////////////////////////////////////////// +Image::Format ImageTexture3D::get_format() const { + return format; +} +int ImageTexture3D::get_width() const { + return width; +} +int ImageTexture3D::get_height() const { + return height; +} +int ImageTexture3D::get_depth() const { + return depth; +} +bool ImageTexture3D::has_mipmaps() const { + return mipmaps; +} + +Error ImageTexture3D::_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data) { + Vector<Ref<Image>> images; + images.resize(p_data.size()); + for (int i = 0; i < images.size(); i++) { + images.write[i] = p_data[i]; + } + return create(p_format, p_width, p_height, p_depth, p_mipmaps, images); +} + +void ImageTexture3D::_update(const TypedArray<Image> &p_data) { + Vector<Ref<Image>> images; + images.resize(p_data.size()); + for (int i = 0; i < images.size(); i++) { + images.write[i] = p_data[i]; + } + return update(images); +} + +Error ImageTexture3D::create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { + RID tex = RenderingServer::get_singleton()->texture_3d_create(p_format, p_width, p_height, p_depth, p_mipmaps, p_data); + ERR_FAIL_COND_V(tex.is_null(), ERR_CANT_CREATE); + + if (texture.is_valid()) { + RenderingServer::get_singleton()->texture_replace(texture, tex); + } + + return OK; +} + +void ImageTexture3D::update(const Vector<Ref<Image>> &p_data) { + ERR_FAIL_COND(!texture.is_valid()); + RenderingServer::get_singleton()->texture_3d_update(texture, p_data); +} + +Vector<Ref<Image>> ImageTexture3D::get_data() const { + ERR_FAIL_COND_V(!texture.is_valid(), Vector<Ref<Image>>()); + return RS::get_singleton()->texture_3d_get(texture); +} + +RID ImageTexture3D::get_rid() const { + if (!texture.is_valid()) { + texture = RS::get_singleton()->texture_3d_placeholder_create(); + } + return texture; +} +void ImageTexture3D::set_path(const String &p_path, bool p_take_over) { + if (texture.is_valid()) { + RenderingServer::get_singleton()->texture_set_path(texture, p_path); + } + + Resource::set_path(p_path, p_take_over); +} + +void ImageTexture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("create", "format", "width", "height", "depth", "use_mipmaps", "data"), &ImageTexture3D::_create); + ClassDB::bind_method(D_METHOD("update", "data"), &ImageTexture3D::_update); +} + +ImageTexture3D::ImageTexture3D() { +} + +ImageTexture3D::~ImageTexture3D() { + if (texture.is_valid()) { + RS::get_singleton()->free(texture); + } +} + +//////////////////////////////////////////// + +void StreamTexture3D::set_path(const String &p_path, bool p_take_over) { + if (texture.is_valid()) { + RenderingServer::get_singleton()->texture_set_path(texture, p_path); + } + + Resource::set_path(p_path, p_take_over); +} + +Image::Format StreamTexture3D::get_format() const { + return format; +} + +Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) { + FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); + + uint8_t header[4]; + f->get_buffer(header, 4); + ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L', ERR_FILE_UNRECOGNIZED); + + //stored as stream textures (used for lossless and lossy compression) + uint32_t version = f->get_32(); + + if (version > FORMAT_VERSION) { + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is too new."); + } + + r_depth = f->get_32(); //depth + f->get_32(); //ignored (mode) + f->get_32(); // ignored (data format) + + f->get_32(); //ignored + int mipmaps = f->get_32(); + f->get_32(); //ignored + f->get_32(); //ignored + + r_mipmaps = mipmaps != 0; + + r_data.clear(); + + for (int i = 0; i < (r_depth + mipmaps); i++) { + Ref<Image> image = StreamTexture2D::load_image_from_file(f, 0); + ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN); + if (i == 0) { + r_format = image->get_format(); + r_width = image->get_width(); + r_height = image->get_height(); + } + r_data.push_back(image); + } + + return OK; +} + +Error StreamTexture3D::load(const String &p_path) { + Vector<Ref<Image>> data; + + int tw, th, td; + Image::Format tfmt; + bool tmm; + + Error err = _load_data(p_path, data, tfmt, tw, th, td, tmm); + if (err) { + return err; + } + + if (texture.is_valid()) { + RID new_texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data); + RS::get_singleton()->texture_replace(texture, new_texture); + } else { + texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data); + } + + w = tw; + h = th; + d = td; + mipmaps = tmm; + format = tfmt; + + path_to_file = p_path; + + if (get_path() == String()) { + //temporarily set path if no path set for resource, helps find errors + RenderingServer::get_singleton()->texture_set_path(texture, p_path); + } + + notify_property_list_changed(); + emit_changed(); + return OK; +} + +String StreamTexture3D::get_load_path() const { + return path_to_file; +} + +int StreamTexture3D::get_width() const { + return w; +} + +int StreamTexture3D::get_height() const { + return h; +} + +int StreamTexture3D::get_depth() const { + return d; +} + +bool StreamTexture3D::has_mipmaps() const { + return mipmaps; +} + +RID StreamTexture3D::get_rid() const { + if (!texture.is_valid()) { + texture = RS::get_singleton()->texture_3d_placeholder_create(); + } + return texture; +} + +Vector<Ref<Image>> StreamTexture3D::get_data() const { + if (texture.is_valid()) { + return RS::get_singleton()->texture_3d_get(texture); + } else { + return Vector<Ref<Image>>(); + } +} + +void StreamTexture3D::reload_from_file() { + String path = get_path(); + if (!path.is_resource_file()) { + return; + } + + path = ResourceLoader::path_remap(path); //remap for translation + path = ResourceLoader::import_remap(path); //remap for import + if (!path.is_resource_file()) { + return; + } + + load(path); +} + +void StreamTexture3D::_validate_property(PropertyInfo &property) const { +} + +void StreamTexture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture3D::load); + ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture3D::get_load_path); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); +} + +StreamTexture3D::StreamTexture3D() {} + +StreamTexture3D::~StreamTexture3D() { + if (texture.is_valid()) { + RS::get_singleton()->free(texture); + } +} + +///////////////////////////// + +RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + Ref<StreamTexture3D> st; + st.instance(); + Error err = st->load(p_path); + if (r_error) { + *r_error = err; + } + if (err != OK) { + return RES(); + } + + return st; +} + +void ResourceFormatLoaderStreamTexture3D::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("stex3d"); +} + +bool ResourceFormatLoaderStreamTexture3D::handles_type(const String &p_type) const { + return p_type == "StreamTexture3D"; +} + +String ResourceFormatLoaderStreamTexture3D::get_resource_type(const String &p_path) const { + if (p_path.get_extension().to_lower() == "stex3d") { + return "StreamTexture3D"; + } + return ""; +} + +//////////////////////////////////////////// + int AtlasTexture::get_width() const { if (region.size.width == 0) { if (atlas.is_valid()) { @@ -838,7 +1110,6 @@ void AtlasTexture::set_atlas(const Ref<Texture2D> &p_atlas) { } atlas = p_atlas; emit_changed(); - _change_notify("atlas"); } Ref<Texture2D> AtlasTexture::get_atlas() const { @@ -851,7 +1122,6 @@ void AtlasTexture::set_region(const Rect2 &p_region) { } region = p_region; emit_changed(); - _change_notify("region"); } Rect2 AtlasTexture::get_region() const { @@ -864,7 +1134,6 @@ void AtlasTexture::set_margin(const Rect2 &p_margin) { } margin = p_margin; emit_changed(); - _change_notify("margin"); } Rect2 AtlasTexture::get_margin() const { @@ -874,7 +1143,6 @@ Rect2 AtlasTexture::get_margin() const { void AtlasTexture::set_filter_clip(const bool p_enable) { filter_clip = p_enable; emit_changed(); - _change_notify("filter_clip"); } bool AtlasTexture::has_filter_clip() const { @@ -900,7 +1168,7 @@ void AtlasTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip"); } -void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if (!atlas.is_valid()) { return; } @@ -915,12 +1183,10 @@ void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_m rc.size.height = atlas->get_height(); } - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat); + RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, filter_clip); } -void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if (!atlas.is_valid()) { return; } @@ -938,12 +1204,10 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile Vector2 scale = p_rect.size / (region.size + margin.size); Rect2 dr(p_rect.position + margin.position * scale, rc.size * scale); - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat); + RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, filter_clip); } -void AtlasTexture::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<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { //this might not necessarily work well if using a rect, needs to be fixed properly if (!atlas.is_valid()) { return; @@ -953,9 +1217,7 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons Rect2 src_c; get_rect_region(p_rect, p_src_rect, dr, src_c); - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat); + RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, filter_clip); } bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { @@ -972,7 +1234,7 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Vector2 scale = p_rect.size / src.size; src.position += (rc.position - margin.position); - Rect2 src_c = rc.clip(src); + Rect2 src_c = rc.intersection(src); if (src_c.size == Size2()) { return false; } @@ -1014,9 +1276,7 @@ bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const { return atlas->is_pixel_opaque(x, y); } -AtlasTexture::AtlasTexture() { - filter_clip = false; -} +AtlasTexture::AtlasTexture() {} ///////////////////////////////////////// @@ -1060,7 +1320,7 @@ Ref<Texture2D> 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<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if (mesh.is_null() || base_texture.is_null()) { return; } @@ -1070,12 +1330,10 @@ void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_mo 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(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_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<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if (mesh.is_null() || base_texture.is_null()) { return; } @@ -1094,12 +1352,10 @@ void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, 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(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_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<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +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, bool p_clip_uv) const { if (mesh.is_null() || base_texture.is_null()) { return; } @@ -1118,9 +1374,7 @@ void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const 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(); - RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid()); } bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { @@ -1265,14 +1519,14 @@ void LargeTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); } -void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { for (int i = 0; i < pieces.size(); i++) { // TODO - pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose); } } -void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { //tiling not supported for this if (size.x == 0 || size.y == 0) { return; @@ -1282,11 +1536,11 @@ void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile for (int i = 0; i < pieces.size(); i++) { // TODO - pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.position, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, p_texture_filter, p_texture_repeat); + pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.position, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose); } } -void LargeTexture::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<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { //tiling not supported for this if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0) { return; @@ -1300,12 +1554,12 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons if (!p_src_rect.intersects(rect)) { continue; } - Rect2 local = p_src_rect.clip(rect); + Rect2 local = p_src_rect.intersection(rect); Rect2 target = local; target.size *= scale; target.position = p_rect.position + (p_src_rect.position + rect.position) * scale; local.position -= rect.position; - pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, p_texture_filter, p_texture_repeat, false); + pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, false); } } @@ -1423,9 +1677,7 @@ RID CurveTexture::get_rid() const { return _texture; } -CurveTexture::CurveTexture() { - _width = 2048; -} +CurveTexture::CurveTexture() {} CurveTexture::~CurveTexture() { if (_texture.is_valid()) { @@ -1435,16 +1687,7 @@ CurveTexture::~CurveTexture() { ////////////////// -//setter and getter names for property serialization -#define COLOR_RAMP_GET_OFFSETS "get_offsets" -#define COLOR_RAMP_GET_COLORS "get_colors" -#define COLOR_RAMP_SET_OFFSETS "set_offsets" -#define COLOR_RAMP_SET_COLORS "set_colors" - GradientTexture::GradientTexture() { - update_pending = false; - width = 2048; - _queue_update(); } @@ -1657,7 +1900,7 @@ void AnimatedTexture::_update_proxy() { } } time -= frame_limit; - _change_notify("current_frame"); + } else { break; } @@ -1859,28 +2102,12 @@ AnimatedTexture::AnimatedTexture() { proxy = RS::get_singleton()->texture_proxy_create(proxy_ph); RenderingServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true); - time = 0; - frame_count = 1; - fps = 4; - prev_ticks = 0; - current_frame = 0; - pause = false; - oneshot = false; RenderingServer::get_singleton()->connect("frame_pre_draw", callable_mp(this, &AnimatedTexture::_update_proxy)); - -#ifndef NO_THREADS - rw_lock = RWLock::create(); -#else - rw_lock = nullptr; -#endif } AnimatedTexture::~AnimatedTexture() { RS::get_singleton()->free(proxy); RS::get_singleton()->free(proxy_ph); - if (rw_lock) { - memdelete(rw_lock); - } } /////////////////////////////// @@ -1954,7 +2181,7 @@ Error ImageTextureLayered::create_from_images(Vector<Ref<Image>> p_images) { "Cubemap array layers must be a multiple of 6"); } - ERR_FAIL_COND_V(p_images[0].is_null() || p_images[0]->empty(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_images[0].is_null() || p_images[0]->is_empty(), ERR_INVALID_PARAMETER); Image::Format new_format = p_images[0]->get_format(); int new_width = p_images[0]->get_width(); @@ -2028,11 +2255,6 @@ void ImageTextureLayered::_bind_methods() { ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) { layered_type = p_layered_type; - format = Image::FORMAT_MAX; - - width = 0; - height = 0; - layers = 0; } ImageTextureLayered::~ImageTextureLayered() { @@ -2059,7 +2281,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER); FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); @@ -2079,7 +2301,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> uint32_t df = f->get_32(); //data format mipmap_limit = int(f->get_32()); - //reserverd + //reserved f->get_32(); f->get_32(); f->get_32(); @@ -2092,7 +2314,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> for (uint32_t i = 0; i < layer_count; i++) { Ref<Image> image = StreamTexture2D::load_image_from_file(f, p_size_limit); - ERR_FAIL_COND_V(image.is_null() || image->empty(), ERR_CANT_OPEN); + ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN); images.write[i] = image; } @@ -2129,7 +2351,7 @@ Error StreamTextureLayered::load(const String &p_path) { RenderingServer::get_singleton()->texture_set_path(texture, p_path); } - _change_notify(); + notify_property_list_changed(); emit_changed(); return OK; } @@ -2200,11 +2422,6 @@ void StreamTextureLayered::_bind_methods() { StreamTextureLayered::StreamTextureLayered(LayeredType p_type) { layered_type = p_type; - format = Image::FORMAT_MAX; - w = 0; - h = 0; - layers = 0; - mipmaps = false; } StreamTextureLayered::~StreamTextureLayered() { @@ -2215,7 +2432,7 @@ StreamTextureLayered::~StreamTextureLayered() { ///////////////////////////////////////////////// -RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<StreamTextureLayered> st; if (p_path.get_extension().to_lower() == "stexarray") { Ref<StreamTexture2DArray> s; @@ -2333,7 +2550,7 @@ Ref<Image> CameraTexture::get_data() const { void CameraTexture::set_camera_feed_id(int p_new_id) { camera_feed_id = p_new_id; - _change_notify(); + notify_property_list_changed(); } int CameraTexture::get_camera_feed_id() const { @@ -2342,7 +2559,7 @@ int CameraTexture::get_camera_feed_id() const { void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) { which_feed = p_which; - _change_notify(); + notify_property_list_changed(); } CameraServer::FeedImage CameraTexture::get_which_feed() const { @@ -2353,7 +2570,7 @@ 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(); + notify_property_list_changed(); } } @@ -2366,10 +2583,7 @@ bool CameraTexture::get_camera_active() const { } } -CameraTexture::CameraTexture() { - camera_feed_id = 0; - which_feed = CameraServer::FEED_RGBA_IMAGE; -} +CameraTexture::CameraTexture() {} CameraTexture::~CameraTexture() { // nothing to do here yet diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 005f899512..a0d917fd86 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,13 +31,13 @@ #ifndef TEXTURE_H #define TEXTURE_H +#include "core/io/resource.h" #include "core/io/resource_loader.h" #include "core/math/rect2.h" #include "core/os/file_access.h" #include "core/os/mutex.h" #include "core/os/rw_lock.h" #include "core/os/thread_safe.h" -#include "core/resource.h" #include "scene/resources/curve.h" #include "scene/resources/gradient.h" #include "servers/camera_server.h" @@ -61,15 +61,14 @@ public: virtual int get_width() const = 0; virtual int get_height() const = 0; virtual Size2 get_size() const; - virtual RID get_rid() const = 0; virtual bool is_pixel_opaque(int p_x, int p_y) const; virtual bool has_alpha() const = 0; - 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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; + 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; + 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, 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; virtual Ref<Image> get_data() const { return Ref<Image>(); } @@ -84,22 +83,23 @@ class ImageTexture : public Texture2D { RES_BASE_EXTENSION("tex"); mutable RID texture; - Image::Format format; - bool mipmaps; - int w, h; + Image::Format format = Image::FORMAT_L8; + bool mipmaps = false; + int w = 0; + int h = 0; Size2 size_override; mutable Ref<BitMap> alpha_cache; - bool image_stored; + bool image_stored = false; protected: - virtual void reload_from_file(); + virtual void reload_from_file() override; bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; void _reload_hook(const RID &p_hook); - virtual void _resource_path_changed(); + virtual void _resource_path_changed() override; static void _bind_methods(); public: @@ -108,23 +108,23 @@ public: Image::Format get_format() const; void update(const Ref<Image> &p_image, bool p_immediate = false); - Ref<Image> get_data() const; + Ref<Image> get_data() const override; - int get_width() const; - int get_height() const; + int get_width() const override; + int get_height() const override; - virtual RID get_rid() const; + virtual RID get_rid() const override; - bool has_alpha() 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const; + bool has_alpha() const override; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + 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 override; + 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, bool p_clip_uv = true) const override; - bool is_pixel_opaque(int p_x, int p_y) const; + bool is_pixel_opaque(int p_x, int p_y) const override; void set_size_override(const Size2 &p_size); - virtual void set_path(const String &p_path, bool p_take_over = false); + virtual void set_path(const String &p_path, bool p_take_over = false) override; ImageTexture(); ~ImageTexture(); @@ -161,11 +161,12 @@ private: Error _load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0); String path_to_file; mutable RID texture; - Image::Format format; - int w, h; + Image::Format format = Image::FORMAT_MAX; + int w = 0; + int h = 0; mutable Ref<BitMap> alpha_cache; - virtual void reload_from_file(); + virtual void reload_from_file() override; static void _requested_3d(void *p_ud); static void _requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel); @@ -173,7 +174,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const; + void _validate_property(PropertyInfo &property) const override; public: static Ref<Image> load_image_from_file(FileAccess *p_file, int p_size_limit); @@ -189,20 +190,20 @@ public: Error load(const String &p_path); String get_load_path() const; - int get_width() const; - int get_height() const; - virtual RID get_rid() const; + int get_width() const override; + int get_height() const override; + virtual RID get_rid() const override; - virtual void set_path(const String &p_path, bool p_take_over); + virtual void set_path(const String &p_path, bool p_take_over) override; - 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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 override; + 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 override; + 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, bool p_clip_uv = true) const override; - virtual bool has_alpha() const; - bool is_pixel_opaque(int p_x, int p_y) const; + virtual bool has_alpha() const override; + bool is_pixel_opaque(int p_x, int p_y) const override; - virtual Ref<Image> get_data() const; + virtual Ref<Image> get_data() const override; StreamTexture2D(); ~StreamTexture2D(); @@ -210,7 +211,7 @@ public: class ResourceFormatLoaderStreamTexture2D : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; @@ -224,16 +225,16 @@ protected: Ref<Texture2D> atlas; Rect2 region; Rect2 margin; - bool filter_clip; + bool filter_clip = false; static void _bind_methods(); public: - virtual int get_width() const; - virtual int get_height() const; - virtual RID get_rid() const; + virtual int get_width() const override; + virtual int get_height() const override; + virtual RID get_rid() const override; - virtual bool has_alpha() const; + virtual bool has_alpha() const override; void set_atlas(const Ref<Texture2D> &p_atlas); Ref<Texture2D> get_atlas() const; @@ -247,12 +248,12 @@ public: void set_filter_clip(const bool p_enable); bool has_filter_clip() 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, 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; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + 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 override; + 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, bool p_clip_uv = true) const override; + virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const override; - bool is_pixel_opaque(int p_x, int p_y) const; + bool is_pixel_opaque(int p_x, int p_y) const override; AtlasTexture(); }; @@ -271,11 +272,11 @@ protected: static void _bind_methods(); public: - virtual int get_width() const; - virtual int get_height() const; - virtual RID get_rid() const; + virtual int get_width() const override; + virtual int get_height() const override; + virtual RID get_rid() const override; - virtual bool has_alpha() const; + virtual bool has_alpha() const override; void set_mesh(const Ref<Mesh> &p_mesh); Ref<Mesh> get_mesh() const; @@ -286,12 +287,12 @@ public: void set_base_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, 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; + virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override; + 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 override; + 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, bool p_clip_uv = true) const override; + virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const override; - bool is_pixel_opaque(int p_x, int p_y) const; + bool is_pixel_opaque(int p_x, int p_y) const override; MeshTexture(); }; @@ -314,11 +315,11 @@ protected: static void _bind_methods(); public: - virtual int get_width() const; - virtual int get_height() const; - virtual RID get_rid() const; + virtual int get_width() const override; + virtual int get_height() const override; + virtual RID get_rid() const override; - virtual bool has_alpha() const; + virtual bool has_alpha() const override; int add_piece(const Point2 &p_offset, const Ref<Texture2D> &p_texture); void set_piece_offset(int p_idx, const Point2 &p_offset); @@ -332,11 +333,11 @@ public: Ref<Texture2D> 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) 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<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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 override; + 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 override; + 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, bool p_clip_uv = true) const override; - bool is_pixel_opaque(int p_x, int p_y) const; + bool is_pixel_opaque(int p_x, int p_y) const override; LargeTexture(); }; @@ -371,12 +372,12 @@ class ImageTextureLayered : public TextureLayered { LayeredType layered_type; mutable RID texture; - Image::Format format; + Image::Format format = Image::FORMAT_MAX; - int width; - int height; - int layers; - bool mipmaps; + int width = 0; + int height = 0; + int layers = 0; + bool mipmaps = false; Error _create_from_images(const Array &p_images); @@ -386,19 +387,19 @@ protected: static void _bind_methods(); public: - virtual Image::Format get_format() const; - virtual int get_width() const; - virtual int get_height() const; - virtual int get_layers() const; - virtual bool has_mipmaps() const; - virtual LayeredType get_layered_type() const; + virtual Image::Format get_format() const override; + virtual int get_width() const override; + virtual int get_height() const override; + virtual int get_layers() const override; + virtual bool has_mipmaps() const override; + virtual LayeredType get_layered_type() const override; Error create_from_images(Vector<Ref<Image>> p_images); void update_layer(const Ref<Image> &p_image, int p_layer); - virtual Ref<Image> get_layer_data(int p_layer) const; + virtual Ref<Image> get_layer_data(int p_layer) const override; - virtual RID get_rid() const; - virtual void set_path(const String &p_path, bool p_take_over = false); + virtual RID get_rid() const override; + virtual void set_path(const String &p_path, bool p_take_over = false) override; ImageTextureLayered(LayeredType p_layered_type); ~ImageTextureLayered(); @@ -454,32 +455,34 @@ private: Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0); String path_to_file; mutable RID texture; - Image::Format format; - int w, h, layers; - bool mipmaps; - LayeredType layered_type; + Image::Format format = Image::FORMAT_MAX; + int w = 0; + int h = 0; + int layers = 0; + bool mipmaps = false; + LayeredType layered_type = LayeredType::LAYERED_TYPE_2D_ARRAY; - virtual void reload_from_file(); + virtual void reload_from_file() override; protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const; + void _validate_property(PropertyInfo &property) const override; public: - Image::Format get_format() const; + Image::Format get_format() const override; Error load(const String &p_path); String get_load_path() const; - virtual LayeredType get_layered_type() const; + virtual LayeredType get_layered_type() const override; - int get_width() const; - int get_height() const; - int get_layers() const; - virtual bool has_mipmaps() const; - virtual RID get_rid() const; + int get_width() const override; + int get_height() const override; + int get_layers() const override; + virtual bool has_mipmaps() const override; + virtual RID get_rid() const override; - virtual void set_path(const String &p_path, bool p_take_over); + virtual void set_path(const String &p_path, bool p_take_over) override; - virtual Ref<Image> get_layer_data(int p_layer) const; + virtual Ref<Image> get_layer_data(int p_layer) const override; StreamTextureLayered(LayeredType p_layered_type); ~StreamTextureLayered(); @@ -510,7 +513,125 @@ public: class ResourceFormatLoaderStreamTextureLayered : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +class Texture3D : public Texture { + GDCLASS(Texture3D, Texture); + +protected: + static void _bind_methods(); + + TypedArray<Image> _get_data() const; + +public: + virtual Image::Format get_format() const = 0; + virtual int get_width() const = 0; + virtual int get_height() const = 0; + virtual int get_depth() const = 0; + virtual bool has_mipmaps() const = 0; + virtual Vector<Ref<Image>> get_data() const = 0; +}; + +class ImageTexture3D : public Texture3D { + GDCLASS(ImageTexture3D, Texture3D); + + mutable RID texture; + + Image::Format format = Image::FORMAT_MAX; + int width = 1; + int height = 1; + int depth = 1; + bool mipmaps = false; + +protected: + static void _bind_methods(); + + Error _create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data); + void _update(const TypedArray<Image> &p_data); + +public: + virtual Image::Format get_format() const override; + virtual int get_width() const override; + virtual int get_height() const override; + virtual int get_depth() const override; + virtual bool has_mipmaps() const override; + + Error create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data); + void update(const Vector<Ref<Image>> &p_data); + virtual Vector<Ref<Image>> get_data() const override; + + virtual RID get_rid() const override; + virtual void set_path(const String &p_path, bool p_take_over = false) override; + + ImageTexture3D(); + ~ImageTexture3D(); +}; + +class StreamTexture3D : public Texture3D { + GDCLASS(StreamTexture3D, Texture3D); + +public: + enum DataFormat { + DATA_FORMAT_IMAGE, + DATA_FORMAT_LOSSLESS, + DATA_FORMAT_LOSSY, + DATA_FORMAT_BASIS_UNIVERSAL, + }; + + enum { + FORMAT_VERSION = 1 + }; + + enum FormatBits { + FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1, + FORMAT_BIT_LOSSLESS = 1 << 20, + FORMAT_BIT_LOSSY = 1 << 21, + FORMAT_BIT_STREAM = 1 << 22, + FORMAT_BIT_HAS_MIPMAPS = 1 << 23, + }; + +private: + Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps); + String path_to_file; + mutable RID texture; + Image::Format format = Image::FORMAT_MAX; + int w = 0; + int h = 0; + int d = 0; + bool mipmaps = false; + + virtual void reload_from_file() override; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; + +public: + Image::Format get_format() const override; + Error load(const String &p_path); + String get_load_path() const; + + int get_width() const override; + int get_height() const override; + int get_depth() const override; + virtual bool has_mipmaps() const override; + virtual RID get_rid() const override; + + virtual void set_path(const String &p_path, bool p_take_over) override; + + virtual Vector<Ref<Image>> get_data() const override; + + StreamTexture3D(); + ~StreamTexture3D(); +}; + +class ResourceFormatLoaderStreamTexture3D : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; @@ -523,7 +644,7 @@ class CurveTexture : public Texture2D { private: mutable RID _texture; Ref<Curve> _curve; - int _width; + int _width = 2048; void _update(); @@ -532,24 +653,23 @@ protected: public: void set_width(int p_width); - int get_width() const; + int get_width() const override; void ensure_default_setup(float p_min = 0, float p_max = 1); void set_curve(Ref<Curve> p_curve); Ref<Curve> get_curve() const; - virtual RID get_rid() const; + virtual RID get_rid() const override; - virtual int get_height() const { return 1; } - virtual bool has_alpha() const { return false; } + virtual int get_height() const override { return 1; } + virtual bool has_alpha() const override { return false; } CurveTexture(); ~CurveTexture(); }; /* enum CubeMapSide { - CUBEMAP_LEFT, CUBEMAP_RIGHT, CUBEMAP_BOTTOM, @@ -566,7 +686,7 @@ class GradientTexture : public Texture2D { public: struct Point { - float offset; + float offset = 0.0; Color color; bool operator<(const Point &p_ponit) const { return offset < p_ponit.offset; @@ -575,9 +695,9 @@ public: private: Ref<Gradient> gradient; - bool update_pending; + bool update_pending = false; RID texture; - int width; + int width = 2048; void _queue_update(); void _update(); @@ -590,13 +710,13 @@ public: Ref<Gradient> get_gradient() const; void set_width(int p_width); - int get_width() const; + int get_width() const override; - virtual RID get_rid() const { return texture; } - virtual int get_height() const { return 1; } - virtual bool has_alpha() const { return true; } + virtual RID get_rid() const override { return texture; } + virtual int get_height() const override { return 1; } + virtual bool has_alpha() const override { return true; } - virtual Ref<Image> get_data() const; + virtual Ref<Image> get_data() const override; GradientTexture(); virtual ~GradientTexture(); @@ -617,11 +737,11 @@ public: void set_base(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_base() const; - virtual int get_width() const; - virtual int get_height() const; - virtual RID get_rid() const; + virtual int get_width() const override; + virtual int get_height() const override; + virtual RID get_rid() const override; - virtual bool has_alpha() const; + virtual bool has_alpha() const override; ProxyTexture(); ~ProxyTexture(); @@ -631,41 +751,38 @@ class AnimatedTexture : public Texture2D { GDCLASS(AnimatedTexture, Texture2D); //use readers writers lock for this, since its far more times read than written to - RWLock *rw_lock; + RWLock rw_lock; -private: +public: enum { MAX_FRAMES = 256 }; +private: RID proxy_ph; RID proxy; struct Frame { Ref<Texture2D> texture; - float delay_sec; - - Frame() { - delay_sec = 0; - } + float delay_sec = 0.0; }; Frame frames[MAX_FRAMES]; - int frame_count; - int current_frame; - bool pause; - bool oneshot; - float fps; + int frame_count = 1.0; + int current_frame = 0; + bool pause = false; + bool oneshot = false; + float fps = 4.0; - float time; + float time = 0.0; - uint64_t prev_ticks; + uint64_t prev_ticks = 0; void _update_proxy(); protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const; + void _validate_property(PropertyInfo &property) const override; public: void set_frames(int p_frames); @@ -689,15 +806,15 @@ public: void set_fps(float p_fps); float get_fps() const; - virtual int get_width() const; - virtual int get_height() const; - virtual RID get_rid() const; + virtual int get_width() const override; + virtual int get_height() const override; + virtual RID get_rid() const override; - virtual bool has_alpha() const; + virtual bool has_alpha() const override; - virtual Ref<Image> get_data() const; + virtual Ref<Image> get_data() const override; - bool is_pixel_opaque(int p_x, int p_y) const; + bool is_pixel_opaque(int p_x, int p_y) const override; AnimatedTexture(); ~AnimatedTexture(); @@ -707,22 +824,22 @@ class CameraTexture : public Texture2D { GDCLASS(CameraTexture, Texture2D); private: - int camera_feed_id; - CameraServer::FeedImage which_feed; + int camera_feed_id = 0; + CameraServer::FeedImage which_feed = CameraServer::FEED_RGBA_IMAGE; 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 int get_width() const override; + virtual int get_height() const override; + virtual RID get_rid() const override; + virtual bool has_alpha() const override; virtual void set_flags(uint32_t p_flags); virtual uint32_t get_flags() const; - virtual Ref<Image> get_data() const; + virtual Ref<Image> get_data() const override; void set_camera_feed_id(int p_new_id); int get_camera_feed_id() const; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 6a85d357ff..0405ea98bb 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,17 +30,17 @@ #include "theme.h" #include "core/os/file_access.h" -#include "core/print_string.h" +#include "core/string/print_string.h" void Theme::_emit_theme_changed() { emit_changed(); } -Vector<String> Theme::_get_icon_list(const String &p_type) const { +Vector<String> Theme::_get_icon_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; - get_icon_list(p_type, &il); + get_icon_list(p_node_type, &il); ilret.resize(il.size()); int i = 0; @@ -51,11 +51,11 @@ Vector<String> Theme::_get_icon_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_stylebox_list(const String &p_type) const { +Vector<String> Theme::_get_icon_type_list() const { Vector<String> ilret; List<StringName> il; - get_stylebox_list(p_type, &il); + get_icon_type_list(&il); ilret.resize(il.size()); int i = 0; @@ -66,11 +66,11 @@ Vector<String> Theme::_get_stylebox_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_stylebox_types() const { +Vector<String> Theme::_get_stylebox_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; - get_stylebox_types(&il); + get_stylebox_list(p_node_type, &il); ilret.resize(il.size()); int i = 0; @@ -81,11 +81,11 @@ Vector<String> Theme::_get_stylebox_types() const { return ilret; } -Vector<String> Theme::_get_font_list(const String &p_type) const { +Vector<String> Theme::_get_stylebox_type_list() const { Vector<String> ilret; List<StringName> il; - get_font_list(p_type, &il); + get_stylebox_type_list(&il); ilret.resize(il.size()); int i = 0; @@ -96,11 +96,11 @@ Vector<String> Theme::_get_font_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_color_list(const String &p_type) const { +Vector<String> Theme::_get_font_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; - get_color_list(p_type, &il); + get_font_list(p_node_type, &il); ilret.resize(il.size()); int i = 0; @@ -111,11 +111,11 @@ Vector<String> Theme::_get_color_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_constant_list(const String &p_type) const { +Vector<String> Theme::_get_font_type_list() const { Vector<String> ilret; List<StringName> il; - get_constant_list(p_type, &il); + get_font_type_list(&il); ilret.resize(il.size()); int i = 0; @@ -126,7 +126,82 @@ Vector<String> Theme::_get_constant_list(const String &p_type) const { return ilret; } -Vector<String> Theme::_get_type_list(const String &p_type) const { +Vector<String> Theme::_get_font_size_list(const String &p_node_type) const { + Vector<String> ilret; + List<StringName> il; + + get_font_size_list(p_node_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_color_list(const String &p_node_type) const { + Vector<String> ilret; + List<StringName> il; + + get_color_list(p_node_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_color_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_color_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_constant_list(const String &p_node_type) const { + Vector<String> ilret; + List<StringName> il; + + get_constant_list(p_node_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_constant_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_constant_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_type_list() const { Vector<String> ilret; List<StringName> il; @@ -283,7 +358,7 @@ void Theme::set_default_theme_font(const Ref<Font> &p_default_font) { default_theme_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -291,11 +366,27 @@ Ref<Font> Theme::get_default_theme_font() const { return default_theme_font; } +void Theme::set_default_theme_font_size(int p_font_size) { + if (default_theme_font_size == p_font_size) { + return; + } + + default_theme_font_size = p_font_size; + + notify_property_list_changed(); + emit_changed(); +} + +int Theme::get_default_theme_font_size() const { + return default_theme_font_size; +} + Ref<Theme> Theme::project_default_theme; Ref<Theme> Theme::default_theme; Ref<Texture2D> Theme::default_icon; Ref<StyleBox> Theme::default_style; Ref<Font> Theme::default_font; +int Theme::default_font_size = 16; Ref<Theme> Theme::get_default() { return default_theme; @@ -325,332 +416,374 @@ void Theme::set_default_font(const Ref<Font> &p_font) { default_font = p_font; } -void Theme::set_icon(const StringName &p_name, const StringName &p_type, const Ref<Texture2D> &p_icon) { +void Theme::set_default_font_size(int p_font_size) { + default_font_size = p_font_size; +} + +void Theme::set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon) { //ERR_FAIL_COND(p_icon.is_null()); - bool new_value = !icon_map.has(p_type) || !icon_map[p_type].has(p_name); + bool new_value = !icon_map.has(p_node_type) || !icon_map[p_node_type].has(p_name); - if (icon_map[p_type].has(p_name) && icon_map[p_type][p_name].is_valid()) { - icon_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) { + icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - icon_map[p_type][p_name] = p_icon; + icon_map[p_node_type][p_name] = p_icon; if (p_icon.is_valid()) { - icon_map[p_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + icon_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } -Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_type) const { - if (icon_map.has(p_type) && icon_map[p_type].has(p_name) && icon_map[p_type][p_name].is_valid()) { - return icon_map[p_type][p_name]; +Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_node_type) const { + if (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) { + return icon_map[p_node_type][p_name]; } else { return default_icon; } } -bool Theme::has_icon(const StringName &p_name, const StringName &p_type) const { - return (icon_map.has(p_type) && icon_map[p_type].has(p_name) && icon_map[p_type][p_name].is_valid()); +bool Theme::has_icon(const StringName &p_name, const StringName &p_node_type) const { + return (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()); } -void Theme::clear_icon(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!icon_map.has(p_type)); - ERR_FAIL_COND(!icon_map[p_type].has(p_name)); +void Theme::clear_icon(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!icon_map.has(p_node_type)); + ERR_FAIL_COND(!icon_map[p_node_type].has(p_name)); - if (icon_map[p_type][p_name].is_valid()) { - icon_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (icon_map[p_node_type][p_name].is_valid()) { + icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - icon_map[p_type].erase(p_name); + icon_map[p_node_type].erase(p_name); - _change_notify(); + notify_property_list_changed(); emit_changed(); } -void Theme::get_icon_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!icon_map.has(p_type)) { + if (!icon_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = icon_map[p_type].next(key))) { + while ((key = icon_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::set_shader(const StringName &p_name, const StringName &p_type, const Ref<Shader> &p_shader) { - bool new_value = !shader_map.has(p_type) || !shader_map[p_type].has(p_name); +void Theme::get_icon_type_list(List<StringName> *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = icon_map.next(key))) { + p_list->push_back(*key); + } +} - shader_map[p_type][p_name] = p_shader; +void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style) { + //ERR_FAIL_COND(p_style.is_null()); + + bool new_value = !style_map.has(p_node_type) || !style_map[p_node_type].has(p_name); + + if (style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) { + style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + + style_map[p_node_type][p_name] = p_style; + + if (p_style.is_valid()) { + style_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + } if (new_value) { - _change_notify(); - emit_changed(); + notify_property_list_changed(); } + emit_changed(); } -Ref<Shader> Theme::get_shader(const StringName &p_name, const StringName &p_type) const { - if (shader_map.has(p_type) && shader_map[p_type].has(p_name) && shader_map[p_type][p_name].is_valid()) { - return shader_map[p_type][p_name]; +Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_node_type) const { + if (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) { + return style_map[p_node_type][p_name]; } else { - return nullptr; + return default_style; } } -bool Theme::has_shader(const StringName &p_name, const StringName &p_type) const { - return (shader_map.has(p_type) && shader_map[p_type].has(p_name) && shader_map[p_type][p_name].is_valid()); +bool Theme::has_stylebox(const StringName &p_name, const StringName &p_node_type) const { + return (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()); } -void Theme::clear_shader(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!shader_map.has(p_type)); - ERR_FAIL_COND(!shader_map[p_type].has(p_name)); +void Theme::clear_stylebox(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!style_map.has(p_node_type)); + ERR_FAIL_COND(!style_map[p_node_type].has(p_name)); + + if (style_map[p_node_type][p_name].is_valid()) { + style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } - shader_map[p_type].erase(p_name); - _change_notify(); + style_map[p_node_type].erase(p_name); + + notify_property_list_changed(); emit_changed(); } -void Theme::get_shader_list(const StringName &p_type, List<StringName> *p_list) const { +void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!shader_map.has(p_type)) { + if (!style_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = shader_map[p_type].next(key))) { + while ((key = style_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::set_stylebox(const StringName &p_name, const StringName &p_type, const Ref<StyleBox> &p_style) { - //ERR_FAIL_COND(p_style.is_null()); +void Theme::get_stylebox_type_list(List<StringName> *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = style_map.next(key))) { + p_list->push_back(*key); + } +} + +void Theme::set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font) { + //ERR_FAIL_COND(p_font.is_null()); - bool new_value = !style_map.has(p_type) || !style_map[p_type].has(p_name); + bool new_value = !font_map.has(p_node_type) || !font_map[p_node_type].has(p_name); - if (style_map[p_type].has(p_name) && style_map[p_type][p_name].is_valid()) { - style_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (font_map[p_node_type][p_name].is_valid()) { + font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - style_map[p_type][p_name] = p_style; + font_map[p_node_type][p_name] = p_font; - if (p_style.is_valid()) { - style_map[p_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + if (p_font.is_valid()) { + font_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } if (new_value) { - _change_notify(); + notify_property_list_changed(); + emit_changed(); } - emit_changed(); } -Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_type) const { - if (style_map.has(p_type) && style_map[p_type].has(p_name) && style_map[p_type][p_name].is_valid()) { - return style_map[p_type][p_name]; +Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_node_type) const { + if (font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) { + return font_map[p_node_type][p_name]; + } else if (default_theme_font.is_valid()) { + return default_theme_font; } else { - return default_style; + return default_font; } } -bool Theme::has_stylebox(const StringName &p_name, const StringName &p_type) const { - return (style_map.has(p_type) && style_map[p_type].has(p_name) && style_map[p_type][p_name].is_valid()); +bool Theme::has_font(const StringName &p_name, const StringName &p_node_type) const { + return ((font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) || default_theme_font.is_valid()); } -void Theme::clear_stylebox(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!style_map.has(p_type)); - ERR_FAIL_COND(!style_map[p_type].has(p_name)); +void Theme::clear_font(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!font_map.has(p_node_type)); + ERR_FAIL_COND(!font_map[p_node_type].has(p_name)); - if (style_map[p_type][p_name].is_valid()) { - style_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + if (font_map[p_node_type][p_name].is_valid()) { + font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } - style_map[p_type].erase(p_name); - - _change_notify(); + font_map[p_node_type].erase(p_name); + notify_property_list_changed(); emit_changed(); } -void Theme::get_stylebox_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!style_map.has(p_type)) { + if (!font_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = style_map[p_type].next(key))) { + while ((key = font_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::get_stylebox_types(List<StringName> *p_list) const { +void Theme::get_font_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); const StringName *key = nullptr; - while ((key = style_map.next(key))) { + while ((key = font_map.next(key))) { p_list->push_back(*key); } } -void Theme::set_font(const StringName &p_name, const StringName &p_type, const Ref<Font> &p_font) { - //ERR_FAIL_COND(p_font.is_null()); +void Theme::set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size) { + bool new_value = !font_size_map.has(p_node_type) || !font_size_map[p_node_type].has(p_name); - bool new_value = !font_map.has(p_type) || !font_map[p_type].has(p_name); - - if (font_map[p_type][p_name].is_valid()) { - font_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - - font_map[p_type][p_name] = p_font; - - if (p_font.is_valid()) { - font_map[p_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); - } + font_size_map[p_node_type][p_name] = p_font_size; if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } -Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_type) const { - if (font_map.has(p_type) && font_map[p_type].has(p_name) && font_map[p_type][p_name].is_valid()) { - return font_map[p_type][p_name]; - } else if (default_theme_font.is_valid()) { - return default_theme_font; +int Theme::get_font_size(const StringName &p_name, const StringName &p_node_type) const { + if (font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name) && (font_size_map[p_node_type][p_name] > 0)) { + return font_size_map[p_node_type][p_name]; + } else if (default_theme_font_size > 0) { + return default_theme_font_size; } else { - return default_font; + return default_font_size; } } -bool Theme::has_font(const StringName &p_name, const StringName &p_type) const { - return (font_map.has(p_type) && font_map[p_type].has(p_name) && font_map[p_type][p_name].is_valid()); +bool Theme::has_font_size(const StringName &p_name, const StringName &p_node_type) const { + return ((font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name) && (font_size_map[p_node_type][p_name] > 0)) || (default_theme_font_size > 0)); } -void Theme::clear_font(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!font_map.has(p_type)); - ERR_FAIL_COND(!font_map[p_type].has(p_name)); - - if (font_map[p_type][p_name].is_valid()) { - font_map[p_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } +void Theme::clear_font_size(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!font_size_map.has(p_node_type)); + ERR_FAIL_COND(!font_size_map[p_node_type].has(p_name)); - font_map[p_type].erase(p_name); - _change_notify(); + font_size_map[p_node_type].erase(p_name); + notify_property_list_changed(); emit_changed(); } -void Theme::get_font_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_font_size_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!font_map.has(p_type)) { + if (!font_size_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = font_map[p_type].next(key))) { + while ((key = font_size_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::set_color(const StringName &p_name, const StringName &p_type, const Color &p_color) { - bool new_value = !color_map.has(p_type) || !color_map[p_type].has(p_name); +void Theme::set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color) { + bool new_value = !color_map.has(p_node_type) || !color_map[p_node_type].has(p_name); - color_map[p_type][p_name] = p_color; + color_map[p_node_type][p_name] = p_color; if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } -Color Theme::get_color(const StringName &p_name, const StringName &p_type) const { - if (color_map.has(p_type) && color_map[p_type].has(p_name)) { - return color_map[p_type][p_name]; +Color Theme::get_color(const StringName &p_name, const StringName &p_node_type) const { + if (color_map.has(p_node_type) && color_map[p_node_type].has(p_name)) { + return color_map[p_node_type][p_name]; } else { return Color(); } } -bool Theme::has_color(const StringName &p_name, const StringName &p_type) const { - return (color_map.has(p_type) && color_map[p_type].has(p_name)); +bool Theme::has_color(const StringName &p_name, const StringName &p_node_type) const { + return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name)); } -void Theme::clear_color(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!color_map.has(p_type)); - ERR_FAIL_COND(!color_map[p_type].has(p_name)); +void Theme::clear_color(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!color_map.has(p_node_type)); + ERR_FAIL_COND(!color_map[p_node_type].has(p_name)); - color_map[p_type].erase(p_name); - _change_notify(); + color_map[p_node_type].erase(p_name); + notify_property_list_changed(); emit_changed(); } -void Theme::get_color_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!color_map.has(p_type)) { + if (!color_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = color_map[p_type].next(key))) { + while ((key = color_map[p_node_type].next(key))) { p_list->push_back(*key); } } -void Theme::set_constant(const StringName &p_name, const StringName &p_type, int p_constant) { - bool new_value = !constant_map.has(p_type) || !constant_map[p_type].has(p_name); - constant_map[p_type][p_name] = p_constant; +void Theme::get_color_type_list(List<StringName> *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = color_map.next(key))) { + p_list->push_back(*key); + } +} + +void Theme::set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant) { + bool new_value = !constant_map.has(p_node_type) || !constant_map[p_node_type].has(p_name); + constant_map[p_node_type][p_name] = p_constant; if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } -int Theme::get_constant(const StringName &p_name, const StringName &p_type) const { - if (constant_map.has(p_type) && constant_map[p_type].has(p_name)) { - return constant_map[p_type][p_name]; +int Theme::get_constant(const StringName &p_name, const StringName &p_node_type) const { + if (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name)) { + return constant_map[p_node_type][p_name]; } else { return 0; } } -bool Theme::has_constant(const StringName &p_name, const StringName &p_type) const { - return (constant_map.has(p_type) && constant_map[p_type].has(p_name)); +bool Theme::has_constant(const StringName &p_name, const StringName &p_node_type) const { + return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name)); } -void Theme::clear_constant(const StringName &p_name, const StringName &p_type) { - ERR_FAIL_COND(!constant_map.has(p_type)); - ERR_FAIL_COND(!constant_map[p_type].has(p_name)); +void Theme::clear_constant(const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND(!constant_map.has(p_node_type)); + ERR_FAIL_COND(!constant_map[p_node_type].has(p_name)); - constant_map[p_type].erase(p_name); - _change_notify(); + constant_map[p_node_type].erase(p_name); + notify_property_list_changed(); emit_changed(); } -void Theme::get_constant_list(StringName p_type, List<StringName> *p_list) const { +void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); - if (!constant_map.has(p_type)) { + if (!constant_map.has(p_node_type)) { return; } const StringName *key = nullptr; - while ((key = constant_map[p_type].next(key))) { + while ((key = constant_map[p_node_type].next(key))) { + p_list->push_back(*key); + } +} + +void Theme::get_constant_type_list(List<StringName> *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = constant_map.next(key))) { p_list->push_back(*key); } } @@ -699,11 +832,10 @@ void Theme::clear() { icon_map.clear(); style_map.clear(); font_map.clear(); - shader_map.clear(); color_map.clear(); constant_map.clear(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -754,9 +886,8 @@ void Theme::copy_theme(const Ref<Theme> &p_other) { color_map = p_other->color_map; constant_map = p_other->constant_map; - shader_map = p_other->shader_map; - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -799,49 +930,66 @@ void Theme::get_type_list(List<StringName> *p_list) const { } } +void Theme::reset_state() { + clear(); +} void Theme::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_icon", "name", "type", "texture"), &Theme::set_icon); - ClassDB::bind_method(D_METHOD("get_icon", "name", "type"), &Theme::get_icon); - ClassDB::bind_method(D_METHOD("has_icon", "name", "type"), &Theme::has_icon); - ClassDB::bind_method(D_METHOD("clear_icon", "name", "type"), &Theme::clear_icon); - ClassDB::bind_method(D_METHOD("get_icon_list", "type"), &Theme::_get_icon_list); - - ClassDB::bind_method(D_METHOD("set_stylebox", "name", "type", "texture"), &Theme::set_stylebox); - ClassDB::bind_method(D_METHOD("get_stylebox", "name", "type"), &Theme::get_stylebox); - ClassDB::bind_method(D_METHOD("has_stylebox", "name", "type"), &Theme::has_stylebox); - ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "type"), &Theme::clear_stylebox); - ClassDB::bind_method(D_METHOD("get_stylebox_list", "type"), &Theme::_get_stylebox_list); - ClassDB::bind_method(D_METHOD("get_stylebox_types"), &Theme::_get_stylebox_types); - - ClassDB::bind_method(D_METHOD("set_font", "name", "type", "font"), &Theme::set_font); - ClassDB::bind_method(D_METHOD("get_font", "name", "type"), &Theme::get_font); - ClassDB::bind_method(D_METHOD("has_font", "name", "type"), &Theme::has_font); - ClassDB::bind_method(D_METHOD("clear_font", "name", "type"), &Theme::clear_font); - ClassDB::bind_method(D_METHOD("get_font_list", "type"), &Theme::_get_font_list); - - ClassDB::bind_method(D_METHOD("set_color", "name", "type", "color"), &Theme::set_color); - ClassDB::bind_method(D_METHOD("get_color", "name", "type"), &Theme::get_color); - ClassDB::bind_method(D_METHOD("has_color", "name", "type"), &Theme::has_color); - ClassDB::bind_method(D_METHOD("clear_color", "name", "type"), &Theme::clear_color); - ClassDB::bind_method(D_METHOD("get_color_list", "type"), &Theme::_get_color_list); - - ClassDB::bind_method(D_METHOD("set_constant", "name", "type", "constant"), &Theme::set_constant); - ClassDB::bind_method(D_METHOD("get_constant", "name", "type"), &Theme::get_constant); - ClassDB::bind_method(D_METHOD("has_constant", "name", "type"), &Theme::has_constant); - ClassDB::bind_method(D_METHOD("clear_constant", "name", "type"), &Theme::clear_constant); - ClassDB::bind_method(D_METHOD("get_constant_list", "type"), &Theme::_get_constant_list); + ClassDB::bind_method(D_METHOD("set_icon", "name", "node_type", "texture"), &Theme::set_icon); + ClassDB::bind_method(D_METHOD("get_icon", "name", "node_type"), &Theme::get_icon); + ClassDB::bind_method(D_METHOD("has_icon", "name", "node_type"), &Theme::has_icon); + ClassDB::bind_method(D_METHOD("clear_icon", "name", "node_type"), &Theme::clear_icon); + ClassDB::bind_method(D_METHOD("get_icon_list", "node_type"), &Theme::_get_icon_list); + ClassDB::bind_method(D_METHOD("get_icon_type_list"), &Theme::_get_icon_type_list); + + ClassDB::bind_method(D_METHOD("set_stylebox", "name", "node_type", "texture"), &Theme::set_stylebox); + ClassDB::bind_method(D_METHOD("get_stylebox", "name", "node_type"), &Theme::get_stylebox); + ClassDB::bind_method(D_METHOD("has_stylebox", "name", "node_type"), &Theme::has_stylebox); + ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "node_type"), &Theme::clear_stylebox); + ClassDB::bind_method(D_METHOD("get_stylebox_list", "node_type"), &Theme::_get_stylebox_list); + ClassDB::bind_method(D_METHOD("get_stylebox_type_list"), &Theme::_get_stylebox_type_list); + + ClassDB::bind_method(D_METHOD("set_font", "name", "node_type", "font"), &Theme::set_font); + ClassDB::bind_method(D_METHOD("get_font", "name", "node_type"), &Theme::get_font); + ClassDB::bind_method(D_METHOD("has_font", "name", "node_type"), &Theme::has_font); + ClassDB::bind_method(D_METHOD("clear_font", "name", "node_type"), &Theme::clear_font); + ClassDB::bind_method(D_METHOD("get_font_list", "node_type"), &Theme::_get_font_list); + ClassDB::bind_method(D_METHOD("get_font_type_list"), &Theme::_get_font_type_list); + + ClassDB::bind_method(D_METHOD("set_font_size", "name", "node_type", "font_size"), &Theme::set_font_size); + ClassDB::bind_method(D_METHOD("get_font_size", "name", "node_type"), &Theme::get_font_size); + ClassDB::bind_method(D_METHOD("has_font_size", "name", "node_type"), &Theme::has_font_size); + ClassDB::bind_method(D_METHOD("clear_font_size", "name", "node_type"), &Theme::clear_font_size); + ClassDB::bind_method(D_METHOD("get_font_size_list", "node_type"), &Theme::_get_font_size_list); + + ClassDB::bind_method(D_METHOD("set_color", "name", "node_type", "color"), &Theme::set_color); + ClassDB::bind_method(D_METHOD("get_color", "name", "node_type"), &Theme::get_color); + ClassDB::bind_method(D_METHOD("has_color", "name", "node_type"), &Theme::has_color); + ClassDB::bind_method(D_METHOD("clear_color", "name", "node_type"), &Theme::clear_color); + ClassDB::bind_method(D_METHOD("get_color_list", "node_type"), &Theme::_get_color_list); + ClassDB::bind_method(D_METHOD("get_color_type_list"), &Theme::_get_color_type_list); + + ClassDB::bind_method(D_METHOD("set_constant", "name", "node_type", "constant"), &Theme::set_constant); + ClassDB::bind_method(D_METHOD("get_constant", "name", "node_type"), &Theme::get_constant); + ClassDB::bind_method(D_METHOD("has_constant", "name", "node_type"), &Theme::has_constant); + ClassDB::bind_method(D_METHOD("clear_constant", "name", "node_type"), &Theme::clear_constant); + ClassDB::bind_method(D_METHOD("get_constant_list", "node_type"), &Theme::_get_constant_list); + ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list); ClassDB::bind_method(D_METHOD("clear"), &Theme::clear); ClassDB::bind_method(D_METHOD("set_default_font", "font"), &Theme::set_default_theme_font); ClassDB::bind_method(D_METHOD("get_default_font"), &Theme::get_default_theme_font); - ClassDB::bind_method(D_METHOD("get_type_list", "type"), &Theme::_get_type_list); + ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size); + ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size); + + ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list); 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"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size"), "set_default_font_size", "get_default_font_size"); } Theme::Theme() { diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 3c72ddd8a2..35481126ea 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,10 +31,9 @@ #ifndef THEME_H #define THEME_H +#include "core/io/resource.h" #include "core/io/resource_loader.h" -#include "core/resource.h" #include "scene/resources/font.h" -#include "scene/resources/shader.h" #include "scene/resources/style_box.h" #include "scene/resources/texture.h" @@ -47,17 +46,22 @@ class Theme : public Resource { HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map; HashMap<StringName, HashMap<StringName, Ref<StyleBox>>> style_map; HashMap<StringName, HashMap<StringName, Ref<Font>>> font_map; - HashMap<StringName, HashMap<StringName, Ref<Shader>>> shader_map; + HashMap<StringName, HashMap<StringName, int>> font_size_map; HashMap<StringName, HashMap<StringName, Color>> color_map; HashMap<StringName, HashMap<StringName, int>> constant_map; - Vector<String> _get_icon_list(const String &p_type) const; - Vector<String> _get_stylebox_list(const String &p_type) const; - Vector<String> _get_stylebox_types() const; - Vector<String> _get_font_list(const String &p_type) const; - Vector<String> _get_color_list(const String &p_type) const; - Vector<String> _get_constant_list(const String &p_type) const; - Vector<String> _get_type_list(const String &p_type) const; + Vector<String> _get_icon_list(const String &p_node_type) const; + Vector<String> _get_icon_type_list() const; + Vector<String> _get_stylebox_list(const String &p_node_type) const; + Vector<String> _get_stylebox_type_list() const; + Vector<String> _get_font_list(const String &p_node_type) const; + Vector<String> _get_font_type_list() const; + Vector<String> _get_font_size_list(const String &p_node_type) const; + Vector<String> _get_color_list(const String &p_node_type) const; + Vector<String> _get_color_type_list() const; + Vector<String> _get_constant_list(const String &p_node_type) const; + Vector<String> _get_constant_type_list() const; + Vector<String> _get_type_list() const; protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -69,11 +73,15 @@ protected: static Ref<Texture2D> default_icon; static Ref<StyleBox> default_style; static Ref<Font> default_font; + static int default_font_size; Ref<Font> default_theme_font; + int default_theme_font_size = -1; static void _bind_methods(); + virtual void reset_state() override; + public: static Ref<Theme> get_default(); static void set_default(const Ref<Theme> &p_default); @@ -84,46 +92,54 @@ public: static void set_default_icon(const Ref<Texture2D> &p_icon); static void set_default_style(const Ref<StyleBox> &p_style); static void set_default_font(const Ref<Font> &p_font); + static void set_default_font_size(int p_font_size); void set_default_theme_font(const Ref<Font> &p_default_font); Ref<Font> get_default_theme_font() const; - void set_icon(const StringName &p_name, const StringName &p_type, const Ref<Texture2D> &p_icon); - Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_type) const; - bool has_icon(const StringName &p_name, const StringName &p_type) const; - void clear_icon(const StringName &p_name, const StringName &p_type); - void get_icon_list(StringName p_type, List<StringName> *p_list) const; - - void set_shader(const StringName &p_name, const StringName &p_type, const Ref<Shader> &p_shader); - Ref<Shader> get_shader(const StringName &p_name, const StringName &p_type) const; - bool has_shader(const StringName &p_name, const StringName &p_type) const; - void clear_shader(const StringName &p_name, const StringName &p_type); - void get_shader_list(const StringName &p_type, List<StringName> *p_list) const; - - void set_stylebox(const StringName &p_name, const StringName &p_type, const Ref<StyleBox> &p_style); - Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_type) const; - bool has_stylebox(const StringName &p_name, const StringName &p_type) const; - void clear_stylebox(const StringName &p_name, const StringName &p_type); - void get_stylebox_list(StringName p_type, List<StringName> *p_list) const; - void get_stylebox_types(List<StringName> *p_list) const; - - void set_font(const StringName &p_name, const StringName &p_type, const Ref<Font> &p_font); - Ref<Font> get_font(const StringName &p_name, const StringName &p_type) const; - bool has_font(const StringName &p_name, const StringName &p_type) const; - void clear_font(const StringName &p_name, const StringName &p_type); - void get_font_list(StringName p_type, List<StringName> *p_list) const; - - void set_color(const StringName &p_name, const StringName &p_type, const Color &p_color); - Color get_color(const StringName &p_name, const StringName &p_type) const; - bool has_color(const StringName &p_name, const StringName &p_type) const; - void clear_color(const StringName &p_name, const StringName &p_type); - void get_color_list(StringName p_type, List<StringName> *p_list) const; - - void set_constant(const StringName &p_name, const StringName &p_type, int p_constant); - int get_constant(const StringName &p_name, const StringName &p_type) const; - bool has_constant(const StringName &p_name, const StringName &p_type) const; - void clear_constant(const StringName &p_name, const StringName &p_type); - void get_constant_list(StringName p_type, List<StringName> *p_list) const; + void set_default_theme_font_size(int p_font_size); + int get_default_theme_font_size() const; + + void set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon); + Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_node_type) const; + bool has_icon(const StringName &p_name, const StringName &p_node_type) const; + void clear_icon(const StringName &p_name, const StringName &p_node_type); + void get_icon_list(StringName p_node_type, List<StringName> *p_list) const; + void get_icon_type_list(List<StringName> *p_list) const; + + void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style); + Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const; + bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const; + void clear_stylebox(const StringName &p_name, const StringName &p_node_type); + void get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const; + void get_stylebox_type_list(List<StringName> *p_list) const; + + void set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font); + Ref<Font> get_font(const StringName &p_name, const StringName &p_node_type) const; + bool has_font(const StringName &p_name, const StringName &p_node_type) const; + void clear_font(const StringName &p_name, const StringName &p_node_type); + void get_font_list(StringName p_node_type, List<StringName> *p_list) const; + void get_font_type_list(List<StringName> *p_list) const; + + void set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size); + int get_font_size(const StringName &p_name, const StringName &p_node_type) const; + bool has_font_size(const StringName &p_name, const StringName &p_node_type) const; + void clear_font_size(const StringName &p_name, const StringName &p_node_type); + void get_font_size_list(StringName p_node_type, List<StringName> *p_list) const; + + void set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color); + Color get_color(const StringName &p_name, const StringName &p_node_type) const; + bool has_color(const StringName &p_name, const StringName &p_node_type) const; + void clear_color(const StringName &p_name, const StringName &p_node_type); + void get_color_list(StringName p_node_type, List<StringName> *p_list) const; + void get_color_type_list(List<StringName> *p_list) const; + + void set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant); + int get_constant(const StringName &p_name, const StringName &p_node_type) const; + bool has_constant(const StringName &p_name, const StringName &p_node_type) const; + void clear_constant(const StringName &p_name, const StringName &p_node_type); + void get_constant_list(StringName p_node_type, List<StringName> *p_list) const; + void get_constant_type_list(List<StringName> *p_list) const; void get_type_list(List<StringName> *p_list) const; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index c17b6f8817..84be69d0d6 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,8 +29,10 @@ /*************************************************************************/ #include "tile_set.h" -#include "core/array.h" -#include "core/engine.h" + +#include "core/config/engine.h" +#include "core/math/geometry_2d.h" +#include "core/variant/array.h" bool TileSet::_set(const StringName &p_name, const Variant &p_value) { String n = p_name; @@ -38,7 +40,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { if (slash == -1) { return false; } - int id = String::to_int(n.c_str(), slash); + int id = String::to_int(n.get_data(), slash); if (!tile_map.has(id)) { create_tile(id); @@ -49,8 +51,6 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { tile_set_name(id, p_value); } else if (what == "texture") { tile_set_texture(id, p_value); - } else if (what == "normal_map") { - tile_set_normal_map(id, p_value); } else if (what == "tex_offset") { tile_set_texture_offset(id, p_value); } else if (what == "material") { @@ -214,7 +214,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { if (slash == -1) { return false; } - int id = String::to_int(n.c_str(), slash); + int id = String::to_int(n.get_data(), slash); ERR_FAIL_COND_V(!tile_map.has(id), false); @@ -224,8 +224,6 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = tile_get_name(id); } else if (what == "texture") { r_ret = tile_get_texture(id); - } else if (what == "normal_map") { - r_ret = tile_get_normal_map(id); } else if (what == "tex_offset") { r_ret = tile_get_texture_offset(id); } else if (what == "material") { @@ -329,7 +327,6 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { String pre = itos(id) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, pre + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "tex_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); @@ -372,14 +369,14 @@ void TileSet::create_tile(int p_id) { ERR_FAIL_COND(tile_map.has(p_id)); tile_map[p_id] = TileData(); tile_map[p_id].autotile_data = AutotileData(); - _change_notify(""); + notify_property_list_changed(); emit_changed(); } void TileSet::autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].autotile_data.bitmask_mode = p_mode; - _change_notify(""); + notify_property_list_changed(); emit_changed(); } @@ -392,7 +389,6 @@ void TileSet::tile_set_texture(int p_id, const Ref<Texture2D> &p_texture) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].texture = p_texture; emit_changed(); - _change_notify("texture"); } Ref<Texture2D> TileSet::tile_get_texture(int p_id) const { @@ -400,17 +396,6 @@ Ref<Texture2D> TileSet::tile_get_texture(int p_id) const { return tile_map[p_id].texture; } -void TileSet::tile_set_normal_map(int p_id, const Ref<Texture2D> &p_normal_map) { - ERR_FAIL_COND(!tile_map.has(p_id)); - tile_map[p_id].normal_map = p_normal_map; - emit_changed(); -} - -Ref<Texture2D> TileSet::tile_get_normal_map(int p_id) const { - ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<Texture2D>()); - return tile_map[p_id].normal_map; -} - void TileSet::tile_set_material(int p_id, const Ref<ShaderMaterial> &p_material) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].material = p_material; @@ -426,7 +411,6 @@ void TileSet::tile_set_modulate(int p_id, const Color &p_modulate) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].modulate = p_modulate; emit_changed(); - _change_notify("modulate"); } Color TileSet::tile_get_modulate(int p_id) const { @@ -449,7 +433,6 @@ void TileSet::tile_set_region(int p_id, const Rect2 &p_region) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].region = p_region; emit_changed(); - _change_notify("region"); } Rect2 TileSet::tile_get_region(int p_id) const { @@ -461,7 +444,6 @@ void TileSet::tile_set_tile_mode(int p_id, TileMode p_tile_mode) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].tile_mode = p_tile_mode; emit_changed(); - _change_notify("tile_mode"); } TileSet::TileMode TileSet::tile_get_tile_mode(int p_id) const { @@ -683,7 +665,6 @@ void TileSet::tile_set_name(int p_id, const String &p_name) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].name = p_name; emit_changed(); - _change_notify("name"); } String TileSet::tile_get_name(int p_id) const { @@ -1033,7 +1014,7 @@ void TileSet::_decompose_convex_shape(Ref<Shape2D> p_shape) { if (!convex.is_valid()) { return; } - Vector<Vector<Vector2>> decomp = Geometry::decompose_polygon_in_convex(convex->get_points()); + Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(convex->get_points()); if (decomp.size() > 1) { Array sub_shapes; for (int i = 0; i < decomp.size(); i++) { @@ -1074,7 +1055,7 @@ bool TileSet::is_tile_bound(int p_drawn_id, int p_neighbor_id) { void TileSet::remove_tile(int p_id) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map.erase(p_id); - _change_notify(""); + notify_property_list_changed(); emit_changed(); } @@ -1095,9 +1076,13 @@ int TileSet::find_tile_by_name(const String &p_name) const { return -1; } +void TileSet::reset_state() { + clear(); +} + void TileSet::clear() { tile_map.clear(); - _change_notify(""); + notify_property_list_changed(); emit_changed(); } @@ -1126,8 +1111,6 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name); ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture"), &TileSet::tile_set_texture); ClassDB::bind_method(D_METHOD("tile_get_texture", "id"), &TileSet::tile_get_texture); - ClassDB::bind_method(D_METHOD("tile_set_normal_map", "id", "normal_map"), &TileSet::tile_set_normal_map); - ClassDB::bind_method(D_METHOD("tile_get_normal_map", "id"), &TileSet::tile_get_normal_map); ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material"), &TileSet::tile_set_material); ClassDB::bind_method(D_METHOD("tile_get_material", "id"), &TileSet::tile_get_material); ClassDB::bind_method(D_METHOD("tile_set_modulate", "id", "color"), &TileSet::tile_set_modulate); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 78f34e46ce..0a8721f35b 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,8 +31,8 @@ #ifndef TILE_SET_H #define TILE_SET_H -#include "core/array.h" -#include "core/resource.h" +#include "core/io/resource.h" +#include "core/variant/array.h" #include "scene/2d/light_occluder_2d.h" #include "scene/2d/navigation_region_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" @@ -106,7 +106,6 @@ private: struct TileData { String name; Ref<Texture2D> texture; - Ref<Texture2D> normal_map; Vector2 offset; Rect2i region; Vector<ShapeData> shapes_data; @@ -137,6 +136,8 @@ protected: static void _bind_methods(); + virtual void reset_state() override; + public: void create_tile(int p_id); @@ -149,9 +150,6 @@ public: void tile_set_texture(int p_id, const Ref<Texture2D> &p_texture); Ref<Texture2D> tile_get_texture(int p_id) const; - void tile_set_normal_map(int p_id, const Ref<Texture2D> &p_normal_map); - Ref<Texture2D> tile_get_normal_map(int p_id) const; - void tile_set_texture_offset(int p_id, const Vector2 &p_offset); Vector2 tile_get_texture_offset(int p_id) const; diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h index 379ba53a34..f960f85521 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 77d4dee21e..859546694f 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,9 +30,10 @@ #include "visual_shader.h" -#include "core/vmap.h" +#include "core/templates/vmap.h" #include "servers/rendering/shader_types.h" #include "visual_shader_nodes.h" +#include "visual_shader_sdf_nodes.h" bool VisualShaderNode::is_simple_decl() const { return simple_decl; @@ -63,6 +64,48 @@ bool VisualShaderNode::is_port_separator(int p_index) const { return false; } +bool VisualShaderNode::is_output_port_connected(int p_port) const { + if (connected_output_ports.has(p_port)) { + return connected_output_ports[p_port] > 0; + } + return false; +} + +void VisualShaderNode::set_output_port_connected(int p_port, bool p_connected) { + if (p_connected) { + connected_output_ports[p_port]++; + } else { + connected_output_ports[p_port]--; + } +} + +bool VisualShaderNode::is_input_port_connected(int p_port) const { + if (connected_input_ports.has(p_port)) { + return connected_input_ports[p_port]; + } + return false; +} + +void VisualShaderNode::set_input_port_connected(int p_port, bool p_connected) { + connected_input_ports[p_port] = p_connected; +} + +bool VisualShaderNode::is_generate_input_var(int p_port) const { + return true; +} + +bool VisualShaderNode::is_code_generated() const { + return true; +} + +bool VisualShaderNode::is_show_prop_names() const { + return false; +} + +bool VisualShaderNode::is_use_prop_slots() const { + return false; +} + Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { return Vector<VisualShader::DefaultTextureParam>(); } @@ -134,8 +177,6 @@ void VisualShaderNode::_bind_methods() { } VisualShaderNode::VisualShaderNode() { - port_preview = -1; - simple_decl = true; } ///////////////////////////////////////////////////////// @@ -281,6 +322,14 @@ VisualShaderNodeCustom::VisualShaderNodeCustom() { ///////////////////////////////////////////////////////// +void VisualShader::set_shader_type(Type p_type) { + current_type = p_type; +} + +VisualShader::Type VisualShader::get_shader_type() const { + return current_type; +} + void VisualShader::set_version(const String &p_version) { version = p_version; } @@ -429,6 +478,7 @@ void VisualShader::remove_node(Type p_type, int p_id) { g->connections.erase(E); if (E->get().from_node == p_id) { g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id); + g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false); } } E = N; @@ -437,6 +487,22 @@ void VisualShader::remove_node(Type p_type, int p_id) { _queue_update(); } +void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_class) { + ERR_FAIL_INDEX(p_type, TYPE_MAX); + ERR_FAIL_COND(p_id < 2); + Graph *g = &graph[p_type]; + ERR_FAIL_COND(!g->nodes.has(p_id)); + + if (g->nodes[p_id].node->get_class_name() == p_new_class) { + return; + } + VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(p_new_class)); + vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update)); + g->nodes[p_id].node = Ref<VisualShaderNode>(vsn); + + _queue_update(); +} + bool VisualShader::is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const { ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false); const Graph *g = &graph[p_type]; @@ -519,6 +585,12 @@ bool VisualShader::is_port_types_compatible(int p_a, int p_b) const { 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]; + + ERR_FAIL_COND(!g->nodes.has(p_from_node)); + ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_output_port_count()); + ERR_FAIL_COND(!g->nodes.has(p_to_node)); + ERR_FAIL_INDEX(p_to_port, g->nodes[p_to_node].node->get_input_port_count()); + Connection c; c.from_node = p_from_node; c.from_port = p_from_port; @@ -526,6 +598,8 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from c.to_port = p_to_port; g->connections.push_back(c); g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node); + g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true); + g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true); _queue_update(); } @@ -557,6 +631,8 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, c.to_port = p_to_port; g->connections.push_back(c); g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node); + g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true); + g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true); _queue_update(); return OK; @@ -570,6 +646,8 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { g->connections.erase(E); g->nodes[p_to_node].prev_connected_nodes.erase(p_from_node); + g->nodes[p_from_node].node->set_output_port_connected(p_from_port, false); + g->nodes[p_to_node].node->set_input_port_connected(p_to_port, false); _queue_update(); return; } @@ -603,6 +681,8 @@ void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connect } void VisualShader::set_mode(Mode p_mode) { + ERR_FAIL_INDEX_MSG(p_mode, Mode::MODE_MAX, vformat("Invalid shader mode: %d.", p_mode)); + if (shader_mode == p_mode) { return; } @@ -658,7 +738,7 @@ void VisualShader::set_mode(Mode p_mode) { } _queue_update(); - _change_notify(); + notify_property_list_changed(); } void VisualShader::set_graph_offset(const Vector2 &p_offset) { @@ -756,8 +836,12 @@ 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; +String VisualShader::validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const { + String name = p_port_name; + + if (name == String()) { + return String(); + } while (name.length() && !IS_INITIAL_CHAR(name[0])) { name = name.substr(1, name.length() - 1); @@ -775,29 +859,28 @@ String VisualShader::validate_port_name(const String &p_name, const List<String> } name = valid_name; + } else { + return String(); } - String valid_name = name; - bool is_equal = false; + List<String> input_names; + List<String> output_names; - for (int i = 0; i < p_input_ports.size(); i++) { - if (name == p_input_ports[i]) { - is_equal = true; - break; + for (int i = 0; i < p_node->get_input_port_count(); i++) { + if (!p_output && i == p_port_id) { + continue; } - } - - if (!is_equal) { - for (int i = 0; i < p_output_ports.size(); i++) { - if (name == p_output_ports[i]) { - is_equal = true; - break; - } + if (name == p_node->get_input_port_name(i)) { + return String(); } } - - if (is_equal) { - name = ""; + for (int i = 0; i < p_node->get_output_port_count(); i++) { + if (p_output && i == p_port_id) { + continue; + } + if (name == p_node->get_output_port_name(i)) { + return String(); + } } return name; @@ -875,8 +958,12 @@ VisualShader::RenderModeEnums VisualShader::render_mode_enums[] = { static const char *type_string[VisualShader::TYPE_MAX] = { "vertex", "fragment", - "light" + "light", + "emit", + "process", + "end" }; + bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; if (name == "mode") { @@ -933,7 +1020,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { set_node_position(type, id, p_value); return true; } else if (what == "size") { - ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_size(p_value); + ((VisualShaderNodeResizableBase *)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); @@ -1000,7 +1087,7 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_node_position(type, id); return true; } else if (what == "size") { - r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_size(); + r_ret = ((VisualShaderNodeResizableBase *)get_node(type, id).ptr())->get_size(); return true; } else if (what == "input_ports") { r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_inputs(); @@ -1016,6 +1103,12 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const { return false; } +void VisualShader::reset_state() { +#ifndef _MSC_VER +#warning everything needs to be cleared here +#endif + emit_changed(); +} void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const { //mode p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky")); @@ -1105,6 +1198,38 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui // then this node + Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node); + for (int i = 0; i < params.size(); i++) { + def_tex_params.push_back(params[i]); + } + + Ref<VisualShaderNodeInput> input = vsnode; + bool skip_global = input.is_valid() && for_preview; + + if (!skip_global) { + Ref<VisualShaderNodeUniform> uniform = vsnode; + if (!uniform.is_valid() || !uniform->is_global_code_generated()) { + global_code += vsnode->generate_global(get_mode(), type, node); + } + + String class_name = vsnode->get_class_name(); + if (class_name == "VisualShaderNodeCustom") { + class_name = vsnode->get_script_instance()->get_script()->get_path(); + } + if (!r_classes.has(class_name)) { + global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node); + for (int i = 0; i < TYPE_MAX; i++) { + global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node); + } + r_classes.insert(class_name); + } + } + + if (!vsnode->is_code_generated()) { // just generate globals and ignore locals + processed.insert(node); + return OK; + } + code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n"; Vector<String> input_vars; @@ -1152,9 +1277,9 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_SCALAR_INT) { inputs[i] = src_var + " > 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"; + inputs[i] = "(" + src_var + " ? 1.0 : 0.0)"; } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR_INT && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { - inputs[i] = src_var + " ? 1 : 0"; + inputs[i] = "(" + src_var + " ? 1 : 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 if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_SCALAR_INT) { @@ -1163,6 +1288,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui inputs[i] = "int(" + src_var + ")"; } } else { + if (!vsnode->is_generate_input_var(i)) { + continue; + } + Variant defval = vsnode->get_input_port_default_value(i); if (defval.get_type() == Variant::FLOAT) { float val = defval; @@ -1255,44 +1384,33 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } } - Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node); - for (int i = 0; i < params.size(); i++) { - def_tex_params.push_back(params[i]); - } + code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); - Ref<VisualShaderNodeInput> input = vsnode; - bool skip_global = input.is_valid() && for_preview; + code += "\n"; // + processed.insert(node); - if (!skip_global) { - global_code += vsnode->generate_global(get_mode(), type, node); + return OK; +} - String class_name = vsnode->get_class_name(); - if (class_name == "VisualShaderNodeCustom") { - class_name = vsnode->get_script_instance()->get_script()->get_language()->get_global_class_name(vsnode->get_script_instance()->get_script()->get_path()); - } - if (!r_classes.has(class_name)) { - global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node); - for (int i = 0; i < TYPE_MAX; i++) { - global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node); +bool VisualShader::has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const { + if (!ShaderTypes::get_singleton()->get_functions(p_mode).has(p_func_name)) { + if (p_mode == RenderingServer::ShaderMode::SHADER_PARTICLES) { + if (p_func_name == "emit" || p_func_name == "process" || p_func_name == "end") { + return true; } - r_classes.insert(class_name); } + return false; } - code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); - - code += "\n"; // - processed.insert(node); - - return OK; + return true; } void VisualShader::_update_shader() const { - if (!dirty) { + if (!dirty.is_set()) { return; } - dirty = false; + dirty.clear(); StringBuilder global_code; StringBuilder global_code_per_node; @@ -1310,10 +1428,19 @@ void VisualShader::_update_shader() const { { //fill render mode enums int idx = 0; + bool specular = false; while (render_mode_enums[idx].string) { if (shader_mode == render_mode_enums[idx].mode) { - if (modes.has(render_mode_enums[idx].string)) { - int which = modes[render_mode_enums[idx].string]; + if (shader_mode == Shader::MODE_SPATIAL) { + if (String(render_mode_enums[idx].string) == "specular") { + specular = true; + } + } + if (modes.has(render_mode_enums[idx].string) || specular) { + int which = 0; + if (modes.has(render_mode_enums[idx].string)) { + which = modes[render_mode_enums[idx].string]; + } int count = 0; for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) { String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i]; @@ -1349,11 +1476,14 @@ void VisualShader::_update_shader() const { global_code += "render_mode " + render_mode + ";\n\n"; } - static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" }; + static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "emit", "process", "end" }; String global_expressions; + Set<String> used_uniform_names; + List<VisualShaderNodeUniform *> uniforms; + for (int i = 0, index = 0; i < TYPE_MAX; i++) { - if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) { + if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) { continue; } @@ -1367,11 +1497,31 @@ void VisualShader::_update_shader() const { expr += "\n"; global_expressions += expr; } + Ref<VisualShaderNodeUniformRef> uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().node.ptr()); + if (uniform_ref.is_valid()) { + used_uniform_names.insert(uniform_ref->get_uniform_name()); + } + Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(E->get().node.ptr()); + if (uniform.is_valid()) { + uniforms.push_back(uniform.ptr()); + } + } + } + + for (int i = 0; i < uniforms.size(); i++) { + VisualShaderNodeUniform *uniform = uniforms[i]; + if (used_uniform_names.has(uniform->get_uniform_name())) { + global_code += uniform->generate_global(get_mode(), Type(i), -1); + const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(true); + } else { + const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(false); } } + Map<int, String> code_map; + for (int i = 0; i < TYPE_MAX; i++) { - if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) { + if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) { continue; } @@ -1379,6 +1529,8 @@ void VisualShader::_update_shader() const { VMap<ConnectionKey, const List<Connection>::Element *> input_connections; VMap<ConnectionKey, const List<Connection>::Element *> output_connections; + StringBuilder func_code; + for (const List<Connection>::Element *E = graph[i].connections.front(); E; E = E->next()) { ConnectionKey from_key; from_key.node = E->get().from_node; @@ -1392,14 +1544,30 @@ void VisualShader::_update_shader() const { input_connections.insert(to_key, E); } - - code += "\nvoid " + String(func_name[i]) + "() {\n"; + if (shader_mode != Shader::MODE_PARTICLES) { + func_code += "\nvoid " + String(func_name[i]) + "() {\n"; + } + insertion_pos.insert(i, code.get_string_length() + func_code.get_string_length()); Set<int> processed; - Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes); + Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes); ERR_FAIL_COND(err != OK); - insertion_pos.insert(i, code.get_string_length()); + if (shader_mode == Shader::MODE_PARTICLES) { + code_map.insert(i, func_code); + } else { + func_code += "}\n"; + code += func_code; + } + } + + if (shader_mode == Shader::MODE_PARTICLES) { + code += "\nvoid compute() {\n"; + code += "\tif (RESTART) {\n"; + code += code_map[TYPE_EMIT]; + code += "\t} else {\n"; + code += code_map[TYPE_PROCESS]; + code += "\t}\n"; code += "}\n"; } @@ -1410,7 +1578,7 @@ void VisualShader::_update_shader() const { final_code += global_expressions; String tcode = code; for (int i = 0; i < TYPE_MAX; i++) { - if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) { + if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) { continue; } tcode = tcode.insert(insertion_pos[i], global_code_per_func[Type(i)]); @@ -1428,15 +1596,16 @@ void VisualShader::_update_shader() const { } void VisualShader::_queue_update() { - if (dirty) { + if (dirty.is_set()) { return; } - dirty = true; + dirty.set(); call_deferred("_update_shader"); } void VisualShader::_input_type_changed(Type p_type, int p_id) { + ERR_FAIL_INDEX(p_type, TYPE_MAX); //erase connections using this input, as type changed Graph *g = &graph[p_type]; @@ -1451,7 +1620,7 @@ void VisualShader::_input_type_changed(Type p_type, int p_id) { } void VisualShader::rebuild() { - dirty = true; + dirty.set(); _update_shader(); } @@ -1468,6 +1637,7 @@ void VisualShader::_bind_methods() { 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("replace_node", "type", "id", "new_class"), &VisualShader::replace_node); 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::can_connect_nodes); @@ -1489,9 +1659,14 @@ void VisualShader::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "version", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_version", "get_version"); + ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs. + BIND_ENUM_CONSTANT(TYPE_VERTEX); BIND_ENUM_CONSTANT(TYPE_FRAGMENT); BIND_ENUM_CONSTANT(TYPE_LIGHT); + BIND_ENUM_CONSTANT(TYPE_EMIT); + BIND_ENUM_CONSTANT(TYPE_PROCESS); + BIND_ENUM_CONSTANT(TYPE_END); BIND_ENUM_CONSTANT(TYPE_MAX); BIND_CONSTANT(NODE_ID_INVALID); @@ -1499,8 +1674,7 @@ void VisualShader::_bind_methods() { } VisualShader::VisualShader() { - shader_mode = Shader::MODE_SPATIAL; - + dirty.set(); for (int i = 0; i < TYPE_MAX; i++) { Ref<VisualShaderNodeOutput> output; output.instance(); @@ -1509,8 +1683,6 @@ VisualShader::VisualShader() { graph[i].nodes[NODE_ID_OUTPUT].node = output; graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150); } - - dirty = true; } /////////////////////////////////////////////////////////// @@ -1571,12 +1743,13 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "view", "VIEW" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_color", "LIGHT_COLOR" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "attenuation", "ATTENUATION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "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, "backlight", "BACKLIGHT" }, { 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_SCALAR, "metallic", "METALLIC" }, { 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" }, @@ -1588,17 +1761,17 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, // 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, "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" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "extra", "EXTRA_MATRIX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "canvas", "CANVAS_MATRIX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "screen", "SCREEN_MATRIX" }, { 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)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" }, // 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)" }, @@ -1609,46 +1782,79 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { 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)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_texture", "NORMAL_TEXTURE" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "specular_shininess", "SPECULAR_SHININESS.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" }, // 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" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_vec", "vec3(LIGHT_VEC, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_height", "LIGHT_HEIGHT" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_color", "LIGHT_COLOR.rgb" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "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_SCALAR, "shadow_alpha", "SHADOW_COLOR.a" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "shadow_vec", "vec3(SHADOW_VEC, 0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_color_alpha", "LIGHT_COLOR.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_position", "LIGHT_POSITION" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_vertex", "LIGHT_VERTEX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "shadow_color", "SHADOW_MODULATE.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "shadow_alpha", "SHADOW_MODULATE.a" }, { 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, "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" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" }, - - // 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" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, - - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, - - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular_shininess", "SPECULAR_SHININESS.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" }, + + // Particles, Emit + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + // Particles, Process + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + // Particles, End + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Sky, Fragment { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" }, @@ -1685,7 +1891,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { }; const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { - // Spatial, Fragment { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0, 1.0, 0.0)" }, @@ -1699,7 +1904,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { 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, "viewport_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)" }, @@ -1791,7 +1996,7 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T code = "\t" + p_output_vars[0] + " = vec3(0.0);\n"; } break; 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"; + 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; case PORT_TYPE_BOOLEAN: { code = "\t" + p_output_vars[0] + " = false;\n"; @@ -1950,10 +2155,218 @@ void VisualShaderNodeInput::_bind_methods() { } VisualShaderNodeInput::VisualShaderNodeInput() { - input_name = "[None]"; - // changed when set - shader_type = VisualShader::TYPE_MAX; - shader_mode = Shader::MODE_MAX; +} + +////////////// UniformRef + +List<VisualShaderNodeUniformRef::Uniform> uniforms; + +void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) { + uniforms.push_back({ p_name, p_type }); +} + +void VisualShaderNodeUniformRef::clear_uniforms() { + uniforms.clear(); +} + +bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) { + for (List<VisualShaderNodeUniformRef::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().name == p_name) { + return true; + } + } + return false; +} + +String VisualShaderNodeUniformRef::get_caption() const { + return "UniformRef"; +} + +int VisualShaderNodeUniformRef::get_input_port_count() const { + return 0; +} + +VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_input_port_type(int p_port) const { + return PortType::PORT_TYPE_SCALAR; +} + +String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeUniformRef::get_output_port_count() const { + switch (uniform_type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return 1; + case UniformType::UNIFORM_TYPE_INT: + return 1; + case UniformType::UNIFORM_TYPE_BOOLEAN: + return 1; + case UniformType::UNIFORM_TYPE_VECTOR: + return 1; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return 1; + case UniformType::UNIFORM_TYPE_COLOR: + return 2; + case UniformType::UNIFORM_TYPE_SAMPLER: + return 1; + default: + break; + } + return 1; +} + +VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const { + switch (uniform_type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return PortType::PORT_TYPE_SCALAR; + case UniformType::UNIFORM_TYPE_INT: + return PortType::PORT_TYPE_SCALAR_INT; + case UniformType::UNIFORM_TYPE_BOOLEAN: + return PortType::PORT_TYPE_BOOLEAN; + case UniformType::UNIFORM_TYPE_VECTOR: + return PortType::PORT_TYPE_VECTOR; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return PortType::PORT_TYPE_TRANSFORM; + case UniformType::UNIFORM_TYPE_COLOR: + if (p_port == 0) { + return PortType::PORT_TYPE_VECTOR; + } else if (p_port == 1) { + return PORT_TYPE_SCALAR; + } + break; + case UniformType::UNIFORM_TYPE_SAMPLER: + return PortType::PORT_TYPE_SAMPLER; + default: + break; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const { + switch (uniform_type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return ""; + case UniformType::UNIFORM_TYPE_INT: + return ""; + case UniformType::UNIFORM_TYPE_BOOLEAN: + return ""; + case UniformType::UNIFORM_TYPE_VECTOR: + return ""; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return ""; + case UniformType::UNIFORM_TYPE_COLOR: + if (p_port == 0) { + return "rgb"; + } else if (p_port == 1) { + return "alpha"; + } + break; + case UniformType::UNIFORM_TYPE_SAMPLER: + return ""; + break; + default: + break; + } + return ""; +} + +void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) { + uniform_name = p_name; + if (uniform_name != "[None]") { + uniform_type = get_uniform_type_by_name(uniform_name); + } else { + uniform_type = UniformType::UNIFORM_TYPE_FLOAT; + } + emit_changed(); +} + +String VisualShaderNodeUniformRef::get_uniform_name() const { + return uniform_name; +} + +int VisualShaderNodeUniformRef::get_uniforms_count() const { + return uniforms.size(); +} + +String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < uniforms.size()) { + return uniforms[p_idx].name; + } + return ""; +} + +VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const { + for (int i = 0; i < uniforms.size(); i++) { + if (uniforms[i].name == p_name) { + return uniforms[i].type; + } + } + return UniformType::UNIFORM_TYPE_FLOAT; +} + +VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < uniforms.size()) { + return uniforms[p_idx].type; + } + return UniformType::UNIFORM_TYPE_FLOAT; +} + +String VisualShaderNodeUniformRef::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 { + switch (uniform_type) { + case UniformType::UNIFORM_TYPE_FLOAT: + if (uniform_name == "[None]") { + return "\t" + p_output_vars[0] + " = 0.0;\n"; + } + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_INT: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_BOOLEAN: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_VECTOR: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + case UniformType::UNIFORM_TYPE_COLOR: { + 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; + } break; + case UniformType::UNIFORM_TYPE_SAMPLER: + break; + default: + break; + } + return ""; +} + +void VisualShaderNodeUniformRef::_set_uniform_type(int p_uniform_type) { + uniform_type = (UniformType)p_uniform_type; +} + +int VisualShaderNodeUniformRef::_get_uniform_type() const { + return (int)uniform_type; +} + +void VisualShaderNodeUniformRef::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name); + ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name); + + ClassDB::bind_method(D_METHOD("_set_uniform_type", "type"), &VisualShaderNodeUniformRef::_set_uniform_type); + ClassDB::bind_method(D_METHOD("_get_uniform_type"), &VisualShaderNodeUniformRef::_get_uniform_type); + + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "uniform_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_uniform_type", "_get_uniform_type"); +} + +Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const { + Vector<StringName> props; + props.push_back("uniform_name"); + props.push_back("uniform_type"); + return props; +} + +VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() { } //////////////////////////////////////////// @@ -1980,8 +2393,8 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normalmap", "NORMALMAP" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal_map", "NORMAL_MAP" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim_tint", "RIM_TINT" }, @@ -1990,9 +2403,9 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "anisotropy", "ANISOTROPY" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "anisotropy_flow", "ANISOTROPY_FLOW:xy" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "subsurf_scatter", "SSS_STRENGTH" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "transmission", "TRANSMISSION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "backlight", "BACKLIGHT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor", "ALPHA_SCISSOR" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor_threshold", "ALPHA_SCISSOR_THRESHOLD" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" }, // Spatial, Light @@ -2007,18 +2420,35 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { 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, "normal", "NORMAL" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normalmap", "NORMALMAP" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal_map", "NORMAL_MAP" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" }, // Canvas Item, Light { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" }, - // 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" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + // Particles, Emit + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + // Particles, Process + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + // Particles, End + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, // Sky, Fragment { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" }, { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" }, @@ -2093,7 +2523,7 @@ String VisualShaderNodeOutput::get_output_port_name(int p_port) const { bool VisualShaderNodeOutput::is_port_separator(int p_index) const { if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) { String name = get_input_port_name(p_index); - return (name == "Normal" || name == "Rim" || name == "Alpha Scissor"); + return (name == "Normal" || name == "Rim" || name == "Alpha Scissor Threshold"); } return false; } @@ -2149,6 +2579,14 @@ VisualShaderNodeUniform::Qualifier VisualShaderNodeUniform::get_qualifier() cons return qualifier; } +void VisualShaderNodeUniform::set_global_code_generated(bool p_enabled) { + global_code_generated = p_enabled; +} + +bool VisualShaderNodeUniform::is_global_code_generated() const { + return global_code_generated; +} + void VisualShaderNodeUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name); ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name); @@ -2198,23 +2636,39 @@ Vector<StringName> VisualShaderNodeUniform::get_editable_properties() const { } VisualShaderNodeUniform::VisualShaderNodeUniform() { - qualifier = QUAL_NONE; } -////////////// GroupBase +////////////// ResizeableBase -String VisualShaderNodeGroupBase::get_caption() const { - return "Group"; -} - -void VisualShaderNodeGroupBase::set_size(const Vector2 &p_size) { +void VisualShaderNodeResizableBase::set_size(const Vector2 &p_size) { size = p_size; } -Vector2 VisualShaderNodeGroupBase::get_size() const { +Vector2 VisualShaderNodeResizableBase::get_size() const { return size; } +void VisualShaderNodeResizableBase::set_allow_v_resize(bool p_enabled) { + allow_v_resize = p_enabled; +} + +bool VisualShaderNodeResizableBase::is_allow_v_resize() const { + return allow_v_resize; +} + +void VisualShaderNodeResizableBase::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeResizableBase::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeResizableBase::get_size); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); +} + +VisualShaderNodeResizableBase::VisualShaderNodeResizableBase() { + set_allow_v_resize(true); +} + +////////////// GroupBase + void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) { if (inputs == p_inputs) { return; @@ -2330,6 +2784,7 @@ void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const Strin } _apply_port_changes(); + emit_changed(); } void VisualShaderNodeGroupBase::remove_input_port(int p_id) { @@ -2349,11 +2804,14 @@ void VisualShaderNodeGroupBase::remove_input_port(int p_id) { inputs.erase(index, count); inputs_strings = inputs.split(";", false); + inputs = inputs.substr(0, index); + for (int i = p_id; i < inputs_strings.size(); i++) { - inputs = inputs.replace_first(inputs_strings[i].split(",")[0], itos(i)); + inputs += inputs_strings[i].replace_first(inputs_strings[i].split(",")[0], itos(i)) + ";"; } _apply_port_changes(); + emit_changed(); } int VisualShaderNodeGroupBase::get_input_port_count() const { @@ -2398,6 +2856,7 @@ void VisualShaderNodeGroupBase::add_output_port(int p_id, int p_type, const Stri } _apply_port_changes(); + emit_changed(); } void VisualShaderNodeGroupBase::remove_output_port(int p_id) { @@ -2417,11 +2876,14 @@ void VisualShaderNodeGroupBase::remove_output_port(int p_id) { outputs.erase(index, count); outputs_strings = outputs.split(";", false); + outputs = outputs.substr(0, index); + for (int i = p_id; i < outputs_strings.size(); i++) { - outputs = outputs.replace_first(outputs_strings[i].split(",")[0], itos(i)); + outputs += outputs_strings[i].replace_first(outputs_strings[i].split(",")[0], itos(i)) + ";"; } _apply_port_changes(); + emit_changed(); } int VisualShaderNodeGroupBase::get_output_port_count() const { @@ -2468,6 +2930,7 @@ void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) { inputs = inputs.insert(index, itos(p_type)); _apply_port_changes(); + emit_changed(); } VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_input_port_type(int p_id) const { @@ -2503,6 +2966,7 @@ void VisualShaderNodeGroupBase::set_input_port_name(int p_id, const String &p_na inputs = inputs.insert(index, p_name); _apply_port_changes(); + emit_changed(); } String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const { @@ -2538,6 +3002,7 @@ void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) { outputs = outputs.insert(index, itos(p_type)); _apply_port_changes(); + emit_changed(); } VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_output_port_type(int p_id) const { @@ -2573,6 +3038,7 @@ void VisualShaderNodeGroupBase::set_output_port_name(int p_id, const String &p_n outputs = outputs.insert(index, p_name); _apply_port_changes(); + emit_changed(); } String VisualShaderNodeGroupBase::get_output_port_name(int p_id) const { @@ -2633,9 +3099,6 @@ bool VisualShaderNodeGroupBase::is_editable() const { } 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); @@ -2663,8 +3126,6 @@ void VisualShaderNodeGroupBase::_bind_methods() { 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); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); } 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 { @@ -2672,10 +3133,6 @@ String VisualShaderNodeGroupBase::generate_code(Shader::Mode p_mode, VisualShade } VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() { - size = Size2(0, 0); - inputs = ""; - outputs = ""; - editable = false; simple_decl = false; } @@ -2687,6 +3144,7 @@ String VisualShaderNodeExpression::get_caption() const { void VisualShaderNodeExpression::set_expression(const String &p_expression) { expression = p_expression; + emit_changed(); } String VisualShaderNodeExpression::get_expression() const { @@ -2700,7 +3158,7 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad _expression = _expression.replace("\n", "\n\t\t"); static Vector<String> pre_symbols; - if (pre_symbols.empty()) { + if (pre_symbols.is_empty()) { pre_symbols.push_back("\t"); pre_symbols.push_back(","); pre_symbols.push_back(";"); @@ -2720,7 +3178,7 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad } static Vector<String> post_symbols; - if (post_symbols.empty()) { + if (post_symbols.is_empty()) { post_symbols.push_back("\t"); post_symbols.push_back("\n"); post_symbols.push_back(","); @@ -2800,7 +3258,6 @@ void VisualShaderNodeExpression::_bind_methods() { } VisualShaderNodeExpression::VisualShaderNodeExpression() { - expression = ""; set_editable(true); } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 8bd09df512..ef724c7650 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,8 @@ #ifndef VISUAL_SHADER_H #define VISUAL_SHADER_H -#include "core/string_builder.h" +#include "core/string/string_builder.h" +#include "core/templates/safe_refcount.h" #include "scene/gui/control.h" #include "scene/resources/shader.h" @@ -50,14 +51,17 @@ public: TYPE_VERTEX, TYPE_FRAGMENT, TYPE_LIGHT, + TYPE_EMIT, + TYPE_PROCESS, + TYPE_END, TYPE_MAX }; struct Connection { - int from_node; - int from_port; - int to_node; - int to_port; + int from_node = 0; + int from_port = 0; + int to_node = 0; + int to_port = 0; }; struct DefaultTextureParam { @@ -66,6 +70,8 @@ public: }; private: + Type current_type; + struct Node { Ref<VisualShaderNode> node; Vector2 position; @@ -77,7 +83,7 @@ private: List<Connection> connections; } graph[TYPE_MAX]; - Shader::Mode shader_mode; + Shader::Mode shader_mode = Shader::MODE_SPATIAL; mutable String previous_code; Array _get_node_connections(Type p_type) const; @@ -85,7 +91,7 @@ private: Vector2 graph_offset; struct RenderModeEnums { - Shader::Mode mode; + Shader::Mode mode = Shader::Mode::MODE_MAX; const char *string; }; @@ -94,7 +100,7 @@ private: static RenderModeEnums render_mode_enums[]; - volatile mutable bool dirty; + mutable SafeFlag dirty; void _queue_update(); union ConnectionKey { @@ -102,7 +108,7 @@ private: uint64_t node : 32; uint64_t port : 32; }; - uint64_t key; + uint64_t key = 0; bool operator<(const ConnectionKey &p_key) const { return key < p_key.key; } @@ -111,15 +117,22 @@ private: Error _write_node(Type p_type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const; void _input_type_changed(Type p_type, int p_id); + bool has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const; protected: - virtual void _update_shader() const; + virtual void _update_shader() const override; static void _bind_methods(); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + +public: // internal methods + void set_shader_type(Type p_type); + Type get_shader_type() const; + public: void set_version(const String &p_version); String get_version() const; @@ -142,6 +155,7 @@ public: int find_node_id(Type p_type, const Ref<VisualShaderNode> &p_node) const; void remove_node(Type p_type, int p_id); + void replace_node(Type p_type, int p_id, const StringName &p_new_class); bool is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const; @@ -156,16 +170,16 @@ public: void get_node_connections(Type p_type, List<Connection> *r_connections) const; void set_mode(Mode p_mode); - virtual Mode get_mode() const; + virtual Mode get_mode() const override; - virtual bool is_text_shader() const; + virtual bool is_text_shader() const override; void set_graph_offset(const Vector2 &p_offset); Vector2 get_graph_offset() const; 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_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const; String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const; VisualShader(); @@ -179,12 +193,14 @@ VARIANT_ENUM_CAST(VisualShader::Type) class VisualShaderNode : public Resource { GDCLASS(VisualShaderNode, Resource); - int port_preview; + int port_preview = -1; Map<int, Variant> default_input_values; + Map<int, bool> connected_input_ports; + Map<int, int> connected_output_ports; protected: - bool simple_decl; + bool simple_decl = true; static void _bind_methods(); public: @@ -222,6 +238,16 @@ public: virtual bool is_port_separator(int p_index) const; + bool is_output_port_connected(int p_port) const; + void set_output_port_connected(int p_port, bool p_connected); + bool is_input_port_connected(int p_port) const; + void set_input_port_connected(int p_port, bool p_connected); + virtual bool is_generate_input_var(int p_port) const; + + virtual bool is_code_generated() const; + virtual bool is_show_prop_names() const; + virtual bool is_use_prop_slots() const; + virtual Vector<StringName> get_editable_properties() const; virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const; @@ -242,7 +268,7 @@ class VisualShaderNodeCustom : public VisualShaderNode { struct Port { String name; - int type; + int type = 0; }; List<Port> input_ports; @@ -251,19 +277,19 @@ class VisualShaderNodeCustom : public VisualShaderNode { friend class VisualShaderEditor; protected: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; protected: - 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; - virtual String generate_global_per_node(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 override; + virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; static void _bind_methods(); @@ -278,13 +304,13 @@ class VisualShaderNodeInput : public VisualShaderNode { GDCLASS(VisualShaderNodeInput, VisualShaderNode); friend class VisualShader; - VisualShader::Type shader_type; - Shader::Mode shader_mode; + VisualShader::Type shader_type = VisualShader::TYPE_MAX; + Shader::Mode shader_mode = Shader::MODE_MAX; struct Port { - Shader::Mode mode; - VisualShader::Type shader_type; - PortType type; + Shader::Mode mode = Shader::Mode::MODE_MAX; + VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX; + PortType type = PortType::PORT_TYPE_MAX; const char *name; const char *string; }; @@ -292,24 +318,24 @@ class VisualShaderNodeInput : public VisualShaderNode { static const Port ports[]; static const Port preview_ports[]; - String input_name; + String input_name = "[None]"; protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const; + void _validate_property(PropertyInfo &property) const override; public: - virtual int get_input_port_count() const; - virtual PortType get_input_port_type(int p_port) const; - virtual String get_input_port_name(int p_port) const; + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - virtual String get_caption() const; + virtual String get_caption() const override; - 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; + 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 override; void set_input_name(String p_name); String get_input_name() const; @@ -321,7 +347,7 @@ public: PortType get_input_type_by_name(String p_name) const; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeInput(); }; @@ -333,13 +359,13 @@ class VisualShaderNodeOutput : public VisualShaderNode { public: friend class VisualShader; - VisualShader::Type shader_type; - Shader::Mode shader_mode; + VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX; + Shader::Mode shader_mode = Shader::Mode::MODE_MAX; struct Port { - Shader::Mode mode; - VisualShader::Type shader_type; - PortType type; + Shader::Mode mode = Shader::Mode::MODE_MAX; + VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX; + PortType type = PortType::PORT_TYPE_MAX; const char *name; const char *string; }; @@ -347,20 +373,20 @@ public: static const Port ports[]; public: - virtual int get_input_port_count() const; - virtual PortType get_input_port_type(int p_port) const; - virtual String get_input_port_name(int p_port) const; + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; Variant get_input_port_default_value(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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - virtual bool is_port_separator(int p_index) const; + virtual bool is_port_separator(int p_index) const override; - virtual String get_caption() const; + virtual String get_caption() const override; - 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; + 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 override; VisualShaderNodeOutput(); }; @@ -376,8 +402,9 @@ public: }; private: - String uniform_name; - Qualifier qualifier; + String uniform_name = ""; + Qualifier qualifier = QUAL_NONE; + bool global_code_generated = false; protected: static void _bind_methods(); @@ -390,30 +417,112 @@ public: void set_qualifier(Qualifier p_qual); Qualifier get_qualifier() const; + void set_global_code_generated(bool p_enabled); + bool is_global_code_generated() const; + virtual bool is_qualifier_supported(Qualifier p_qual) const = 0; - virtual Vector<StringName> get_editable_properties() const; - virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const; + virtual Vector<StringName> get_editable_properties() const override; + virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; VisualShaderNodeUniform(); }; VARIANT_ENUM_CAST(VisualShaderNodeUniform::Qualifier) -class VisualShaderNodeGroupBase : public VisualShaderNode { - GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode); +class VisualShaderNodeUniformRef : public VisualShaderNode { + GDCLASS(VisualShaderNodeUniformRef, VisualShaderNode); + +public: + enum UniformType { + UNIFORM_TYPE_FLOAT, + UNIFORM_TYPE_INT, + UNIFORM_TYPE_BOOLEAN, + UNIFORM_TYPE_VECTOR, + UNIFORM_TYPE_TRANSFORM, + UNIFORM_TYPE_COLOR, + UNIFORM_TYPE_SAMPLER, + }; + + struct Uniform { + String name; + UniformType type; + }; + +private: + String uniform_name = "[None]"; + UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT; + +protected: + static void _bind_methods(); + +public: + static void add_uniform(const String &p_name, UniformType p_type); + static void clear_uniforms(); + static bool has_uniform(const String &p_name); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + void set_uniform_name(const String &p_name); + String get_uniform_name() const; + + void _set_uniform_type(int p_uniform_type); + int _get_uniform_type() const; + + int get_uniforms_count() const; + String get_uniform_name_by_index(int p_idx) const; + UniformType get_uniform_type_by_name(const String &p_name) const; + UniformType get_uniform_type_by_index(int p_idx) const; + + virtual Vector<StringName> get_editable_properties() const override; + + 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 override; + + VisualShaderNodeUniformRef(); +}; + +class VisualShaderNodeResizableBase : public VisualShaderNode { + GDCLASS(VisualShaderNodeResizableBase, VisualShaderNode); + +protected: + Vector2 size = Size2(0, 0); + bool allow_v_resize = true; + +protected: + static void _bind_methods(); + +public: + void set_size(const Vector2 &p_size); + Vector2 get_size() const; + + bool is_allow_v_resize() const; + void set_allow_v_resize(bool p_enabled); + + VisualShaderNodeResizableBase(); +}; + +class VisualShaderNodeGroupBase : public VisualShaderNodeResizableBase { + GDCLASS(VisualShaderNodeGroupBase, VisualShaderNodeResizableBase); private: void _apply_port_changes(); protected: - Vector2 size; - String inputs; - String outputs; - bool editable; + String inputs = ""; + String outputs = ""; + bool editable = false; struct Port { - PortType type; + PortType type = PortType::PORT_TYPE_MAX; String name; }; @@ -425,11 +534,6 @@ 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; @@ -440,25 +544,25 @@ public: 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; + virtual int get_input_port_count() const override; 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; + virtual int get_output_port_count() const override; 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; + virtual PortType get_input_port_type(int p_id) const override; void set_input_port_name(int p_id, const String &p_name); - virtual String get_input_port_name(int p_id) const; + virtual String get_input_port_name(int p_id) const override; void set_output_port_type(int p_id, int p_type); - virtual PortType get_output_port_type(int p_id) const; + virtual PortType get_output_port_type(int p_id) const override; void set_output_port_name(int p_id, const String &p_name); - virtual String get_output_port_name(int p_id) const; + virtual String get_output_port_name(int p_id) const override; int get_free_input_port_id() const; int get_free_output_port_id() const; @@ -469,7 +573,7 @@ public: void set_editable(bool p_enabled); bool is_editable() 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; + 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 override; VisualShaderNodeGroupBase(); }; @@ -478,17 +582,17 @@ class VisualShaderNodeExpression : public VisualShaderNodeGroupBase { GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase); protected: - String expression; + String expression = ""; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; void set_expression(const String &p_expression); String get_expression() 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; + 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 override; VisualShaderNodeExpression(); }; @@ -497,9 +601,9 @@ class VisualShaderNodeGlobalExpression : public VisualShaderNodeExpression { GDCLASS(VisualShaderNodeGlobalExpression, VisualShaderNodeExpression); public: - virtual String get_caption() const; + virtual String get_caption() const override; - virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; VisualShaderNodeGlobalExpression(); }; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 87720cf110..d6200059f6 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,11 @@ #include "visual_shader_nodes.h" +////////////// Constants Base + +VisualShaderNodeConstant::VisualShaderNodeConstant() { +} + ////////////// Scalar(Float) String VisualShaderNodeFloatConstant::get_caption() const { @@ -87,7 +92,6 @@ void VisualShaderNodeFloatConstant::_bind_methods() { } VisualShaderNodeFloatConstant::VisualShaderNodeFloatConstant() { - constant = 0.0; } ////////////// Scalar(Int) @@ -147,7 +151,6 @@ void VisualShaderNodeIntConstant::_bind_methods() { } VisualShaderNodeIntConstant::VisualShaderNodeIntConstant() { - constant = 0; } ////////////// Boolean @@ -207,7 +210,6 @@ void VisualShaderNodeBooleanConstant::_bind_methods() { } VisualShaderNodeBooleanConstant::VisualShaderNodeBooleanConstant() { - constant = false; } ////////////// Color @@ -271,7 +273,6 @@ void VisualShaderNodeColorConstant::_bind_methods() { } VisualShaderNodeColorConstant::VisualShaderNodeColorConstant() { - constant = Color(1, 1, 1, 1); } ////////////// Vector @@ -456,7 +457,7 @@ String VisualShaderNodeTexture::get_output_port_name(int p_port) const { String VisualShaderNodeTexture::get_input_port_default_hint(int p_port) const { if (p_port == 0) { - return "UV.xy"; + return "default"; } return ""; } @@ -484,7 +485,7 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade case TYPE_COLOR: u += " : hint_albedo"; break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: u += " : hint_normal"; break; } @@ -495,15 +496,22 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade } 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 { + String default_uv; + if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + default_uv = "UV.xy"; + } else { + default_uv = "vec2(0.0)"; + } + if (source == SOURCE_TEXTURE) { String id = make_unique_id(p_type, p_id, "tex"); String code; if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\tvec4 " + id + "_read = texture(" + id + ", UV.xy);\n"; + code += "\tvec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\tvec4 " + id + "_read = textureLod(" + id + ", UV.xy, " + p_input_vars[1] + ");\n"; + code += "\tvec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -529,9 +537,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", UV.xy);\n"; + code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -553,9 +561,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String() || p_for_preview) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, UV.xy, 0.0 );\n"; + code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0 );\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -576,9 +584,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = texture(TEXTURE , UV.xy);\n"; + code += "\t\tvec4 _tex_read = texture(TEXTURE, " + default_uv + ");\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(TEXTURE, UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 _tex_read = textureLod(TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -599,9 +607,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = texture(NORMAL_TEXTURE, UV.xy);\n"; + code += "\t\tvec4 _tex_read = texture(NORMAL_TEXTURE, " + default_uv + ");\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(NORMAL_TEXTURE, UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 _tex_read = textureLod(NORMAL_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { @@ -632,9 +640,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tfloat _depth = texture(DEPTH_TEXTURE, UV.xy).r;\n"; + code += "\t\tfloat _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n"; } else { - code += "\t\tfloat _depth = textureLod(DEPTH_TEXTURE, UV.xy, " + p_input_vars[1] + ").r;\n"; + code += "\t\tfloat _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n"; } } else if (p_input_vars[1] == String()) { @@ -721,6 +729,10 @@ Vector<StringName> VisualShaderNodeTexture::get_editable_properties() const { } String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { + if (is_input_port_connected(2) && source != SOURCE_PORT) { + return TTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'."); + } + if (source == SOURCE_TEXTURE) { return String(); // all good } @@ -773,12 +785,339 @@ void VisualShaderNodeTexture::_bind_methods() { BIND_ENUM_CONSTANT(SOURCE_PORT); BIND_ENUM_CONSTANT(TYPE_DATA); BIND_ENUM_CONSTANT(TYPE_COLOR); - BIND_ENUM_CONSTANT(TYPE_NORMALMAP); + BIND_ENUM_CONSTANT(TYPE_NORMAL_MAP); } VisualShaderNodeTexture::VisualShaderNodeTexture() { - texture_type = TYPE_DATA; - source = SOURCE_TEXTURE; +} + +////////////// Curve + +String VisualShaderNodeCurveTexture::get_caption() const { + return "CurveTexture"; +} + +int VisualShaderNodeCurveTexture::get_input_port_count() const { + return 1; +} + +VisualShaderNodeCurveTexture::PortType VisualShaderNodeCurveTexture::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeCurveTexture::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeCurveTexture::get_output_port_count() const { + return 1; +} + +VisualShaderNodeCurveTexture::PortType VisualShaderNodeCurveTexture::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeCurveTexture::get_output_port_name(int p_port) const { + return String(); +} + +void VisualShaderNodeCurveTexture::set_texture(Ref<CurveTexture> p_texture) { + texture = p_texture; + emit_changed(); +} + +Ref<CurveTexture> VisualShaderNodeCurveTexture::get_texture() const { + return texture; +} + +Vector<StringName> VisualShaderNodeCurveTexture::get_editable_properties() const { + Vector<StringName> props; + props.push_back("texture"); + return props; +} + +String VisualShaderNodeCurveTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + ";\n"; +} + +String VisualShaderNodeCurveTexture::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 (p_input_vars[0] == String()) { + return "\t" + p_output_vars[0] + " = 0.0;\n"; + } + String id = make_unique_id(p_type, p_id, "curve"); + String code; + code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ", 0.0)).r;\n"; + return code; +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCurveTexture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "curve"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +void VisualShaderNodeCurveTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &VisualShaderNodeCurveTexture::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeCurveTexture::get_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_texture", "get_texture"); +} + +bool VisualShaderNodeCurveTexture::is_use_prop_slots() const { + return true; +} + +VisualShaderNodeCurveTexture::VisualShaderNodeCurveTexture() { + simple_decl = true; + allow_v_resize = false; +} + +////////////// Sample3D + +int VisualShaderNodeSample3D::get_input_port_count() const { + return 3; +} + +VisualShaderNodeSample3D::PortType VisualShaderNodeSample3D::get_input_port_type(int p_port) const { + switch (p_port) { + case 0: + return PORT_TYPE_VECTOR; + case 1: + return PORT_TYPE_SCALAR; + case 2: + return PORT_TYPE_SAMPLER; + default: + return PORT_TYPE_SCALAR; + } +} + +String VisualShaderNodeSample3D::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "uvw"; + case 1: + return "lod"; + default: + return ""; + } +} + +int VisualShaderNodeSample3D::get_output_port_count() const { + return 2; +} + +VisualShaderNodeSample3D::PortType VisualShaderNodeSample3D::get_output_port_type(int p_port) const { + return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; +} + +String VisualShaderNodeSample3D::get_output_port_name(int p_port) const { + return p_port == 0 ? "rgb" : "alpha"; +} + +String VisualShaderNodeSample3D::get_input_port_default_hint(int p_port) const { + if (p_port == 0) { + return "default"; + } + return ""; +} + +String VisualShaderNodeSample3D::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 default_uv; + if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + default_uv = "vec3(UV, 0.0)"; + } else { + default_uv = "vec3(0.0)"; + } + + String code; + if (source == SOURCE_TEXTURE || source == SOURCE_PORT) { + String id; + code += "\t{\n"; + if (source == SOURCE_TEXTURE) { + id = make_unique_id(p_type, p_id, "tex3d"); + } else { + id = p_input_vars[2]; + } + if (id != String()) { + if (p_input_vars[0] == String()) { // Use UV by default. + if (p_input_vars[1] == String()) { + code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n"; + } else { + code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; + } + } else if (p_input_vars[1] == String()) { + //no lod + code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ");\n"; + } else { + code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + } + } else { + code += "\t\tvec4 " + id + "_tex_read = vec4(0.0);\n"; + } + + code += "\t\t" + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n"; + code += "\t\t" + p_output_vars[1] + " = " + id + "_tex_read.a;\n"; + code += "\t}\n"; + return code; + } + code += "\t" + p_output_vars[0] + " = vec3(0.0);\n"; + code += "\t" + p_output_vars[1] + " = 1.0;\n"; + return code; +} + +void VisualShaderNodeSample3D::set_source(Source p_source) { + source = p_source; + emit_changed(); + emit_signal("editor_refresh_request"); +} + +VisualShaderNodeSample3D::Source VisualShaderNodeSample3D::get_source() const { + return source; +} + +void VisualShaderNodeSample3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_source", "value"), &VisualShaderNodeSample3D::set_source); + ClassDB::bind_method(D_METHOD("get_source"), &VisualShaderNodeSample3D::get_source); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,SamplerPort"), "set_source", "get_source"); + + BIND_ENUM_CONSTANT(SOURCE_TEXTURE); + BIND_ENUM_CONSTANT(SOURCE_PORT); +} + +String VisualShaderNodeSample3D::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { + if (is_input_port_connected(2) && source != SOURCE_PORT) { + return TTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'."); + } + + if (source == SOURCE_TEXTURE) { + return String(); // all good + } + if (source == SOURCE_PORT) { + return String(); // all good + } + return TTR("Invalid source for shader."); +} + +VisualShaderNodeSample3D::VisualShaderNodeSample3D() { + simple_decl = false; +} + +////////////// Texture2DArray + +String VisualShaderNodeTexture2DArray::get_caption() const { + return "Texture2DArray"; +} + +String VisualShaderNodeTexture2DArray::get_input_port_name(int p_port) const { + if (p_port == 2) { + return "sampler2DArray"; + } + return VisualShaderNodeSample3D::get_input_port_name(p_port); +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture2DArray::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "tex3d"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +String VisualShaderNodeTexture2DArray::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + if (source == SOURCE_TEXTURE) { + return "uniform sampler2DArray " + make_unique_id(p_type, p_id, "tex3d") + ";\n"; + } + return String(); +} + +void VisualShaderNodeTexture2DArray::set_texture_array(Ref<Texture2DArray> p_value) { + texture = p_value; + emit_changed(); +} + +Ref<Texture2DArray> VisualShaderNodeTexture2DArray::get_texture_array() const { + return texture; +} + +Vector<StringName> VisualShaderNodeTexture2DArray::get_editable_properties() const { + Vector<StringName> props; + props.push_back("source"); + if (source == SOURCE_TEXTURE) { + props.push_back("texture_array"); + } + return props; +} + +void VisualShaderNodeTexture2DArray::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture_array", "value"), &VisualShaderNodeTexture2DArray::set_texture_array); + ClassDB::bind_method(D_METHOD("get_texture_array"), &VisualShaderNodeTexture2DArray::get_texture_array); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_array", PROPERTY_HINT_RESOURCE_TYPE, "Texture2DArray"), "set_texture_array", "get_texture_array"); +} + +VisualShaderNodeTexture2DArray::VisualShaderNodeTexture2DArray() { +} + +////////////// Texture3D + +String VisualShaderNodeTexture3D::get_caption() const { + return "Texture3D"; +} + +String VisualShaderNodeTexture3D::get_input_port_name(int p_port) const { + if (p_port == 2) { + return "sampler3D"; + } + return VisualShaderNodeSample3D::get_input_port_name(p_port); +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture3D::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "tex3d"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +String VisualShaderNodeTexture3D::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + if (source == SOURCE_TEXTURE) { + return "uniform sampler3D " + make_unique_id(p_type, p_id, "tex3d") + ";\n"; + } + return String(); +} + +void VisualShaderNodeTexture3D::set_texture(Ref<Texture3D> p_value) { + texture = p_value; + emit_changed(); +} + +Ref<Texture3D> VisualShaderNodeTexture3D::get_texture() const { + return texture; +} + +Vector<StringName> VisualShaderNodeTexture3D::get_editable_properties() const { + Vector<StringName> props; + props.push_back("source"); + if (source == SOURCE_TEXTURE) { + props.push_back("texture"); + } + return props; +} + +void VisualShaderNodeTexture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture", "value"), &VisualShaderNodeTexture3D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeTexture3D::get_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture"); +} + +VisualShaderNodeTexture3D::VisualShaderNodeTexture3D() { } ////////////// Cubemap @@ -847,7 +1186,7 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade case TYPE_COLOR: u += " : hint_albedo"; break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: u += " : hint_normal"; break; } @@ -857,6 +1196,13 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade } 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 default_uv; + if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + default_uv = "vec3(UV, 0.0)"; + } else { + default_uv = "vec3(0.0)"; + } + String code; String id; if (source == SOURCE_TEXTURE) { @@ -880,9 +1226,9 @@ String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 " + id + "_read = texture(" + id + " , vec3(UV, 0.0));\n"; + code += "\t\tvec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 " + id + "_read = textureLod(" + id + " , vec3(UV, 0.0)" + " , " + p_input_vars[1] + " );\n"; + code += "\t\tvec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + " );\n"; } } else if (p_input_vars[1] == String()) { @@ -900,7 +1246,7 @@ String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader: String VisualShaderNodeCubemap::get_input_port_default_hint(int p_port) const { if (p_port == 0) { - return "vec3(UV, 0.0)"; + return "default"; } return ""; } @@ -943,6 +1289,13 @@ Vector<StringName> VisualShaderNodeCubemap::get_editable_properties() const { return props; } +String VisualShaderNodeCubemap::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { + if (is_input_port_connected(2) && source != SOURCE_PORT) { + return TTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'."); + } + return String(); +} + void VisualShaderNodeCubemap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_source", "value"), &VisualShaderNodeCubemap::set_source); ClassDB::bind_method(D_METHOD("get_source"), &VisualShaderNodeCubemap::get_source); @@ -962,12 +1315,10 @@ void VisualShaderNodeCubemap::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_DATA); BIND_ENUM_CONSTANT(TYPE_COLOR); - BIND_ENUM_CONSTANT(TYPE_NORMALMAP); + BIND_ENUM_CONSTANT(TYPE_NORMAL_MAP); } VisualShaderNodeCubemap::VisualShaderNodeCubemap() { - texture_type = TYPE_DATA; - source = SOURCE_TEXTURE; simple_decl = false; } @@ -1073,7 +1424,6 @@ void VisualShaderNodeFloatOp::_bind_methods() { } VisualShaderNodeFloatOp::VisualShaderNodeFloatOp() { - op = OP_ADD; set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); } @@ -1168,7 +1518,6 @@ void VisualShaderNodeIntOp::_bind_methods() { } VisualShaderNodeIntOp::VisualShaderNodeIntOp() { - op = OP_ADD; set_input_port_default_value(0, 0); set_input_port_default_value(1, 0); } @@ -1283,7 +1632,6 @@ void VisualShaderNodeVectorOp::_bind_methods() { } VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() { - op = OP_ADD; set_input_port_default_value(0, Vector3()); set_input_port_default_value(1, Vector3()); } @@ -1451,7 +1799,6 @@ void VisualShaderNodeColorOp::_bind_methods() { } VisualShaderNodeColorOp::VisualShaderNodeColorOp() { - op = OP_SCREEN; set_input_port_default_value(0, Vector3()); set_input_port_default_value(1, Vector3()); } @@ -1526,7 +1873,6 @@ void VisualShaderNodeTransformMult::_bind_methods() { } VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() { - op = OP_AxB; set_input_port_default_value(0, Transform()); set_input_port_default_value(1, Transform()); } @@ -1601,7 +1947,6 @@ void VisualShaderNodeTransformVecMult::_bind_methods() { } VisualShaderNodeTransformVecMult::VisualShaderNodeTransformVecMult() { - op = OP_AxB; set_input_port_default_value(0, Transform()); set_input_port_default_value(1, Vector3()); } @@ -1731,7 +2076,6 @@ void VisualShaderNodeFloatFunc::_bind_methods() { } VisualShaderNodeFloatFunc::VisualShaderNodeFloatFunc() { - func = FUNC_SIGN; set_input_port_default_value(0, 0.0); } @@ -1742,9 +2086,6 @@ String VisualShaderNodeIntFunc::get_caption() const { } int VisualShaderNodeIntFunc::get_input_port_count() const { - if (func == FUNC_CLAMP) { - return 3; - } return 1; } @@ -1753,15 +2094,6 @@ VisualShaderNodeIntFunc::PortType VisualShaderNodeIntFunc::get_input_port_type(i } String VisualShaderNodeIntFunc::get_input_port_name(int p_port) const { - if (func == FUNC_CLAMP) { - if (p_port == 0) { - return ""; - } else if (p_port == 1) { - return "min"; - } else if (p_port == 2) { - return "max"; - } - } return ""; } @@ -1778,13 +2110,8 @@ String VisualShaderNodeIntFunc::get_output_port_name(int p_port) const { } String VisualShaderNodeIntFunc::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 (func == FUNC_CLAMP) { - return "\t" + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; - } - static const char *int_func_id[FUNC_SIGN + 1] = { "abs($)", - "", "-($)", "sign($)" }; @@ -1793,12 +2120,6 @@ String VisualShaderNodeIntFunc::generate_code(Shader::Mode p_mode, VisualShader: } void VisualShaderNodeIntFunc::set_function(Function p_func) { - if (func != p_func) { - if (p_func == FUNC_CLAMP) { - set_input_port_default_value(1, 0); - set_input_port_default_value(2, 0); - } - } func = p_func; emit_changed(); } @@ -1817,16 +2138,14 @@ void VisualShaderNodeIntFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeIntFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeIntFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Abs,Clamp,Negate,Sign"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Abs,Negate,Sign"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_ABS); - BIND_ENUM_CONSTANT(FUNC_CLAMP); BIND_ENUM_CONSTANT(FUNC_NEGATE); BIND_ENUM_CONSTANT(FUNC_SIGN); } VisualShaderNodeIntFunc::VisualShaderNodeIntFunc() { - func = FUNC_SIGN; set_input_port_default_value(0, 0); } @@ -1992,7 +2311,6 @@ void VisualShaderNodeVectorFunc::_bind_methods() { } VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() { - func = FUNC_NORMALIZE; set_input_port_default_value(0, Vector3()); } @@ -2079,9 +2397,8 @@ void VisualShaderNodeColorFunc::_bind_methods() { } VisualShaderNodeColorFunc::VisualShaderNodeColorFunc() { - func = FUNC_GRAYSCALE; - set_input_port_default_value(0, Vector3()); simple_decl = false; + set_input_port_default_value(0, Vector3()); } ////////////// Transform Func @@ -2151,7 +2468,6 @@ void VisualShaderNodeTransformFunc::_bind_methods() { } VisualShaderNodeTransformFunc::VisualShaderNodeTransformFunc() { - func = FUNC_INVERSE; set_input_port_default_value(0, Transform()); } @@ -2339,7 +2655,6 @@ void VisualShaderNodeScalarDerivativeFunc::_bind_methods() { } VisualShaderNodeScalarDerivativeFunc::VisualShaderNodeScalarDerivativeFunc() { - func = FUNC_SUM; set_input_port_default_value(0, 0.0); } @@ -2412,25 +2727,34 @@ void VisualShaderNodeVectorDerivativeFunc::_bind_methods() { } VisualShaderNodeVectorDerivativeFunc::VisualShaderNodeVectorDerivativeFunc() { - func = FUNC_SUM; set_input_port_default_value(0, Vector3()); } -////////////// Scalar Clamp +////////////// Clamp -String VisualShaderNodeScalarClamp::get_caption() const { - return "ScalarClamp"; +String VisualShaderNodeClamp::get_caption() const { + return "Clamp"; } -int VisualShaderNodeScalarClamp::get_input_port_count() const { +int VisualShaderNodeClamp::get_input_port_count() const { return 3; } -VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_input_port_type(int p_port) const { +VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarClamp::get_input_port_name(int p_port) const { +String VisualShaderNodeClamp::get_input_port_name(int p_port) const { if (p_port == 0) { return ""; } else if (p_port == 1) { @@ -2441,73 +2765,86 @@ String VisualShaderNodeScalarClamp::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeScalarClamp::get_output_port_count() const { +int VisualShaderNodeClamp::get_output_port_count() const { return 1; } -VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_output_port_type(int p_port) const { +VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarClamp::get_output_port_name(int p_port) const { +String VisualShaderNodeClamp::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 { +String VisualShaderNodeClamp::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"; +void VisualShaderNodeClamp::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; } - return ""; + switch (p_op_type) { + case OP_TYPE_FLOAT: + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); + break; + case OP_TYPE_INT: + set_input_port_default_value(0, 0); + set_input_port_default_value(1, 0); + set_input_port_default_value(2, 0); + break; + case OP_TYPE_VECTOR: + 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)); + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); } -int VisualShaderNodeVectorClamp::get_output_port_count() const { - return 1; +VisualShaderNodeClamp::OpType VisualShaderNodeClamp::get_op_type() const { + return op_type; } -VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +Vector<StringName> VisualShaderNodeClamp::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -String VisualShaderNodeVectorClamp::get_output_port_name(int p_port) const { - return ""; -} +void VisualShaderNodeClamp::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeClamp::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeClamp::get_op_type); -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"; + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_FLOAT); + BIND_ENUM_CONSTANT(OP_TYPE_INT); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -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)); +VisualShaderNodeClamp::VisualShaderNodeClamp() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 1.0); } ////////////// FaceForward @@ -2605,24 +2942,39 @@ VisualShaderNodeOuterProduct::VisualShaderNodeOuterProduct() { set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); } -////////////// Vector-Scalar Step +////////////// Step -String VisualShaderNodeVectorScalarStep::get_caption() const { - return "VectorScalarStep"; +String VisualShaderNodeStep::get_caption() const { + return "Step"; } -int VisualShaderNodeVectorScalarStep::get_input_port_count() const { +int VisualShaderNodeStep::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; +VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + switch (p_port) { + case 0: + return PORT_TYPE_SCALAR; + case 1: + return PORT_TYPE_VECTOR; + default: + break; + } + break; + default: + break; } - return PORT_TYPE_VECTOR; + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorScalarStep::get_input_port_name(int p_port) const { +String VisualShaderNodeStep::get_input_port_name(int p_port) const { if (p_port == 0) { return "edge"; } else if (p_port == 1) { @@ -2631,89 +2983,131 @@ String VisualShaderNodeVectorScalarStep::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeVectorScalarStep::get_output_port_count() const { +int VisualShaderNodeStep::get_output_port_count() const { return 1; } -VisualShaderNodeVectorScalarStep::PortType VisualShaderNodeVectorScalarStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeStep::PortType VisualShaderNodeStep::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorScalarStep::get_output_port_name(int p_port) const { +String VisualShaderNodeStep::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; +void VisualShaderNodeStep::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge + } + if (op_type == OP_TYPE_VECTOR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(1, 0.0); // x + } + break; + case OP_TYPE_VECTOR: + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // edge + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x + } + break; + case OP_TYPE_VECTOR_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(1, 0.0); // x + } + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); } -VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_input_port_type(int p_port) const { - return PORT_TYPE_SCALAR; +VisualShaderNodeStep::OpType VisualShaderNodeStep::get_op_type() const { + return op_type; } -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 ""; +String VisualShaderNodeStep::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"; } -int VisualShaderNodeScalarSmoothStep::get_output_port_count() const { - return 1; +Vector<StringName> VisualShaderNodeStep::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_SCALAR; -} +void VisualShaderNodeStep::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeStep::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeStep::get_op_type); -String VisualShaderNodeScalarSmoothStep::get_output_port_name(int p_port) const { - return ""; -} + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); -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"; + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeScalarSmoothStep::VisualShaderNodeScalarSmoothStep() { +VisualShaderNodeStep::VisualShaderNodeStep() { 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 +////////////// SmoothStep -String VisualShaderNodeVectorSmoothStep::get_caption() const { - return "VectorSmoothStep"; +String VisualShaderNodeSmoothStep::get_caption() const { + return "SmoothStep"; } -int VisualShaderNodeVectorSmoothStep::get_input_port_count() const { +int VisualShaderNodeSmoothStep::get_input_port_count() const { return 3; } -VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + switch (p_port) { + case 0: + return PORT_TYPE_SCALAR; // edge0 + case 1: + return PORT_TYPE_SCALAR; // edge1 + case 2: + return PORT_TYPE_VECTOR; // x + default: + break; + } + break; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorSmoothStep::get_input_port_name(int p_port) const { +String VisualShaderNodeSmoothStep::get_input_port_name(int p_port) const { if (p_port == 0) { return "edge0"; } else if (p_port == 1) { @@ -2724,78 +3118,98 @@ String VisualShaderNodeVectorSmoothStep::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeVectorSmoothStep::get_output_port_count() const { +int VisualShaderNodeSmoothStep::get_output_port_count() const { return 1; } -VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorSmoothStep::get_output_port_name(int p_port) const { +String VisualShaderNodeSmoothStep::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; +void VisualShaderNodeSmoothStep::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; } - 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"; + switch (p_op_type) { + case OP_TYPE_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge0 + set_input_port_default_value(1, 0.0); // edge1 + } + if (op_type == OP_TYPE_VECTOR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(2, 0.0); // x + } + break; + case OP_TYPE_VECTOR: + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // edge0 + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // edge1 + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); // x + } + break; + case OP_TYPE_VECTOR_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge0 + set_input_port_default_value(1, 0.0); // edge1 + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); // x + } + break; + default: + break; } - return ""; + op_type = p_op_type; + emit_changed(); } -int VisualShaderNodeVectorScalarSmoothStep::get_output_port_count() const { - return 1; +VisualShaderNodeSmoothStep::OpType VisualShaderNodeSmoothStep::get_op_type() const { + return op_type; } -VisualShaderNodeVectorScalarSmoothStep::PortType VisualShaderNodeVectorScalarSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +String VisualShaderNodeSmoothStep::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"; } -String VisualShaderNodeVectorScalarSmoothStep::get_output_port_name(int p_port) const { - return ""; +Vector<StringName> VisualShaderNodeSmoothStep::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -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"; +void VisualShaderNodeSmoothStep::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeSmoothStep::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSmoothStep::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeVectorScalarSmoothStep::VisualShaderNodeVectorScalarSmoothStep() { +VisualShaderNodeSmoothStep::VisualShaderNodeSmoothStep() { 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)); + set_input_port_default_value(2, 0.0); } ////////////// Distance @@ -2893,21 +3307,37 @@ VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() { set_input_port_default_value(2, 0.0); } -////////////// Scalar Mix +////////////// Mix -String VisualShaderNodeScalarInterp::get_caption() const { - return "ScalarMix"; +String VisualShaderNodeMix::get_caption() const { + return "Mix"; } -int VisualShaderNodeScalarInterp::get_input_port_count() const { +int VisualShaderNodeMix::get_input_port_count() const { return 3; } -VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_input_port_type(int p_port) const { +VisualShaderNodeMix::PortType VisualShaderNodeMix::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + if (p_port == 2) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + if (p_port == 2) { + return PORT_TYPE_SCALAR; + } + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const { +String VisualShaderNodeMix::get_input_port_name(int p_port) const { if (p_port == 0) { return "a"; } else if (p_port == 1) { @@ -2917,121 +3347,92 @@ String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const { } } -int VisualShaderNodeScalarInterp::get_output_port_count() const { +int VisualShaderNodeMix::get_output_port_count() const { return 1; } -VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_output_port_type(int p_port) const { +VisualShaderNodeMix::PortType VisualShaderNodeMix::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarInterp::get_output_port_name(int p_port) const { +String VisualShaderNodeMix::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, 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"; -} - -VisualShaderNodeScalarInterp::VisualShaderNodeScalarInterp() { - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 1.0); - set_input_port_default_value(2, 0.5); -} - -////////////// Vector Mix - -String VisualShaderNodeVectorInterp::get_caption() const { - return "VectorMix"; -} - -int VisualShaderNodeVectorInterp::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorInterp::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "a"; - } else if (p_port == 1) { - return "b"; - } else { - return "weight"; +void VisualShaderNodeMix::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; } + switch (p_op_type) { + case OP_TYPE_SCALAR: + set_input_port_default_value(0, 0.0); // a + set_input_port_default_value(1, 1.0); // b + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(2, 0.5); // weight + } + break; + case OP_TYPE_VECTOR: + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); // b + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(2, Vector3(0.5, 0.5, 0.5)); // weight + } + break; + case OP_TYPE_VECTOR_SCALAR: + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); // b + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(2, 0.5); // weight + } + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); } -int VisualShaderNodeVectorInterp::get_output_port_count() const { - return 1; -} - -VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorInterp::get_output_port_name(int p_port) const { - return "mix"; +VisualShaderNodeMix::OpType VisualShaderNodeMix::get_op_type() const { + return op_type; } -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 { +String VisualShaderNodeMix::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"; } -VisualShaderNodeVectorInterp::VisualShaderNodeVectorInterp() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, Vector3(0.5, 0.5, 0.5)); -} - -////////////// Vector Mix (by scalar) - -String VisualShaderNodeVectorScalarMix::get_caption() const { - return "VectorScalarMix"; -} - -int VisualShaderNodeVectorScalarMix::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorScalarMix::PortType VisualShaderNodeVectorScalarMix::get_input_port_type(int p_port) const { - if (p_port == 2) { - return PORT_TYPE_SCALAR; - } - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorScalarMix::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "a"; - } else if (p_port == 1) { - return "b"; - } else { - return "weight"; - } -} - -int VisualShaderNodeVectorScalarMix::get_output_port_count() const { - return 1; +Vector<StringName> VisualShaderNodeMix::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -VisualShaderNodeVectorScalarMix::PortType VisualShaderNodeVectorScalarMix::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} +void VisualShaderNodeMix::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeMix::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMix::get_op_type); -String VisualShaderNodeVectorScalarMix::get_output_port_name(int p_port) const { - return "mix"; -} + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); -String VisualShaderNodeVectorScalarMix::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"; + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeVectorScalarMix::VisualShaderNodeVectorScalarMix() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, 0.5); +VisualShaderNodeMix::VisualShaderNodeMix() { + set_input_port_default_value(0, 0.0); // a + set_input_port_default_value(1, 1.0); // b + set_input_port_default_value(2, 0.5); // weight } ////////////// Vector Compose @@ -3258,18 +3659,33 @@ String VisualShaderNodeFloatUniform::get_output_port_name(int p_port) const { } String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = ""; if (hint == HINT_RANGE) { - return _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ");\n"; + code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")"; } else if (hint == HINT_RANGE_STEP) { - return _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ");\n"; + code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")"; + } else { + code += _get_qual_str() + "uniform float " + get_uniform_name(); } - return _get_qual_str() + "uniform float " + get_uniform_name() + ";\n"; + if (default_value_enabled) { + code += " = " + rtos(default_value); + } + code += ";\n"; + return code; } String VisualShaderNodeFloatUniform::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"; } +bool VisualShaderNodeFloatUniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeFloatUniform::is_use_prop_slots() const { + return true; +} + void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) { hint = p_hint; emit_changed(); @@ -3306,6 +3722,24 @@ float VisualShaderNodeFloatUniform::get_step() const { return hint_range_step; } +void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeFloatUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeFloatUniform::set_default_value(float p_value) { + default_value = p_value; + emit_changed(); +} + +float VisualShaderNodeFloatUniform::get_default_value() const { + return default_value; +} + void VisualShaderNodeFloatUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatUniform::set_hint); ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatUniform::get_hint); @@ -3319,10 +3753,18 @@ void VisualShaderNodeFloatUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatUniform::set_step); ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatUniform::get_step); + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatUniform::get_default_value); + ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min"), "set_min", "get_min"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max"), "set_max", "get_max"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step"), "set_step", "get_step"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_value"), "set_default_value", "get_default_value"); BIND_ENUM_CONSTANT(HINT_NONE); BIND_ENUM_CONSTANT(HINT_RANGE); @@ -3343,14 +3785,14 @@ Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const if (hint == HINT_RANGE_STEP) { props.push_back("step"); } + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } return props; } VisualShaderNodeFloatUniform::VisualShaderNodeFloatUniform() { - hint = HINT_NONE; - hint_range_min = 0.0; - hint_range_max = 1.0; - hint_range_step = 0.1; } ////////////// Integer Uniform @@ -3384,18 +3826,33 @@ String VisualShaderNodeIntUniform::get_output_port_name(int p_port) const { } String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = ""; if (hint == HINT_RANGE) { - return _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ");\n"; + code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")"; } else if (hint == HINT_RANGE_STEP) { - return _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ");\n"; + code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")"; + } else { + code += _get_qual_str() + "uniform int " + get_uniform_name(); + } + if (default_value_enabled) { + code += " = " + itos(default_value); } - return _get_qual_str() + "uniform int " + get_uniform_name() + ";\n"; + code += ";\n"; + return code; } String VisualShaderNodeIntUniform::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"; } +bool VisualShaderNodeIntUniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeIntUniform::is_use_prop_slots() const { + return true; +} + void VisualShaderNodeIntUniform::set_hint(Hint p_hint) { hint = p_hint; emit_changed(); @@ -3432,6 +3889,24 @@ int VisualShaderNodeIntUniform::get_step() const { return hint_range_step; } +void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeIntUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeIntUniform::set_default_value(int p_value) { + default_value = p_value; + emit_changed(); +} + +int VisualShaderNodeIntUniform::get_default_value() const { + return default_value; +} + void VisualShaderNodeIntUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntUniform::set_hint); ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntUniform::get_hint); @@ -3445,10 +3920,18 @@ void VisualShaderNodeIntUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntUniform::set_step); ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntUniform::get_step); + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntUniform::get_default_value); + ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint"); ADD_PROPERTY(PropertyInfo(Variant::INT, "min"), "set_min", "get_min"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max"), "set_max", "get_max"); ADD_PROPERTY(PropertyInfo(Variant::INT, "step"), "set_step", "get_step"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "default_value"), "set_default_value", "get_default_value"); BIND_ENUM_CONSTANT(HINT_NONE); BIND_ENUM_CONSTANT(HINT_RANGE); @@ -3469,14 +3952,14 @@ Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const { if (hint == HINT_RANGE_STEP) { props.push_back("step"); } + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } return props; } VisualShaderNodeIntUniform::VisualShaderNodeIntUniform() { - hint = HINT_NONE; - hint_range_min = 0; - hint_range_max = 100; - hint_range_step = 1; } ////////////// Boolean Uniform @@ -3509,18 +3992,73 @@ String VisualShaderNodeBooleanUniform::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } +void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeBooleanUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeBooleanUniform::set_default_value(bool p_value) { + default_value = p_value; + emit_changed(); +} + +bool VisualShaderNodeBooleanUniform::get_default_value() const { + return default_value; +} + String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return _get_qual_str() + "uniform bool " + get_uniform_name() + ";\n"; + String code = _get_qual_str() + "uniform bool " + get_uniform_name(); + if (default_value_enabled) { + if (default_value) { + code += " = true"; + } else { + code += " = false"; + } + } + code += ";\n"; + return code; } 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"; } +bool VisualShaderNodeBooleanUniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeBooleanUniform::is_use_prop_slots() const { + return true; +} + +void VisualShaderNodeBooleanUniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanUniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value"), "set_default_value", "get_default_value"); +} + bool VisualShaderNodeBooleanUniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } +Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() { } @@ -3554,8 +4092,31 @@ String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const { return p_port == 0 ? "color" : "alpha"; //no output port means the editor will be used as port } +void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeColorUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) { + default_value = p_value; + emit_changed(); +} + +Color VisualShaderNodeColorUniform::get_default_value() const { + return default_value; +} + String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color;\n"; + String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color"; + if (default_value_enabled) { + code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.r, default_value.g, default_value.b, default_value.a); + } + code += ";\n"; + return code; } 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 { @@ -3564,10 +4125,34 @@ String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualSh return code; } +bool VisualShaderNodeColorUniform::is_show_prop_names() const { + return true; +} + +void VisualShaderNodeColorUniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorUniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_value"), "set_default_value", "get_default_value"); +} + bool VisualShaderNodeColorUniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } +Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() { } @@ -3601,18 +4186,69 @@ String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } +void VisualShaderNodeVec3Uniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeVec3Uniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeVec3Uniform::set_default_value(const Vector3 &p_value) { + default_value = p_value; + emit_changed(); +} + +Vector3 VisualShaderNodeVec3Uniform::get_default_value() const { + return default_value; +} + String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return _get_qual_str() + "uniform vec3 " + get_uniform_name() + ";\n"; + String code = _get_qual_str() + "uniform vec3 " + get_uniform_name(); + if (default_value_enabled) { + code += vformat(" = vec3(%.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z); + } + code += ";\n"; + return code; } 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"; } +void VisualShaderNodeVec3Uniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Uniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Uniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Uniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Uniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value"); +} + +bool VisualShaderNodeVec3Uniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeVec3Uniform::is_use_prop_slots() const { + return true; +} + bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } +Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() { } @@ -3646,18 +4282,73 @@ String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const return ""; //no output port means the editor will be used as port } +void VisualShaderNodeTransformUniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeTransformUniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeTransformUniform::set_default_value(const Transform &p_value) { + default_value = p_value; + emit_changed(); +} + +Transform VisualShaderNodeTransformUniform::get_default_value() const { + return default_value; +} + String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return _get_qual_str() + "uniform mat4 " + get_uniform_name() + ";\n"; + String code = _get_qual_str() + "uniform mat4 " + get_uniform_name(); + if (default_value_enabled) { + Vector3 row0 = default_value.basis.get_row(0); + Vector3 row1 = default_value.basis.get_row(1); + Vector3 row2 = default_value.basis.get_row(2); + Vector3 origin = default_value.origin; + code += " = mat4(" + vformat("vec4(%.6f, %.6f, %.6f, 0.0)", row0.x, row0.y, row0.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row1.x, row1.y, row1.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row2.x, row2.y, row2.z) + vformat(", vec4(%.6f, %.6f, %.6f, 1.0)", origin.x, origin.y, origin.z) + ")"; + } + code += ";\n"; + return code; } 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"; } +void VisualShaderNodeTransformUniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformUniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformUniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformUniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformUniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "default_value"), "set_default_value", "get_default_value"); +} + +bool VisualShaderNodeTransformUniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeTransformUniform::is_use_prop_slots() const { + return true; +} + bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } +Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() { } @@ -3727,7 +4418,7 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu code += " : hint_albedo;\n"; } break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: code += " : hint_normal;\n"; break; case TYPE_ANISO: @@ -3738,14 +4429,25 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu return code; } +bool VisualShaderNodeTextureUniform::is_code_generated() const { + return is_output_port_connected(0) || is_output_port_connected(1); // rgb or alpha +} + 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 default_uv; + if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + default_uv = "UV.xy"; + } else { + default_uv = "vec2(0.0)"; + } + String id = get_uniform_name(); String code = "\t{\n"; if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = texture(" + id + ", UV.xy);\n"; + code += "\t\tvec4 n_tex_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 n_tex_read = textureLod(" + id + ", UV.xy, " + p_input_vars[1] + ");\n"; + code += "\t\tvec4 n_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod @@ -3797,7 +4499,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_DATA); BIND_ENUM_CONSTANT(TYPE_COLOR); - BIND_ENUM_CONSTANT(TYPE_NORMALMAP); + BIND_ENUM_CONSTANT(TYPE_NORMAL_MAP); BIND_ENUM_CONSTANT(TYPE_ANISO); BIND_ENUM_CONSTANT(COLOR_DEFAULT_WHITE); @@ -3806,7 +4508,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() { String VisualShaderNodeTextureUniform::get_input_port_default_hint(int p_port) const { if (p_port == 0) { - return "UV.xy"; + return "default"; } return ""; } @@ -3824,8 +4526,6 @@ bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) co } VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() { - texture_type = TYPE_DATA; - color_default = COLOR_DEFAULT_WHITE; simple_decl = false; } @@ -3898,13 +4598,13 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod String code = "\t{\n"; if (p_input_vars[0] == String() && p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", triplanar_power_normal, triplanar_pos );\n"; + code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, triplanar_pos);\n"; } else if (p_input_vars[0] != String() && p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", " + p_input_vars[0] + ", triplanar_pos );\n"; + code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", triplanar_pos);\n"; } else if (p_input_vars[0] == String() && p_input_vars[1] != String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", triplanar_power_normal," + p_input_vars[1] + " );\n"; + code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, " + p_input_vars[1] + ");\n"; } else { - code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + " );\n"; + code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } code += "\t\t" + p_output_vars[0] + " = n_tex_read.rgb;\n"; @@ -3926,6 +4626,142 @@ String VisualShaderNodeTextureUniformTriplanar::get_input_port_default_hint(int VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() { } +////////////// Texture2DArray Uniform + +String VisualShaderNodeTexture2DArrayUniform::get_caption() const { + return "Texture2DArrayUniform"; +} + +int VisualShaderNodeTexture2DArrayUniform::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTexture2DArrayUniform::PortType VisualShaderNodeTexture2DArrayUniform::get_output_port_type(int p_port) const { + return PORT_TYPE_SAMPLER; +} + +String VisualShaderNodeTexture2DArrayUniform::get_output_port_name(int p_port) const { + return "sampler2DArray"; +} + +int VisualShaderNodeTexture2DArrayUniform::get_input_port_count() const { + return 0; +} + +VisualShaderNodeTexture2DArrayUniform::PortType VisualShaderNodeTexture2DArrayUniform::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeTexture2DArrayUniform::get_input_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeTexture2DArrayUniform::get_input_port_default_hint(int p_port) const { + return ""; +} + +String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform sampler2DArray " + get_uniform_name(); + + switch (texture_type) { + case TYPE_DATA: + if (color_default == COLOR_DEFAULT_BLACK) + code += " : hint_black;\n"; + else + code += ";\n"; + break; + case TYPE_COLOR: + if (color_default == COLOR_DEFAULT_BLACK) + code += " : hint_black_albedo;\n"; + else + code += " : hint_albedo;\n"; + break; + case TYPE_NORMAL_MAP: + code += " : hint_normal;\n"; + break; + case TYPE_ANISO: + code += " : hint_aniso;\n"; + break; + } + + return code; +} + +String VisualShaderNodeTexture2DArrayUniform::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(); +} + +VisualShaderNodeTexture2DArrayUniform::VisualShaderNodeTexture2DArrayUniform() { +} + +////////////// Texture3D Uniform + +String VisualShaderNodeTexture3DUniform::get_caption() const { + return "Texture3DUniform"; +} + +int VisualShaderNodeTexture3DUniform::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTexture3DUniform::PortType VisualShaderNodeTexture3DUniform::get_output_port_type(int p_port) const { + return PORT_TYPE_SAMPLER; +} + +String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const { + return "sampler3D"; +} + +int VisualShaderNodeTexture3DUniform::get_input_port_count() const { + return 0; +} + +VisualShaderNodeTexture3DUniform::PortType VisualShaderNodeTexture3DUniform::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeTexture3DUniform::get_input_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeTexture3DUniform::get_input_port_default_hint(int p_port) const { + return ""; +} + +String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name(); + + switch (texture_type) { + case TYPE_DATA: + if (color_default == COLOR_DEFAULT_BLACK) + code += " : hint_black;\n"; + else + code += ";\n"; + break; + case TYPE_COLOR: + if (color_default == COLOR_DEFAULT_BLACK) + code += " : hint_black_albedo;\n"; + else + code += " : hint_albedo;\n"; + break; + case TYPE_NORMAL_MAP: + code += " : hint_normal;\n"; + break; + case TYPE_ANISO: + code += " : hint_aniso;\n"; + break; + } + + return code; +} + +String VisualShaderNodeTexture3DUniform::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(); +} + +VisualShaderNodeTexture3DUniform::VisualShaderNodeTexture3DUniform() { +} + ////////////// Cubemap Uniform String VisualShaderNodeCubemapUniform::get_caption() const { @@ -3978,7 +4814,7 @@ String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, Visu code += " : hint_albedo;\n"; } break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: code += " : hint_normal;\n"; break; case TYPE_ANISO: @@ -4062,19 +4898,19 @@ String VisualShaderNodeIf::generate_code(Shader::Mode p_mode, VisualShader::Type } VisualShaderNodeIf::VisualShaderNodeIf() { + simple_decl = false; 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)); - simple_decl = false; } ////////////// Switch String VisualShaderNodeSwitch::get_caption() const { - return "VectorSwitch"; + return "Switch"; } int VisualShaderNodeSwitch::get_input_port_count() const { @@ -4085,7 +4921,23 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int if (p_port == 0) { return PORT_TYPE_BOOLEAN; } - return PORT_TYPE_VECTOR; + if (p_port == 1 || p_port == 2) { + switch (op_type) { + case OP_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_BOOLEAN: + return PORT_TYPE_BOOLEAN; + case OP_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + default: + break; + } + } + return PORT_TYPE_SCALAR; } String VisualShaderNodeSwitch::get_input_port_name(int p_port) const { @@ -4106,13 +4958,84 @@ int VisualShaderNodeSwitch::get_output_port_count() const { } VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + switch (op_type) { + case OP_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_BOOLEAN: + return PORT_TYPE_BOOLEAN; + case OP_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + default: + break; + } + return PORT_TYPE_SCALAR; } String VisualShaderNodeSwitch::get_output_port_name(int p_port) const { return "result"; } +void VisualShaderNodeSwitch::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_FLOAT: + set_input_port_default_value(1, 1.0); + set_input_port_default_value(2, 0.0); + break; + case OP_TYPE_INT: + set_input_port_default_value(1, 1); + set_input_port_default_value(2, 0); + break; + case OP_TYPE_VECTOR: + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + break; + case OP_TYPE_BOOLEAN: + set_input_port_default_value(1, true); + set_input_port_default_value(2, false); + break; + case OP_TYPE_TRANSFORM: + set_input_port_default_value(1, Transform()); + set_input_port_default_value(2, Transform()); + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + +VisualShaderNodeSwitch::OpType VisualShaderNodeSwitch::get_op_type() const { + return op_type; +} + +Vector<StringName> VisualShaderNodeSwitch::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; +} + +void VisualShaderNodeSwitch::_bind_methods() { // static + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeSwitch::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSwitch::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector,Boolean,Transform"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_FLOAT); + BIND_ENUM_CONSTANT(OP_TYPE_INT); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_BOOLEAN); + BIND_ENUM_CONSTANT(OP_TYPE_TRANSFORM); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); +} + 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"; @@ -4127,30 +5050,7 @@ String VisualShaderNodeSwitch::generate_code(Shader::Mode p_mode, VisualShader:: } VisualShaderNodeSwitch::VisualShaderNodeSwitch() { - set_input_port_default_value(0, false); - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); simple_decl = false; -} - -////////////// Switch(scalar) - -String VisualShaderNodeScalarSwitch::get_caption() const { - return "ScalarSwitch"; -} - -VisualShaderNodeScalarSwitch::PortType VisualShaderNodeScalarSwitch::get_input_port_type(int p_port) const { - if (p_port == 0) { - return PORT_TYPE_BOOLEAN; - } - return PORT_TYPE_SCALAR; -} - -VisualShaderNodeScalarSwitch::PortType VisualShaderNodeScalarSwitch::get_output_port_type(int p_port) const { - return PORT_TYPE_SCALAR; -} - -VisualShaderNodeScalarSwitch::VisualShaderNodeScalarSwitch() { set_input_port_default_value(0, false); set_input_port_default_value(1, 1.0); set_input_port_default_value(2, 0.0); @@ -4208,6 +5108,13 @@ String VisualShaderNodeFresnel::get_output_port_name(int p_port) const { return "result"; } +bool VisualShaderNodeFresnel::is_generate_input_var(int p_port) const { + if (p_port == 2) { + return false; + } + return true; +} + 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 { String normal; String view; @@ -4222,7 +5129,15 @@ String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader: view = p_input_vars[1]; } - return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n"; + if (is_input_port_connected(2)) { + return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n"; + } else { + if (get_input_port_default_value(2)) { + return "\t" + p_output_vars[0] + " = pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n"; + } else { + return "\t" + p_output_vars[0] + " = pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n"; + } + } } String VisualShaderNodeFresnel::get_input_port_default_hint(int p_port) const { @@ -4306,7 +5221,6 @@ void VisualShaderNodeIs::_bind_methods() { } VisualShaderNodeIs::VisualShaderNodeIs() { - func = FUNC_IS_INF; set_input_port_default_value(0, 0.0); } @@ -4542,10 +5456,105 @@ void VisualShaderNodeCompare::_bind_methods() { } VisualShaderNodeCompare::VisualShaderNodeCompare() { - ctype = CTYPE_SCALAR; - func = FUNC_EQUAL; - condition = COND_ALL; set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); set_input_port_default_value(2, CMP_EPSILON); } + +////////////// Fma + +String VisualShaderNodeMultiplyAdd::get_caption() const { + return "MultiplyAdd"; +} + +int VisualShaderNodeMultiplyAdd::get_input_port_count() const { + return 3; +} + +VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_input_port_type(int p_port) const { + if (op_type == OP_TYPE_SCALAR) { + return PORT_TYPE_SCALAR; + } + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeMultiplyAdd::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "a"; + } else if (p_port == 1) { + return "b(*)"; + } else if (p_port == 2) { + return "c(+)"; + } + return ""; +} + +int VisualShaderNodeMultiplyAdd::get_output_port_count() const { + return 1; +} + +VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_output_port_type(int p_port) const { + if (op_type == OP_TYPE_SCALAR) { + return PORT_TYPE_SCALAR; + } else { + return PORT_TYPE_VECTOR; + } +} + +String VisualShaderNodeMultiplyAdd::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeMultiplyAdd::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] + " = fma(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; +} + +void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); + break; + case OP_TYPE_VECTOR: + 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)); + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + +VisualShaderNodeMultiplyAdd::OpType VisualShaderNodeMultiplyAdd::get_op_type() const { + return op_type; +} + +Vector<StringName> VisualShaderNodeMultiplyAdd::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; +} + +void VisualShaderNodeMultiplyAdd::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeMultiplyAdd::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMultiplyAdd::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); +} + +VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); +} diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 69f42f621a..a5d0fe4649 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,180 +37,199 @@ /// CONSTANTS /////////////////////////////////////// -class VisualShaderNodeFloatConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeFloatConstant, VisualShaderNode); - float constant; +class VisualShaderNodeConstant : public VisualShaderNode { + GDCLASS(VisualShaderNodeConstant, VisualShaderNode); + +public: + virtual String get_caption() const override = 0; + + virtual int get_input_port_count() const override = 0; + virtual PortType get_input_port_type(int p_port) const override = 0; + virtual String get_input_port_name(int p_port) const override = 0; + + virtual int get_output_port_count() const override = 0; + virtual PortType get_output_port_type(int p_port) const override = 0; + virtual String get_output_port_name(int p_port) const override = 0; + + 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 override = 0; + + VisualShaderNodeConstant(); +}; + +class VisualShaderNodeFloatConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeFloatConstant, VisualShaderNodeConstant); + float constant = 0.0f; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeFloatConstant(); }; /////////////////////////////////////// -class VisualShaderNodeIntConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeIntConstant, VisualShaderNode); - int constant; +class VisualShaderNodeIntConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeIntConstant, VisualShaderNodeConstant); + int constant = 0; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(int p_value); int get_constant() const; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeIntConstant(); }; /////////////////////////////////////// -class VisualShaderNodeBooleanConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNode); - bool constant; +class VisualShaderNodeBooleanConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNodeConstant); + bool constant = false; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeBooleanConstant(); }; /////////////////////////////////////// -class VisualShaderNodeColorConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode); - Color constant; +class VisualShaderNodeColorConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeColorConstant, VisualShaderNodeConstant); + Color constant = Color(1, 1, 1, 1); protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeColorConstant(); }; /////////////////////////////////////// -class VisualShaderNodeVec3Constant : public VisualShaderNode { - GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNode); +class VisualShaderNodeVec3Constant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNodeConstant); Vector3 constant; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeVec3Constant(); }; /////////////////////////////////////// -class VisualShaderNodeTransformConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNode); +class VisualShaderNodeTransformConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNodeConstant); Transform constant; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeTransformConstant(); }; @@ -236,32 +255,32 @@ public: enum TextureType { TYPE_DATA, TYPE_COLOR, - TYPE_NORMALMAP + TYPE_NORMAL_MAP, }; private: - Source source; - TextureType texture_type; + Source source = SOURCE_TEXTURE; + TextureType texture_type = TYPE_DATA; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const; + virtual String get_input_port_default_hint(int p_port) const override; - virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const; - virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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; @@ -272,9 +291,9 @@ public: void set_texture_type(TextureType p_type); TextureType get_texture_type() const; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; - virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const; + virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; VisualShaderNodeTexture(); }; @@ -284,6 +303,121 @@ VARIANT_ENUM_CAST(VisualShaderNodeTexture::Source) /////////////////////////////////////// +class VisualShaderNodeCurveTexture : public VisualShaderNodeResizableBase { + GDCLASS(VisualShaderNodeCurveTexture, VisualShaderNodeResizableBase); + Ref<CurveTexture> texture; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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_texture(Ref<CurveTexture> p_value); + Ref<CurveTexture> get_texture() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual bool is_use_prop_slots() const override; + + VisualShaderNodeCurveTexture(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeSample3D : public VisualShaderNode { + GDCLASS(VisualShaderNodeSample3D, VisualShaderNode); + +public: + enum Source { + SOURCE_TEXTURE, + SOURCE_PORT, + }; + +protected: + Source source = SOURCE_TEXTURE; + + static void _bind_methods(); + +public: + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + virtual String get_input_port_default_hint(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + 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 override; //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; + + virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; + + VisualShaderNodeSample3D(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeSample3D::Source) + +class VisualShaderNodeTexture2DArray : public VisualShaderNodeSample3D { + GDCLASS(VisualShaderNodeTexture2DArray, VisualShaderNodeSample3D); + Ref<Texture2DArray> texture; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual String get_input_port_name(int p_port) const override; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + + void set_texture_array(Ref<Texture2DArray> p_value); + Ref<Texture2DArray> get_texture_array() const; + + virtual Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeTexture2DArray(); +}; + +class VisualShaderNodeTexture3D : public VisualShaderNodeSample3D { + GDCLASS(VisualShaderNodeTexture3D, VisualShaderNodeSample3D); + Ref<Texture3D> texture; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual String get_input_port_name(int p_port) const override; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + + void set_texture(Ref<Texture3D> p_value); + Ref<Texture3D> get_texture() const; + + virtual Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeTexture3D(); +}; + class VisualShaderNodeCubemap : public VisualShaderNode { GDCLASS(VisualShaderNodeCubemap, VisualShaderNode); Ref<Cubemap> cube_map; @@ -297,31 +431,31 @@ public: enum TextureType { TYPE_DATA, TYPE_COLOR, - TYPE_NORMALMAP + TYPE_NORMAL_MAP }; private: - Source source; - TextureType texture_type; + Source source = SOURCE_TEXTURE; + TextureType texture_type = TYPE_DATA; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - virtual int get_input_port_count() const; - virtual PortType get_input_port_type(int p_port) const; - virtual String get_input_port_name(int p_port) const; - virtual String get_input_port_default_hint(int p_port) const; + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + virtual String get_input_port_default_hint(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const; - virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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; @@ -332,7 +466,8 @@ public: void set_texture_type(TextureType p_type); TextureType get_texture_type() const; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; + virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; VisualShaderNodeCubemap(); }; @@ -362,27 +497,27 @@ public: }; protected: - Operator op; + Operator op = OP_ADD; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeFloatOp(); }; @@ -404,27 +539,27 @@ public: }; protected: - Operator op; + Operator op = OP_ADD; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeIntOp(); }; @@ -451,27 +586,27 @@ public: }; protected: - Operator op; + Operator op = OP_ADD; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeVectorOp(); }; @@ -497,27 +632,27 @@ public: }; protected: - Operator op; + Operator op = OP_SCREEN; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeColorOp(); }; @@ -540,27 +675,27 @@ public: }; protected: - Operator op; + Operator op = OP_AxB; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeTransformMult(); }; @@ -583,27 +718,27 @@ public: }; protected: - Operator op; + Operator op = OP_AxB; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeTransformVecMult(); }; @@ -654,27 +789,27 @@ public: }; protected: - Function func; + Function func = FUNC_SIGN; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeFloatFunc(); }; @@ -691,33 +826,32 @@ class VisualShaderNodeIntFunc : public VisualShaderNode { public: enum Function { FUNC_ABS, - FUNC_CLAMP, FUNC_NEGATE, FUNC_SIGN, }; protected: - Function func; + Function func = FUNC_SIGN; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeIntFunc(); }; @@ -771,27 +905,27 @@ public: }; protected: - Function func; + Function func = FUNC_NORMALIZE; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeVectorFunc(); }; @@ -812,27 +946,27 @@ public: }; protected: - Function func; + Function func = FUNC_GRAYSCALE; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeColorFunc(); }; @@ -853,27 +987,27 @@ public: }; protected: - Function func; + Function func = FUNC_INVERSE; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeTransformFunc(); }; @@ -888,17 +1022,17 @@ class VisualShaderNodeDotProduct : public VisualShaderNode { GDCLASS(VisualShaderNodeDotProduct, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -911,17 +1045,17 @@ class VisualShaderNodeVectorLen : public VisualShaderNode { GDCLASS(VisualShaderNodeVectorLen, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -934,17 +1068,17 @@ class VisualShaderNodeDeterminant : public VisualShaderNode { GDCLASS(VisualShaderNodeDeterminant, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -953,46 +1087,44 @@ public: /// CLAMP /////////////////////////////////////// -class VisualShaderNodeScalarClamp : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarClamp, VisualShaderNode); +class VisualShaderNodeClamp : public VisualShaderNode { + GDCLASS(VisualShaderNodeClamp, 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 + enum OpType { + OP_TYPE_FLOAT, + OP_TYPE_INT, + OP_TYPE_VECTOR, + OP_TYPE_MAX, + }; - VisualShaderNodeScalarClamp(); -}; +protected: + OpType op_type = OP_TYPE_FLOAT; + static void _bind_methods(); -/////////////////////////////////////// +public: + virtual String get_caption() const override; -class VisualShaderNodeVectorClamp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorClamp, VisualShaderNode); + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; -public: - virtual String get_caption() const; + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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; + void set_op_type(OpType p_type); + OpType get_op_type() 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 Vector<StringName> get_editable_properties() const override; - 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 + 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 override; //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(); + VisualShaderNodeClamp(); }; +VARIANT_ENUM_CAST(VisualShaderNodeClamp::OpType) + /////////////////////////////////////// /// DERIVATIVE FUNCTIONS /////////////////////////////////////// @@ -1008,27 +1140,27 @@ public: }; protected: - Function func; + Function func = FUNC_SUM; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeScalarDerivativeFunc(); }; @@ -1048,27 +1180,27 @@ public: }; protected: - Function func; + Function func = FUNC_SUM; static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeVectorDerivativeFunc(); }; @@ -1083,17 +1215,17 @@ class VisualShaderNodeFaceForward : public VisualShaderNode { GDCLASS(VisualShaderNodeFaceForward, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -1106,17 +1238,17 @@ class VisualShaderNodeOuterProduct : public VisualShaderNode { GDCLASS(VisualShaderNodeOuterProduct, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -1125,90 +1257,86 @@ public: /// STEP /////////////////////////////////////// -class VisualShaderNodeVectorScalarStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarStep, VisualShaderNode); +class VisualShaderNodeStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeStep, 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 + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; - VisualShaderNodeVectorScalarStep(); -}; +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); -/////////////////////////////////////// -/// SMOOTHSTEP -/////////////////////////////////////// +public: + virtual String get_caption() const override; -class VisualShaderNodeScalarSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarSmoothStep, VisualShaderNode); + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; -public: - virtual String get_caption() const; + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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; + void set_op_type(OpType p_type); + OpType get_op_type() 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 Vector<StringName> get_editable_properties() const override; - 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 + 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 override; //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(); + VisualShaderNodeStep(); }; +VARIANT_ENUM_CAST(VisualShaderNodeStep::OpType) + +/////////////////////////////////////// +/// SMOOTHSTEP /////////////////////////////////////// -class VisualShaderNodeVectorSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorSmoothStep, VisualShaderNode); +class VisualShaderNodeSmoothStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeSmoothStep, 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 + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; - VisualShaderNodeVectorSmoothStep(); -}; +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); -/////////////////////////////////////// +public: + virtual String get_caption() const override; -class VisualShaderNodeVectorScalarSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarSmoothStep, VisualShaderNode); + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; -public: - virtual String get_caption() const; + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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; + void set_op_type(OpType p_type); + OpType get_op_type() 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 Vector<StringName> get_editable_properties() const override; - 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 + 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 override; //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(); + VisualShaderNodeSmoothStep(); }; +VARIANT_ENUM_CAST(VisualShaderNodeSmoothStep::OpType) + /////////////////////////////////////// /// DISTANCE /////////////////////////////////////// @@ -1217,17 +1345,17 @@ class VisualShaderNodeVectorDistance : public VisualShaderNode { GDCLASS(VisualShaderNodeVectorDistance, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -1240,17 +1368,17 @@ class VisualShaderNodeVectorRefract : public VisualShaderNode { GDCLASS(VisualShaderNodeVectorRefract, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -1259,67 +1387,44 @@ public: /// MIX /////////////////////////////////////// -class VisualShaderNodeScalarInterp : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarInterp, VisualShaderNode); +class VisualShaderNodeMix : public VisualShaderNode { + GDCLASS(VisualShaderNodeMix, 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 - - VisualShaderNodeScalarInterp(); -}; - -/////////////////////////////////////// + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; -class VisualShaderNodeVectorInterp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorInterp, VisualShaderNode); +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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(); -}; - -/////////////////////////////////////// - -class VisualShaderNodeVectorScalarMix : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarMix, VisualShaderNode); - -public: - virtual String get_caption() const; + void set_op_type(OpType p_type); + OpType get_op_type() 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 Vector<StringName> get_editable_properties() const override; - 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 override; //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 - - VisualShaderNodeVectorScalarMix(); + VisualShaderNodeMix(); }; +VARIANT_ENUM_CAST(VisualShaderNodeMix::OpType) + /////////////////////////////////////// /// COMPOSE /////////////////////////////////////// @@ -1328,17 +1433,17 @@ class VisualShaderNodeVectorCompose : public VisualShaderNode { GDCLASS(VisualShaderNodeVectorCompose, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -1349,17 +1454,17 @@ class VisualShaderNodeTransformCompose : public VisualShaderNode { GDCLASS(VisualShaderNodeTransformCompose, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -1372,17 +1477,17 @@ class VisualShaderNodeVectorDecompose : public VisualShaderNode { GDCLASS(VisualShaderNodeVectorDecompose, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -1393,17 +1498,17 @@ class VisualShaderNodeTransformDecompose : public VisualShaderNode { GDCLASS(VisualShaderNodeTransformDecompose, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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(); }; @@ -1423,27 +1528,32 @@ public: }; private: - Hint hint; - float hint_range_min; - float hint_range_max; - float hint_range_step; + Hint hint = HINT_NONE; + float hint_range_min = 0.0f; + float hint_range_max = 1.0f; + float hint_range_step = 0.1f; + bool default_value_enabled = false; + float default_value = 0.0f; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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 bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; void set_hint(Hint p_hint); Hint get_hint() const; @@ -1457,9 +1567,15 @@ public: void set_step(float p_value); float get_step() const; - bool is_qualifier_supported(Qualifier p_qual) const; + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(float p_value); + float get_default_value() const; - virtual Vector<StringName> get_editable_properties() const; + bool is_qualifier_supported(Qualifier p_qual) const override; + + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeFloatUniform(); }; @@ -1477,27 +1593,32 @@ public: }; private: - Hint hint; - int hint_range_min; - int hint_range_max; - int hint_range_step; + Hint hint = HINT_NONE; + int hint_range_min = 0; + int hint_range_max = 100; + int hint_range_step = 1; + bool default_value_enabled = false; + int default_value = 0; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 override; + 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 override; //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_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 + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; void set_hint(Hint p_hint); Hint get_hint() const; @@ -1511,9 +1632,15 @@ public: void set_step(int p_value); int get_step() const; - bool is_qualifier_supported(Qualifier p_qual) const; + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(int p_value); + int get_default_value() const; - virtual Vector<StringName> get_editable_properties() const; + bool is_qualifier_supported(Qualifier p_qual) const override; + + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeIntUniform(); }; @@ -1525,21 +1652,39 @@ VARIANT_ENUM_CAST(VisualShaderNodeIntUniform::Hint) class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform); +private: + bool default_value_enabled = false; + bool default_value = false; + +protected: + static void _bind_methods(); + public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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 - bool is_qualifier_supported(Qualifier p_qual) const; + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; + + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(bool p_value); + bool get_default_value() const; + + bool is_qualifier_supported(Qualifier p_qual) const override; + + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeBooleanUniform(); }; @@ -1549,21 +1694,38 @@ public: class VisualShaderNodeColorUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform); +private: + bool default_value_enabled = false; + Color default_value = Color(1.0, 1.0, 1.0, 1.0); + +protected: + static void _bind_methods(); + public: - virtual String get_caption() const; + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - virtual int get_input_port_count() const; - virtual PortType get_input_port_type(int p_port) const; - virtual String get_input_port_name(int p_port) const; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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 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 bool is_show_prop_names() const override; - 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 + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; - bool is_qualifier_supported(Qualifier p_qual) const; + void set_default_value(const Color &p_value); + Color get_default_value() const; + + bool is_qualifier_supported(Qualifier p_qual) const override; + + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeColorUniform(); }; @@ -1573,21 +1735,39 @@ public: class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform); +private: + bool default_value_enabled = false; + Vector3 default_value; + +protected: + static void _bind_methods(); + public: - virtual String get_caption() const; + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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 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 bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; - 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; + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() 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 + void set_default_value(const Vector3 &p_value); + Vector3 get_default_value() const; - bool is_qualifier_supported(Qualifier p_qual) const; + bool is_qualifier_supported(Qualifier p_qual) const override; + + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeVec3Uniform(); }; @@ -1597,21 +1777,39 @@ public: class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform); +private: + bool default_value_enabled = false; + Transform default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); + +protected: + static void _bind_methods(); + public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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 - bool is_qualifier_supported(Qualifier p_qual) const; + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; + + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(const Transform &p_value); + Transform get_default_value() const; + + bool is_qualifier_supported(Qualifier p_qual) const override; + + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeTransformUniform(); }; @@ -1625,7 +1823,7 @@ public: enum TextureType { TYPE_DATA, TYPE_COLOR, - TYPE_NORMALMAP, + TYPE_NORMAL_MAP, TYPE_ANISO, }; @@ -1635,28 +1833,30 @@ public: }; protected: - TextureType texture_type; - ColorDefault color_default; + TextureType texture_type = TYPE_DATA; + ColorDefault color_default = COLOR_DEFAULT_WHITE; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - virtual int get_input_port_count() const; - virtual PortType get_input_port_type(int p_port) const; - virtual String get_input_port_name(int p_port) const; - virtual String get_input_port_default_hint(int p_port) const; + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + virtual String get_input_port_default_hint(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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; + virtual bool is_code_generated() const override; + + Vector<StringName> get_editable_properties() const override; void set_texture_type(TextureType p_type); TextureType get_texture_type() const; @@ -1664,7 +1864,7 @@ public: void set_color_default(ColorDefault p_default); ColorDefault get_color_default() const; - bool is_qualifier_supported(Qualifier p_qual) const; + bool is_qualifier_supported(Qualifier p_qual) const override; VisualShaderNodeTextureUniform(); }; @@ -1678,40 +1878,86 @@ class VisualShaderNodeTextureUniformTriplanar : public VisualShaderNodeTextureUn GDCLASS(VisualShaderNodeTextureUniformTriplanar, VisualShaderNodeTextureUniform); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const; + virtual String get_input_port_default_hint(int p_port) const override; - virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; - virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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 VisualShaderNodeTextureUniformTriplanar(); }; /////////////////////////////////////// +class VisualShaderNodeTexture2DArrayUniform : public VisualShaderNodeTextureUniform { + GDCLASS(VisualShaderNodeTexture2DArrayUniform, VisualShaderNodeTextureUniform); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String get_input_port_default_hint(int p_port) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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 + + VisualShaderNodeTexture2DArrayUniform(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeTexture3DUniform : public VisualShaderNodeTextureUniform { + GDCLASS(VisualShaderNodeTexture3DUniform, VisualShaderNodeTextureUniform); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String get_input_port_default_hint(int p_port) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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 + + VisualShaderNodeTexture3DUniform(); +}; + +/////////////////////////////////////// + class VisualShaderNodeCubemapUniform : public VisualShaderNodeTextureUniform { GDCLASS(VisualShaderNodeCubemapUniform, VisualShaderNodeTextureUniform); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - virtual String get_input_port_default_hint(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 + virtual String get_input_port_default_hint(int p_port) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; //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(); }; @@ -1724,17 +1970,17 @@ class VisualShaderNodeIf : public VisualShaderNode { GDCLASS(VisualShaderNodeIf, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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; + 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 override; VisualShaderNodeIf(); }; @@ -1747,33 +1993,43 @@ class VisualShaderNodeSwitch : public VisualShaderNode { GDCLASS(VisualShaderNodeSwitch, VisualShaderNode); public: - virtual String get_caption() const; + enum OpType { + OP_TYPE_FLOAT, + OP_TYPE_INT, + OP_TYPE_VECTOR, + OP_TYPE_BOOLEAN, + OP_TYPE_TRANSFORM, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_FLOAT; - 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; + static void _bind_methods(); - 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; +public: + virtual String get_caption() const override; - 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; + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - VisualShaderNodeSwitch(); -}; + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; -class VisualShaderNodeScalarSwitch : public VisualShaderNodeSwitch { - GDCLASS(VisualShaderNodeScalarSwitch, VisualShaderNodeSwitch); + void set_op_type(OpType p_type); + OpType get_op_type() const; -public: - virtual String get_caption() const; + virtual Vector<StringName> get_editable_properties() const override; - virtual PortType get_input_port_type(int p_port) const; - virtual PortType get_output_port_type(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 override; - VisualShaderNodeScalarSwitch(); + VisualShaderNodeSwitch(); }; +VARIANT_ENUM_CAST(VisualShaderNodeSwitch::OpType) + /////////////////////////////////////// /// FRESNEL /////////////////////////////////////// @@ -1782,18 +2038,19 @@ class VisualShaderNodeFresnel : public VisualShaderNode { GDCLASS(VisualShaderNodeFresnel, VisualShaderNode); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - virtual String get_input_port_default_hint(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; + virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_generate_input_var(int p_port) const override; + 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 override; VisualShaderNodeFresnel(); }; @@ -1812,28 +2069,28 @@ public: }; protected: - Function func; + Function func = FUNC_IS_INF; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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; - virtual Vector<StringName> get_editable_properties() const; + virtual Vector<StringName> get_editable_properties() const override; VisualShaderNodeIs(); }; @@ -1871,25 +2128,25 @@ public: }; protected: - ComparisonType ctype; - Function func; - Condition condition; + ComparisonType ctype = CTYPE_SCALAR; + Function func = FUNC_EQUAL; + Condition condition = COND_ALL; protected: static void _bind_methods(); public: - virtual String get_caption() const; + virtual String get_caption() const override; - 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_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; - 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 int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; - 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 + 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 override; //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_comparison_type(ComparisonType p_type); ComparisonType get_comparison_type() const; @@ -1900,8 +2157,8 @@ public: void set_condition(Condition p_cond); Condition get_condition() const; - virtual Vector<StringName> get_editable_properties() const; - virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const; + virtual Vector<StringName> get_editable_properties() const override; + virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; VisualShaderNodeCompare(); }; @@ -1910,4 +2167,43 @@ VARIANT_ENUM_CAST(VisualShaderNodeCompare::ComparisonType) VARIANT_ENUM_CAST(VisualShaderNodeCompare::Function) VARIANT_ENUM_CAST(VisualShaderNodeCompare::Condition) +class VisualShaderNodeMultiplyAdd : public VisualShaderNode { + GDCLASS(VisualShaderNodeMultiplyAdd, VisualShaderNode); + +public: + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_SCALAR; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + 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 override; //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_op_type(OpType p_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeMultiplyAdd(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeMultiplyAdd::OpType) + #endif // VISUAL_SHADER_NODES_H diff --git a/scene/resources/visual_shader_sdf_nodes.cpp b/scene/resources/visual_shader_sdf_nodes.cpp new file mode 100644 index 0000000000..d25e32b070 --- /dev/null +++ b/scene/resources/visual_shader_sdf_nodes.cpp @@ -0,0 +1,283 @@ +/*************************************************************************/ +/* visual_shader_sdf_nodes.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "visual_shader_sdf_nodes.h" + +// VisualShaderNodeSDFToScreenUV + +String VisualShaderNodeSDFToScreenUV::get_caption() const { + return "SDFToScreenUV"; +} + +int VisualShaderNodeSDFToScreenUV::get_input_port_count() const { + return 1; +} + +VisualShaderNodeSDFToScreenUV::PortType VisualShaderNodeSDFToScreenUV::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeSDFToScreenUV::get_input_port_name(int p_port) const { + return "sdf_pos"; +} + +int VisualShaderNodeSDFToScreenUV::get_output_port_count() const { + return 1; +} + +VisualShaderNodeSDFToScreenUV::PortType VisualShaderNodeSDFToScreenUV::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeSDFToScreenUV::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeSDFToScreenUV::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(sdf_to_screen_uv(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; +} + +VisualShaderNodeSDFToScreenUV::VisualShaderNodeSDFToScreenUV() { +} + +// VisualShaderNodeScreenUVToSDF + +String VisualShaderNodeScreenUVToSDF::get_caption() const { + return "ScreenUVToSDF"; +} + +int VisualShaderNodeScreenUVToSDF::get_input_port_count() const { + return 1; +} + +VisualShaderNodeScreenUVToSDF::PortType VisualShaderNodeScreenUVToSDF::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeScreenUVToSDF::get_input_port_name(int p_port) const { + return "uv"; +} + +int VisualShaderNodeScreenUVToSDF::get_output_port_count() const { + return 1; +} + +VisualShaderNodeScreenUVToSDF::PortType VisualShaderNodeScreenUVToSDF::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeScreenUVToSDF::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeScreenUVToSDF::get_input_port_default_hint(int p_port) const { + if (p_port == 0) { + return "default"; + } + return ""; +} + +String VisualShaderNodeScreenUVToSDF::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(screen_uv_to_sdf(" + (p_input_vars[0] == String() ? "SCREEN_UV" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; +} + +VisualShaderNodeScreenUVToSDF::VisualShaderNodeScreenUVToSDF() { +} + +// VisualShaderNodeTextureSDF + +String VisualShaderNodeTextureSDF::get_caption() const { + return "TextureSDF"; +} + +int VisualShaderNodeTextureSDF::get_input_port_count() const { + return 1; +} + +VisualShaderNodeTextureSDF::PortType VisualShaderNodeTextureSDF::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeTextureSDF::get_input_port_name(int p_port) const { + return "sdf_pos"; +} + +int VisualShaderNodeTextureSDF::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTextureSDF::PortType VisualShaderNodeTextureSDF::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeTextureSDF::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeTextureSDF::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] + " = texture_sdf(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + ");\n"; +} + +VisualShaderNodeTextureSDF::VisualShaderNodeTextureSDF() { +} + +// VisualShaderNodeTextureSDFNormal + +String VisualShaderNodeTextureSDFNormal::get_caption() const { + return "TextureSDFNormal"; +} + +int VisualShaderNodeTextureSDFNormal::get_input_port_count() const { + return 1; +} + +VisualShaderNodeTextureSDFNormal::PortType VisualShaderNodeTextureSDFNormal::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeTextureSDFNormal::get_input_port_name(int p_port) const { + return "sdf_pos"; +} + +int VisualShaderNodeTextureSDFNormal::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTextureSDFNormal::PortType VisualShaderNodeTextureSDFNormal::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeTextureSDFNormal::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeTextureSDFNormal::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(texture_sdf_normal(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; +} + +VisualShaderNodeTextureSDFNormal::VisualShaderNodeTextureSDFNormal() { +} + +// VisualShaderNodeSDFRaymarch + +String VisualShaderNodeSDFRaymarch::get_caption() const { + return "SDFRaymarch"; +} + +int VisualShaderNodeSDFRaymarch::get_input_port_count() const { + return 2; +} + +VisualShaderNodeSDFRaymarch::PortType VisualShaderNodeSDFRaymarch::get_input_port_type(int p_port) const { + if (p_port == 0 || p_port == 1) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeSDFRaymarch::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "from_pos"; + } else if (p_port == 1) { + return "to_pos"; + } + return String(); +} + +int VisualShaderNodeSDFRaymarch::get_output_port_count() const { + return 3; +} + +VisualShaderNodeSDFRaymarch::PortType VisualShaderNodeSDFRaymarch::get_output_port_type(int p_port) const { + if (p_port == 0) { + return PORT_TYPE_SCALAR; + } else if (p_port == 1) { + return PORT_TYPE_BOOLEAN; + } else if (p_port == 2) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeSDFRaymarch::get_output_port_name(int p_port) const { + if (p_port == 0) { + return "distance"; + } else if (p_port == 1) { + return "hit"; + } else if (p_port == 2) { + return "end_pos"; + } + return String(); +} + +String VisualShaderNodeSDFRaymarch::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{\n"; + + if (p_input_vars[0] == String()) { + code += "\t\tvec2 __from_pos = vec2(0.0f);\n"; + } else { + code += "\t\tvec2 __from_pos = " + p_input_vars[0] + ".xy;\n"; + } + + if (p_input_vars[1] == String()) { + code += "\t\tvec2 __to_pos = vec2(0.0f);\n"; + } else { + code += "\t\tvec2 __to_pos = " + p_input_vars[1] + ".xy;\n"; + } + + code += "\n\t\tvec2 __at = __from_pos;\n"; + code += "\t\tfloat __max_dist = distance(__from_pos, __to_pos);\n"; + code += "\t\tvec2 __dir = normalize(__to_pos - __from_pos);\n\n"; + + code += "\t\tfloat __accum = 0.0f;\n"; + code += "\t\twhile(__accum < __max_dist) {\n"; + code += "\t\t\tfloat __d = texture_sdf(__at);\n"; + code += "\t\t\t__accum += __d;\n"; + code += "\t\t\tif (__d < 0.01f) {\n"; + code += "\t\t\t\tbreak;\n"; + code += "\t\t\t}\n"; + code += "\t\t\t__at += __d * __dir;\n"; + code += "\t\t}\n"; + + code += "\t\tfloat __dist = min(__max_dist, __accum);\n"; + code += "\t\t" + p_output_vars[0] + " = __dist;\n"; + code += "\t\t" + p_output_vars[1] + " = __accum < __max_dist;\n"; + code += "\t\t" + p_output_vars[2] + " = vec3(__from_pos + __dir * __dist, 0.0f);\n"; + + code += "\t}\n"; + + return code; +} + +VisualShaderNodeSDFRaymarch::VisualShaderNodeSDFRaymarch() { + simple_decl = false; +} diff --git a/scene/resources/visual_shader_sdf_nodes.h b/scene/resources/visual_shader_sdf_nodes.h new file mode 100644 index 0000000000..0fcf5ec0b5 --- /dev/null +++ b/scene/resources/visual_shader_sdf_nodes.h @@ -0,0 +1,132 @@ +/*************************************************************************/ +/* visual_shader_sdf_nodes.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef VISUAL_SHADER_SDF_NODES_H +#define VISUAL_SHADER_SDF_NODES_H + +#include "scene/resources/visual_shader.h" + +class VisualShaderNodeSDFToScreenUV : public VisualShaderNode { + GDCLASS(VisualShaderNodeSDFToScreenUV, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + 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 override; + + VisualShaderNodeSDFToScreenUV(); +}; + +class VisualShaderNodeScreenUVToSDF : public VisualShaderNode { + GDCLASS(VisualShaderNodeScreenUVToSDF, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String get_input_port_default_hint(int p_port) const override; + 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 override; + + VisualShaderNodeScreenUVToSDF(); +}; + +class VisualShaderNodeTextureSDF : public VisualShaderNode { + GDCLASS(VisualShaderNodeTextureSDF, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + 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 override; + + VisualShaderNodeTextureSDF(); +}; + +class VisualShaderNodeTextureSDFNormal : public VisualShaderNode { + GDCLASS(VisualShaderNodeTextureSDFNormal, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + 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 override; + + VisualShaderNodeTextureSDFNormal(); +}; + +class VisualShaderNodeSDFRaymarch : public VisualShaderNode { + GDCLASS(VisualShaderNodeSDFRaymarch, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + 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 override; + + VisualShaderNodeSDFRaymarch(); +}; + +#endif // VISUAL_SHADER_SDF_NODES_H diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 1c753fdb91..156c7d0576 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +30,7 @@ #include "world_2d.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" #include "scene/2d/camera_2d.h" #include "scene/2d/visibility_notifier_2d.h" #include "scene/main/window.h" @@ -39,7 +39,7 @@ struct SpatialIndexer2D { struct CellRef { - int ref; + int ref = 0; _FORCE_INLINE_ int inc() { ref++; @@ -49,10 +49,6 @@ struct SpatialIndexer2D { ref--; return ref; } - - _FORCE_INLINE_ CellRef() { - ref = 0; - } }; struct CellKey { @@ -61,7 +57,7 @@ struct SpatialIndexer2D { int32_t x; int32_t y; }; - uint64_t key; + uint64_t key = 0; }; bool operator==(const CellKey &p_key) const { return key == p_key.key; } @@ -86,9 +82,9 @@ struct SpatialIndexer2D { Map<Viewport *, ViewportData> viewports; - bool changed; + bool changed = false; - uint64_t pass; + uint64_t pass = 0; void _notifier_update_cells(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect, bool p_add) { Point2i begin = p_rect.position; @@ -111,7 +107,7 @@ struct SpatialIndexer2D { ERR_CONTINUE(!E); if (E->get().notifiers[p_notifier].dec() == 0) { E->get().notifiers.erase(p_notifier); - if (E->get().notifiers.empty()) { + if (E->get().notifiers.is_empty()) { cells.erase(E); } } @@ -156,7 +152,7 @@ struct SpatialIndexer2D { } } - while (!removed.empty()) { + while (!removed.is_empty()) { p_notifier->_exit_viewport(removed.front()->get()); removed.pop_front(); } @@ -189,7 +185,7 @@ struct SpatialIndexer2D { removed.push_back(E->key()); } - while (!removed.empty()) { + while (!removed.is_empty()) { removed.front()->get()->_exit_viewport(p_viewport); removed.pop_front(); } @@ -211,7 +207,7 @@ struct SpatialIndexer2D { List<VisibilityNotifier2D *> added; List<VisibilityNotifier2D *> removed; - int visible_cells = (end.x - begin.x) * (end.y - begin.y); + uint64_t visible_cells = (uint64_t)(end.x - begin.x) * (uint64_t)(end.y - begin.y); if (visible_cells > 10000) { //well you zoomed out a lot, it's your problem. To avoid freezing in the for loops below, we'll manually check cell by cell @@ -271,12 +267,12 @@ struct SpatialIndexer2D { } } - while (!added.empty()) { + while (!added.is_empty()) { added.front()->get()->_enter_viewport(E->key()); added.pop_front(); } - while (!removed.empty()) { + while (!removed.is_empty()) { E->get().notifiers.erase(removed.front()->get()); removed.front()->get()->_exit_viewport(E->key()); removed.pop_front(); @@ -287,8 +283,6 @@ struct SpatialIndexer2D { } SpatialIndexer2D() { - pass = 0; - changed = false; cell_size = GLOBAL_DEF("world/2d/cell_size", 100); } }; @@ -341,8 +335,8 @@ void World2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World2D::get_direct_space_state); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "canvas", PROPERTY_HINT_NONE, "", 0), "", "get_canvas"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "canvas", PROPERTY_HINT_NONE, "", 0), "", "get_canvas"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState2D", 0), "", "get_direct_space_state"); } diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index c330719104..ae13367421 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-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,8 +31,8 @@ #ifndef WORLD_2D_H #define WORLD_2D_H -#include "core/project_settings.h" -#include "core/resource.h" +#include "core/config/project_settings.h" +#include "core/io/resource.h" #include "servers/physics_server_2d.h" class VisibilityNotifier2D; diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index 8100f150ef..9c0317454b 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -97,7 +97,7 @@ struct SpatialIndexer { } } - while (!removed.empty()) { + while (!removed.is_empty()) { p_notifier->_exit_camera(removed.front()->get()); removed.pop_front(); } @@ -125,7 +125,7 @@ struct SpatialIndexer { removed.push_back(E->key()); } - while (!removed.empty()) { + while (!removed.is_empty()) { removed.front()->get()->_exit_camera(p_camera); removed.pop_front(); } @@ -175,12 +175,12 @@ struct SpatialIndexer { } } - while (!added.empty()) { + while (!added.is_empty()) { added.front()->get()->_enter_camera(E->key()); added.pop_front(); } - while (!removed.empty()) { + while (!removed.is_empty()) { E->get().notifiers.erase(removed.front()->get()); removed.front()->get()->_exit_camera(E->key()); removed.pop_front(); @@ -321,8 +321,8 @@ void World3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "scenario", PROPERTY_HINT_NONE, "", 0), "", "get_scenario"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", 0), "", "get_scenario"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState3D", 0), "", "get_direct_space_state"); } diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h index 81a27a7349..3d6c33997e 100644 --- a/scene/resources/world_3d.h +++ b/scene/resources/world_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,7 +31,8 @@ #ifndef WORLD_3D_H #define WORLD_3D_H -#include "core/resource.h" +#include "core/io/resource.h" +#include "scene/resources/camera_effects.h" #include "scene/resources/environment.h" #include "servers/physics_server_3d.h" #include "servers/rendering_server.h" diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_margin_shape_3d.cpp index d613413b33..28d50e1921 100644 --- a/scene/resources/world_margin_shape_3d.cpp +++ b/scene/resources/world_margin_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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 "servers/physics_server_3d.h" -Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() { +Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const { Plane p = get_plane(); Vector<Vector3> points; @@ -69,7 +69,6 @@ void WorldMarginShape3D::set_plane(Plane p_plane) { plane = p_plane; _update_shape(); notify_change_to_owners(); - _change_notify("plane"); } Plane WorldMarginShape3D::get_plane() const { diff --git a/scene/resources/world_margin_shape_3d.h b/scene/resources/world_margin_shape_3d.h index acb479972b..00417c4408 100644 --- a/scene/resources/world_margin_shape_3d.h +++ b/scene/resources/world_margin_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (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,14 +39,14 @@ class WorldMarginShape3D : public Shape3D { protected: static void _bind_methods(); - virtual void _update_shape(); + virtual void _update_shape() override; public: void set_plane(Plane p_plane); Plane get_plane() const; - virtual Vector<Vector3> get_debug_mesh_lines(); - virtual real_t get_enclosing_radius() const { + virtual Vector<Vector3> get_debug_mesh_lines() const override; + virtual real_t get_enclosing_radius() const override { // Should be infinite? return 0; } |