diff options
170 files changed, 4496 insertions, 2123 deletions
diff --git a/.clang-format b/.clang-format index bc69a6a3a6..212bc25109 100644 --- a/.clang-format +++ b/.clang-format @@ -44,7 +44,6 @@ AllowShortIfStatementsOnASingleLine: true BreakBeforeTernaryOperators: false # BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: AfterColon -# BreakAfterJavaFieldAnnotations: false # BreakStringLiterals: true ColumnLimit: 0 # CommentPragmas: '^ IWYU pragma:' @@ -113,4 +112,8 @@ Language: ObjC ObjCBlockIndentWidth: 4 # ObjCSpaceAfterProperty: false # ObjCSpaceBeforeProtocolList: true +--- +### Java specific config ### +Language: Java +# BreakAfterJavaFieldAnnotations: false ... diff --git a/.gitignore b/.gitignore index 0de1e682a0..cbb0b5b133 100644 --- a/.gitignore +++ b/.gitignore @@ -91,6 +91,9 @@ bld/ # Hints for improving IntelliSense, created together with VS project cpp.hint +# Visualizers for the VS debugger +*.natvis + #NUNIT *.VisualState.xml TestResult.xml diff --git a/AUTHORS.md b/AUTHORS.md index 73712bbfc4..9a373896f8 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -32,6 +32,7 @@ name is available. Alket Rexhepi (alketii) Andrea Catania (AndreaCatania) Andreas Haas (Hinsbart) + Andy Moss (MillionOstrich) Anton Yabchinskiy (a12n) Aren Villanueva (kurikaesu) Ariel Manzur (punto-) @@ -43,6 +44,7 @@ name is available. Carl Olsson (not-surt) Dana Olson (adolson) Daniel J. Ramirez (djrm) + Dmitry Koteroff (Krakean) Дмитрий Сальников (DmitriySalnikov) Emmanuel Leblond (touilleMan) Fabio Alessandrelli (Faless) @@ -53,7 +55,7 @@ name is available. George Marques (vnen) Gerrit Großkopf (Grosskopf) Gilles Roudiere (groud) - Guilherme Felipe (guilhermefelipecgs) + Guilherme Felipe de C. G. da Silva (guilhermefelipecgs) Hein-Pieter van Braam (hpvb) Hiroshi Ogawa (hi-ogawa) Hubert Jarosz (Marqin) @@ -76,6 +78,7 @@ name is available. Masoud BH (masoudbh3) Matthias Hölzl (hoelzl) Max Hilbrunner (mhilbrunner) + Michael Alexsander Silva Dias (YeldhamDev) Nathan Warden (NathanWarden) Nuno Donato (nunodonato) Ovnuniarchos @@ -97,13 +100,18 @@ name is available. Timo (toger5) V. Vamsi Krishna (vkbsb) Vinzenz Feenstra (vinzenz) + Will Nations (willnationsdev) Wilson E. Alvarez (Rubonnek) + Yuri Roubinski (Chaosus) Zher Huei Lee (leezh) ZuBsPaCe 박한얼 (volzhs) bruvzg est31 + m4nu3lf marynate mrezai + rraallvv romulox-x + sersoong yg2f (SuperUserNameMan) @@ -12,7 +12,7 @@ generous deed immortalized in the next stable release of Godot Engine. ## Platinum sponsors -None so far, but your company could be the first! :) + Enjin Coin <https://enjincoin.io> ## Gold sponsors @@ -22,15 +22,16 @@ None so far, but your company could be the first! :) ## Mini sponsors Andreas - Andreas Hirschauer + Brandon Lamb Christian Uldall Pedersen Christoph Woinke E Hewert Hein-Pieter van Braam + Jamal Alyafei + Jordan M Lucas Matthieu Huvé Nathan Warden Neal Gompa (Conan Kudo) - Olimpiu Metiu Pascal Julien Ruslan Mustakov Slobodan Milnovic @@ -48,15 +49,19 @@ None so far, but your company could be the first! :) Officine Pixel S.n.c. Rémi Verschelde Stephan Lanfermann + Zaven Muradyan Andreas Schüle Austen McRae Bernhard Liebl + Cody Brocious Gerald E Butler Jahn Johansen - Jordan M Lucas + Johannes Wuensch Kris Michael + Libre-Dépanne Ranoller + Svenne Krap BanjoNode2D Chris Serino @@ -80,40 +85,49 @@ None so far, but your company could be the first! :) Amanda Haldy Andreas Haas - Andres Cuevas Arnaud Verstuyf - Bryanna M Chris Brown Cody Parker D + Daniel Eliasinski + Daniel Langegger + Eric Monson Ezra Theunissen flesk François Cantin Giovanni Solimeno - Hendrik Mans Jeppe Zapp Justin Arnold Justo Delgado Baudà Leandro Voltolino Lucien Boudy Noah + Patrick Schnorbus + Pete Goodwin Ryan Estes + Ted + Travis Womack Trent McPheron ## Silver donors 1D_Inc + Abe Pazos + Alder Stefano Alessandro Senese Alex Barsukov + Andres Cuevas Anthony Bongiovanni Avencherus Bastian Böhm Ben Vercammen Blair Allen Bryan Stevenson + Casey Foote Christian Baune Christian Winter Collin Shooltz + Daniel Egger Daniel Kaplan David Cravens David May @@ -122,11 +136,13 @@ None so far, but your company could be the first! :) Eric Martini Fabian Becker fengjiongmax + Francesco Lisi Frank C. Simmons + Fredy Romero Sam + G3Dev sà rl Geequlim Gerrit Großkopf Guldoman - Gustav Dahlström HardRound hatniX HeartBeast @@ -134,6 +150,7 @@ None so far, but your company could be the first! :) Hunter Jones Jaime Ruiz-Borau Vizárraga Jeff Hungerford + Jerry Chen Jesse Liles joe513 Jonathon @@ -146,15 +163,15 @@ None so far, but your company could be the first! :) Kevin Boyer Kevin Kamper Meejach Petersen Klavdij Voncina - Kobi Malul Linus Lind Lundgren Lisandro Lorea magodev + Markus Wiesner Martin Novák Matthew Fitzpatrick - Matthew Valancy Matthias Hölzl Max R.R. Collada + memoryruins mhilbrunner Michael Gringauz Michael Tintiuc @@ -172,17 +189,18 @@ None so far, but your company could be the first! :) Patrick Nafarrete Paul Mason Paweł Kowal - Pete Goodwin + Pierre-Igor Berthet Pietro Vertechi rayos Richman Stewart + Rodolfo Baeza + Roger Burgess Roger Smith Roman Tinkov Sam Van Campenhout Sasori Olkof Scott D. Yelich Sootstone - TheHappieCat Theo Cranmore Thomas Norman Tom Larrow diff --git a/core/class_db.cpp b/core/class_db.cpp index 57e88044b5..edd49fe95f 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -1036,7 +1036,6 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia r_value = *c; return true; } - //if (check->constant_map.fin) check = check->inherits_ptr; } @@ -1163,24 +1162,6 @@ bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inhe return false; } -bool ClassDB::get_setter_and_type_for_property(const StringName &p_class, const StringName &p_prop, StringName &r_class, StringName &r_setter) { - - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - - if (check->property_setget.has(p_prop)) { - r_class = check->name; - r_setter = check->property_setget[p_prop].setter; - return true; - } - - check = check->inherits_ptr; - } - - return false; -} - #ifdef DEBUG_METHODS_ENABLED MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { StringName mdname = method_name.name; diff --git a/core/class_db.h b/core/class_db.h index b8b681301d..55fe01ec6d 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -349,8 +349,6 @@ public: static StringName get_category(const StringName &p_node); - static bool get_setter_and_type_for_property(const StringName &p_class, const StringName &p_prop, StringName &r_class, StringName &r_setter); - static void set_class_enabled(StringName p_class, bool p_enable); static bool is_class_enabled(StringName p_class); diff --git a/core/io/json.cpp b/core/io/json.cpp index ddfc792cc7..82e938d2db 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -43,7 +43,7 @@ const char *JSON::tk_name[TK_MAX] = { "EOF", }; -static String _make_indent(const String& p_indent, int p_size) { +static String _make_indent(const String &p_indent, int p_size) { String indent_text = ""; if (!p_indent.empty()) { @@ -53,7 +53,7 @@ static String _make_indent(const String& p_indent, int p_size) { return indent_text; } -String JSON::_print_var(const Variant &p_var, const String& p_indent, int p_cur_indent, bool p_sort_keys) { +String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys) { String colon = ":"; String end_statement = ""; @@ -116,7 +116,7 @@ String JSON::_print_var(const Variant &p_var, const String& p_indent, int p_cur_ } } -String JSON::print(const Variant &p_var, const String& p_indent, bool p_sort_keys) { +String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys) { return _print_var(p_var, p_indent, 0, p_sort_keys); } diff --git a/core/io/json.h b/core/io/json.h index 5e1a89f069..fbb7875c7c 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -64,7 +64,7 @@ class JSON { static const char *tk_name[TK_MAX]; - static String _print_var(const Variant &p_var, const String& p_indent, int p_cur_indent, bool p_sort_keys); + static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys); static Error _get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str); static Error _parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str); @@ -72,7 +72,7 @@ class JSON { static Error _parse_object(Dictionary &object, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str); public: - static String print(const Variant &p_var, const String& p_indent = "", bool p_sort_keys = true); + static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true); static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); }; diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp index c77fe96ff2..11003c1cd5 100644 --- a/core/math/math_2d.cpp +++ b/core/math/math_2d.cpp @@ -222,35 +222,6 @@ Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, c (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); return out; - - /* - real_t mu = p_t; - real_t mu2 = mu*mu; - - Vector2 a0 = p_post_b - p_b - p_pre_a + *this; - Vector2 a1 = p_pre_a - *this - a0; - Vector2 a2 = p_b - p_pre_a; - Vector2 a3 = *this; - - return ( a0*mu*mu2 + a1*mu2 + a2*mu + a3 ); -*/ - /* - real_t t = p_t; - real_t t2 = t*t; - real_t t3 = t2*t; - - real_t a = 2.0*t3- 3.0*t2 + 1; - real_t b = -2.0*t3+ 3.0*t2; - real_t c = t3- 2.0*t2 + t; - real_t d = t3- t2; - - Vector2 p_a=*this; - - return Vector2( - (a * p_a.x) + (b *p_b.x) + (c * p_pre_a.x) + (d * p_post_b.x), - (a * p_a.y) + (b *p_b.y) + (c * p_pre_a.y) + (d * p_post_b.y) - ); -*/ } // slide returns the component of the vector along the given plane, specified by its normal vector. diff --git a/core/math/math_2d.h b/core/math/math_2d.h index d788318f5e..60351445c0 100644 --- a/core/math/math_2d.h +++ b/core/math/math_2d.h @@ -382,6 +382,11 @@ struct Rect2 { size = end - begin; } + inline Rect2 abs() const { + + return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); + } + operator String() const { return String(position) + ", " + String(size); } Rect2() {} diff --git a/core/os/os.h b/core/os/os.h index 4f968020cc..979ad7e92a 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -92,14 +92,16 @@ public: bool resizable; bool borderless_window; bool maximized; + bool use_vsync; float get_aspect() const { return (float)width / (float)height; } - VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false, bool p_maximized = false) { + VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false, bool p_maximized = false, bool p_use_vsync = false) { width = p_width; height = p_height; fullscreen = p_fullscreen; resizable = p_resizable; borderless_window = p_borderless_window; maximized = p_maximized; + use_vsync = p_use_vsync; } }; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 991573e8d7..f66cce85c9 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -360,6 +360,7 @@ struct _VariantCall { VCALL_LOCALMEM2R(Rect2, grow_margin); VCALL_LOCALMEM4R(Rect2, grow_individual); VCALL_LOCALMEM1R(Rect2, expand); + VCALL_LOCALMEM0R(Rect2, abs); VCALL_LOCALMEM0R(Vector3, min_axis); VCALL_LOCALMEM0R(Vector3, max_axis); @@ -1526,6 +1527,7 @@ void register_variant_methods() { ADDFUNC2R(RECT2, RECT2, Rect2, grow_margin, INT, "margin", REAL, "by", varray()); ADDFUNC4R(RECT2, RECT2, Rect2, grow_individual, REAL, "left", REAL, "top", REAL, "right", REAL, " bottom", varray()); ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray()); + ADDFUNC0R(RECT2, RECT2, Rect2, abs, varray()); ADDFUNC0R(VECTOR3, INT, Vector3, min_axis, varray()); ADDFUNC0R(VECTOR3, INT, Vector3, max_axis, varray()); diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index c3933443a0..93b01a466b 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -30,6 +30,16 @@ Clear the animation (clear all tracks and reset all). </description> </method> + <method name="copy_track"> + <return type="void"> + </return> + <argument index="0" name="track" type="int"> + </argument> + <argument index="1" name="to_animation" type="Animation"> + </argument> + <description> + </description> + </method> <method name="find_track" qualifiers="const"> <return type="int"> </return> @@ -244,6 +254,14 @@ Insert a generic key in a given track. </description> </method> + <method name="track_is_enabled" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <description> + </description> + </method> <method name="track_is_imported" qualifiers="const"> <return type="bool"> </return> @@ -293,6 +311,16 @@ Remove a key by position (seconds) in a given track. </description> </method> + <method name="track_set_enabled"> + <return type="void"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <argument index="1" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> <method name="track_set_imported"> <return type="void"> </return> diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index 3b1ce37619..d61211bb6b 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -74,20 +74,6 @@ Returns the name of [code]animation[/code] or empty string if not found. </description> </method> - <method name="get_anim_length" qualifiers="const"> - <return type="float"> - </return> - <description> - Get the length (in seconds) of the currently playing animation. - </description> - </method> - <method name="get_anim_position" qualifiers="const"> - <return type="float"> - </return> - <description> - Get the position (in seconds) of the currently playing animation. - </description> - </method> <method name="get_animation" qualifiers="const"> <return type="Animation"> </return> @@ -115,11 +101,18 @@ Get the blend time (in seconds) between two animations, referenced by their names. </description> </method> - <method name="get_current_animation" qualifiers="const"> - <return type="String"> + <method name="get_current_animation_length" qualifiers="const"> + <return type="float"> </return> <description> - Returns the name of the currently playing animation. + Get the length (in seconds) of the currently playing animation. + </description> + </method> + <method name="get_current_animation_position" qualifiers="const"> + <return type="float"> + </return> + <description> + Get the position (in seconds) of the currently playing animation. </description> </method> <method name="has_animation" qualifiers="const"> @@ -217,15 +210,6 @@ Specify a blend time (in seconds) between two animations, referenced by their names. </description> </method> - <method name="set_current_animation"> - <return type="void"> - </return> - <argument index="0" name="anim" type="String"> - </argument> - <description> - Set the current animation (even if no playback occurs). Using set_current_animation() and set_active() are similar to calling play(). - </description> - </method> <method name="stop"> <return type="void"> </return> @@ -250,8 +234,10 @@ <member name="autoplay" type="String" setter="set_autoplay" getter="get_autoplay"> The name of the animation to play when the scene loads. Default value: [code]""[/code]. </member> + <member name="current_animation" type="String" setter="set_current_animation" getter="get_current_animation"> + The name of the current animation. Default value: [code]""[/code]. + </member> <member name="playback_default_blend_time" type="float" setter="set_default_blend_time" getter="get_default_blend_time"> - The default time in which to blend animations. Ranges from 0 to 4096 with 0.01 precision. Default value: [code]0[/code]. </member> <member name="playback_process_mode" type="int" setter="set_animation_process_mode" getter="get_animation_process_mode" enum="AnimationPlayer.AnimationProcessMode"> The process notification in which to update animations. Default value: [enum ANIMATION_PROCESS_IDLE]. diff --git a/doc/classes/AnimationTreePlayer.xml b/doc/classes/AnimationTreePlayer.xml index 4fb33eb5a3..ecd1f81951 100644 --- a/doc/classes/AnimationTreePlayer.xml +++ b/doc/classes/AnimationTreePlayer.xml @@ -4,7 +4,7 @@ Animation Player that uses a node graph for the blending. </brief_description> <description> - Animation Player that uses a node graph for the blending. This kind of player is very useful when animating character or other skeleton based rigs, because it can combine several animations to form a desired pose. + A node graph tool for blending multiple animations bound to an [AnimationPlayer]. Especially useful for animating characters or other skeleton-based rigs. It can combine several animations to form a desired pose. </description> <tutorials> </tutorials> @@ -19,7 +19,7 @@ <argument index="1" name="id" type="String"> </argument> <description> - Add a node of a given type in the graph with given id. + Adds a [code]type[/code] node to the graph with name [code]id[/code]. </description> </method> <method name="advance"> @@ -28,6 +28,7 @@ <argument index="0" name="delta" type="float"> </argument> <description> + Shifts position in the animation timeline. Delta is the time in seconds to shift. </description> </method> <method name="animation_node_get_animation" qualifiers="const"> @@ -36,7 +37,7 @@ <argument index="0" name="id" type="String"> </argument> <description> - Returns an animation given its name. + Returns the [AnimationPlayer]'s animation bound to the [code]AnimationTreePlayer[/code]'s animation node with name [code]id[/code]. </description> </method> <method name="animation_node_get_master_animation" qualifiers="const"> @@ -45,6 +46,7 @@ <argument index="0" name="id" type="String"> </argument> <description> + Returns the name of the [member master_player]'s animation bound to this animation node. </description> </method> <method name="animation_node_set_animation"> @@ -55,7 +57,7 @@ <argument index="1" name="animation" type="Animation"> </argument> <description> - Set the animation for an animation node. + Binds a new animation from the [member master_player] to the [code]AnimationTreePlayer[/code]'s animation node with name [code]id[/code]. </description> </method> <method name="animation_node_set_filter_path"> @@ -68,6 +70,7 @@ <argument index="2" name="enable" type="bool"> </argument> <description> + If [code]enable[/code] is [code]true[/code], the animation node with ID [code]id[/code] turns off the track modifying the property at [code]path[/code]. The modified node's children continue to animate. </description> </method> <method name="animation_node_set_master_animation"> @@ -78,6 +81,7 @@ <argument index="1" name="source" type="String"> </argument> <description> + Binds the animation named [code]source[/code] from [member master_player] to the animation node [code]id[/code]. Recalculates caches. </description> </method> <method name="are_nodes_connected" qualifiers="const"> @@ -123,6 +127,7 @@ <argument index="2" name="enable" type="bool"> </argument> <description> + If [code]enable[/code] is [code]true[/code], the blend2 node with ID [code]id[/code] turns off the track modifying the property at [code]path[/code]. The modified node's children continue to animate. </description> </method> <method name="blend3_node_get_amount" qualifiers="const"> @@ -189,18 +194,6 @@ Disconnects nodes connected to [code]id[/code] at the specified input slot. </description> </method> - <method name="get_base_path" qualifiers="const"> - <return type="NodePath"> - </return> - <description> - </description> - </method> - <method name="get_master_player" qualifiers="const"> - <return type="NodePath"> - </return> - <description> - </description> - </method> <method name="get_node_list"> <return type="PoolStringArray"> </return> @@ -208,13 +201,6 @@ Returns a PoolStringArray containing the name of all nodes. </description> </method> - <method name="is_active" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns whether this AnimationTreePlayer is active. - </description> - </method> <method name="mix_node_get_amount" qualifiers="const"> <return type="float"> </return> @@ -423,6 +409,7 @@ <argument index="2" name="enable" type="bool"> </argument> <description> + If [code]enable[/code] is [code]true[/code], the oneshot node with ID [code]id[/code] turns off the track modifying the property at [code]path[/code]. The modified node's children continue to animate. </description> </method> <method name="oneshot_node_start"> @@ -440,13 +427,14 @@ <argument index="0" name="id" type="String"> </argument> <description> - Stops a OneShot node given its name. + Stops the OneShot node with name [code]id[/code]. </description> </method> <method name="recompute_caches"> <return type="void"> </return> <description> + Manually recalculates the cache of track information generated from animation nodes. Needed when external sources modify the animation nodes' state. </description> </method> <method name="remove_node"> @@ -455,6 +443,7 @@ <argument index="0" name="id" type="String"> </argument> <description> + Removes the animation node with name [code]id[/code]. </description> </method> <method name="reset"> @@ -464,39 +453,13 @@ Resets this AnimationTreePlayer. </description> </method> - <method name="set_active"> - <return type="void"> - </return> - <argument index="0" name="enabled" type="bool"> - </argument> - <description> - Sets whether this AnimationTreePlayer is active. AnimationTreePlayer will start processing if set to active. - </description> - </method> - <method name="set_base_path"> - <return type="void"> - </return> - <argument index="0" name="path" type="NodePath"> - </argument> - <description> - Sets base path of this AnimationTreePlayer. - </description> - </method> - <method name="set_master_player"> - <return type="void"> - </return> - <argument index="0" name="nodepath" type="NodePath"> - </argument> - <description> - </description> - </method> <method name="timescale_node_get_scale" qualifiers="const"> <return type="float"> </return> <argument index="0" name="id" type="String"> </argument> <description> - Returns time scale value of a TimeScale node given its name. + Returns time scale value of the TimeScale node with name [code]id[/code]. </description> </method> <method name="timescale_node_set_scale"> @@ -507,7 +470,7 @@ <argument index="1" name="scale" type="float"> </argument> <description> - Sets time scale value of a TimeScale node given its name and value. + Sets the time scale of the TimeScale node with name [code]id[/code] to [code]scale[/code]. </description> </method> <method name="timeseek_node_seek"> @@ -518,7 +481,7 @@ <argument index="1" name="seconds" type="float"> </argument> <description> - Sets time seek value of a TimeSeek node given its name and value. + Sets the time seek value of the TimeSeek node with name [code]id[/code] to [code]seconds[/code] </description> </method> <method name="transition_node_delete_input"> @@ -529,6 +492,7 @@ <argument index="1" name="input_idx" type="int"> </argument> <description> + Deletes the input at [code]input_idx[/code] for the transition node with name [code]id[/code]. </description> </method> <method name="transition_node_get_current" qualifiers="const"> @@ -537,6 +501,7 @@ <argument index="0" name="id" type="String"> </argument> <description> + Returns the index of the currently evaluated input for the transition node with name [code]id[/code]. </description> </method> <method name="transition_node_get_input_count" qualifiers="const"> @@ -545,6 +510,7 @@ <argument index="0" name="id" type="String"> </argument> <description> + Returns the number of inputs for the transition node with name [code]id[/code]. </description> </method> <method name="transition_node_get_xfade_time" qualifiers="const"> @@ -553,6 +519,7 @@ <argument index="0" name="id" type="String"> </argument> <description> + Returns the cross fade time for the transition node with name [code]id[/code]. </description> </method> <method name="transition_node_has_input_auto_advance" qualifiers="const"> @@ -563,6 +530,7 @@ <argument index="1" name="input_idx" type="int"> </argument> <description> + Returns [code]true[/code] if the input at [code]input_idx[/code] on transition node with name [code]id[/code] is set to automatically advance to the next input upon completion. </description> </method> <method name="transition_node_set_current"> @@ -573,6 +541,7 @@ <argument index="1" name="input_idx" type="int"> </argument> <description> + The transition node with name [code]id[/code] sets its current input at [code]input_idx[/code]. </description> </method> <method name="transition_node_set_input_auto_advance"> @@ -585,6 +554,7 @@ <argument index="2" name="enable" type="bool"> </argument> <description> + The transition node with name [code]id[/code] advances to its next input automatically when the input at [code]input_idx[/code] completes. </description> </method> <method name="transition_node_set_input_count"> @@ -595,6 +565,7 @@ <argument index="1" name="count" type="int"> </argument> <description> + Resizes the number of inputs available for the transition node with name [code]id[/code]. </description> </method> <method name="transition_node_set_xfade_time"> @@ -605,11 +576,22 @@ <argument index="1" name="time_sec" type="float"> </argument> <description> + The transition node with name [code]id[/code] sets its cross fade time to [code]time_sec[/code]. </description> </method> </methods> <members> + <member name="active" type="bool" setter="set_active" getter="is_active"> + If [code]true[/code] the [code]AnimationTreePlayer[/code] is able to play animations. Default value: [code]false[/code]. + </member> + <member name="base_path" type="NodePath" setter="set_base_path" getter="get_base_path"> + The node from which to relatively access other nodes. Default value: [code]".."[/code]. + </member> + <member name="master_player" type="NodePath" setter="set_master_player" getter="get_master_player"> + The path to the [AnimationPlayer] from which this [code]AnimationTreePlayer[/code] binds animations to animation nodes. + </member> <member name="playback_process_mode" type="int" setter="set_animation_process_mode" getter="get_animation_process_mode" enum="AnimationTreePlayer.AnimationProcessMode"> + The thread in which to update animations. Default value: [enum ANIMATION_PROCESS_IDLE]. </member> </members> <constants> @@ -644,8 +626,10 @@ Transition node. </constant> <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessMode"> + Process animation during the physics process. This is especially useful when animating physics bodies. </constant> <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode"> + Process animation during the idle process. </constant> </constants> </class> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index a7f9a6e09c..9445a1732e 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -284,6 +284,16 @@ </argument> <description> Sort the array using a custom method and return reference to the array. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return true if the first argument is less than the second, and return false otherwise. Note: you cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior. + [codeblock] + class MyCustomSorter: + static func sort(a, b): + if a[0] < b[0]: + return true + return false + + var my_items = [[5, "Potato"], [9, "Rice"], [4, "Tomato"]] + my_items.sort_custom(MyCustomSorter, "sort") + [/codeblock] </description> </method> </methods> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 4a567981e6..cf0b482b07 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -88,6 +88,34 @@ Draw a line from a 2D point to another, with a given color and width. It can be optionally antialiased. </description> </method> + <method name="draw_multiline"> + <return type="void"> + </return> + <argument index="0" name="points" type="PoolVector2Array"> + </argument> + <argument index="1" name="color" type="Color"> + </argument> + <argument index="2" name="width" type="float" default="1.0"> + </argument> + <argument index="3" name="antialiased" type="bool" default="false"> + </argument> + <description> + </description> + </method> + <method name="draw_multiline_colors"> + <return type="void"> + </return> + <argument index="0" name="points" type="PoolVector2Array"> + </argument> + <argument index="1" name="colors" type="PoolColorArray"> + </argument> + <argument index="2" name="width" type="float" default="1.0"> + </argument> + <argument index="3" name="antialiased" type="bool" default="false"> + </argument> + <description> + </description> + </method> <method name="draw_polygon"> <return type="void"> </return> diff --git a/doc/classes/ConcavePolygonShape2D.xml b/doc/classes/ConcavePolygonShape2D.xml index 1910b1d62d..1d2aabd6ea 100644 --- a/doc/classes/ConcavePolygonShape2D.xml +++ b/doc/classes/ConcavePolygonShape2D.xml @@ -15,6 +15,7 @@ </methods> <members> <member name="segments" type="PoolVector2Array" setter="set_segments" getter="get_segments"> + The array of points that make up the [code]ConcavePolygonShape2D[/code]'s line segments. </member> </members> <constants> diff --git a/doc/classes/CubeMap.xml b/doc/classes/CubeMap.xml index a7857dba78..7444fb0258 100644 --- a/doc/classes/CubeMap.xml +++ b/doc/classes/CubeMap.xml @@ -4,7 +4,7 @@ A CubeMap is a 6 sided 3D texture. </brief_description> <description> - A CubeMap is a 6 sided 3D texture typically used for faking reflections. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods. + A 6-sided 3D texture typically used for faking reflections. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods. </description> <tutorials> </tutorials> @@ -15,13 +15,14 @@ <return type="int"> </return> <description> + Returns the render flags for the [code]CubeMap[/code]. See the [code]FLAG_*[/code] constants for details. </description> </method> <method name="get_height" qualifiers="const"> <return type="int"> </return> <description> - Returns the CubeMap's height. + Returns the [code]CubeMap[/code]'s height. </description> </method> <method name="get_side" qualifiers="const"> @@ -30,14 +31,14 @@ <argument index="0" name="side" type="int" enum="CubeMap.Side"> </argument> <description> - Returns an [Image] for a side of the CubeMap using one of the [code]SIDE_*[/code] constants or an integer 0-5. + Returns an [Image] for a side of the [code]CubeMap[/code] using one of the [code]SIDE_*[/code] constants or an integer 0-5. </description> </method> <method name="get_width" qualifiers="const"> <return type="int"> </return> <description> - Returns the CubeMap's width. + Returns the [code]CubeMap[/code]'s width. </description> </method> <method name="set_flags"> @@ -46,6 +47,7 @@ <argument index="0" name="flags" type="int"> </argument> <description> + Returns the render flags for the [code]CubeMap[/code]. See the [code]FLAG_*[/code] constants for details. </description> </method> <method name="set_side"> @@ -56,44 +58,57 @@ <argument index="1" name="image" type="Image"> </argument> <description> - Sets an [Image] for a side of the CubeMap using one of the [code]SIDE_*[/code] constants or an integer 0-5. + Sets an [Image] for a side of the [code]CubeMap[/code] using one of the [code]SIDE_*[/code] constants or an integer 0-5. </description> </method> </methods> <members> <member name="lossy_storage_quality" type="float" setter="set_lossy_storage_quality" getter="get_lossy_storage_quality"> - The lossy storage quality of the CubeMap if the storage mode is set to STORAGE_COMPRESS_LOSSY. + The lossy storage quality of the [code]CubeMap[/code] if the storage mode is set to STORAGE_COMPRESS_LOSSY. </member> - <member name="storage_mode" type="int" setter="set_storage" getter="get_storage" enum="CubeMap.Storage"> - The CubeMap's storage mode. See [code]STORAGE_*[/code] constants. + <member name="storage_mode" type="CubeMap.Storage" setter="set_storage" getter="get_storage" enum="CubeMap.Storage"> + The [code]CubeMap[/code]'s storage mode. See [code]STORAGE_*[/code] constants. </member> </members> <constants> <constant name="STORAGE_RAW" value="0" enum="Storage"> + Store the [code]CubeMap[/code] without any compression. </constant> <constant name="STORAGE_COMPRESS_LOSSY" value="1" enum="Storage"> + Store the [code]CubeMap[/code] with strong compression that reduces image quality. </constant> <constant name="STORAGE_COMPRESS_LOSSLESS" value="2" enum="Storage"> + Store the [code]CubeMap[/code] with moderate compression that doesn't reduce image quality. </constant> <constant name="SIDE_LEFT" value="0" enum="Side"> + Identifier for the left face of the [code]CubeMap[/code]. </constant> <constant name="SIDE_RIGHT" value="1" enum="Side"> + Identifier for the right face of the [code]CubeMap[/code]. </constant> <constant name="SIDE_BOTTOM" value="2" enum="Side"> + Identifier for the bottom face of the [code]CubeMap[/code]. </constant> <constant name="SIDE_TOP" value="3" enum="Side"> + Identifier for the top face of the [code]CubeMap[/code]. </constant> <constant name="SIDE_FRONT" value="4" enum="Side"> + Identifier for the front face of the [code]CubeMap[/code]. </constant> <constant name="SIDE_BACK" value="5" enum="Side"> + Identifier for the back face of the [code]CubeMap[/code]. </constant> <constant name="FLAG_MIPMAPS" value="1" enum="Flags"> + Generate mipmaps, to enable smooth zooming out of the texture. </constant> <constant name="FLAG_REPEAT" value="2" enum="Flags"> + Repeat (instead of clamp to edge). </constant> <constant name="FLAG_FILTER" value="4" enum="Flags"> + Turn on magnifying filter, to enable smooth zooming in of the texture. </constant> <constant name="FLAGS_DEFAULT" value="7" enum="Flags"> + Default flags. Generate mipmaps, repeat, and filter are enabled. </constant> </constants> </class> diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml index f577a4676f..54b3accb19 100644 --- a/doc/classes/EditorFileSystem.xml +++ b/doc/classes/EditorFileSystem.xml @@ -33,6 +33,7 @@ <argument index="0" name="path" type="String"> </argument> <description> + Returns a view into the filesystem at [code]path[/code]. </description> </method> <method name="get_scanning_progress" qualifiers="const"> @@ -83,6 +84,7 @@ <argument index="0" name="resources" type="PoolStringArray"> </argument> <description> + Remitted if a resource is reimported. </description> </signal> <signal name="sources_changed"> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index edd1f721b5..ada0ee56a8 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -82,6 +82,14 @@ <description> </description> </method> + <method name="add_scene_import_plugin"> + <return type="void"> + </return> + <argument index="0" name="scene_importer" type="EditorSceneImporter"> + </argument> + <description> + </description> + </method> <method name="add_tool_submenu_item"> <return type="void"> </return> @@ -176,6 +184,12 @@ <description> </description> </method> + <method name="get_plugin_icon" qualifiers="virtual"> + <return type="Object"> + </return> + <description> + </description> + </method> <method name="get_plugin_name" qualifiers="virtual"> <return type="String"> </return> @@ -295,6 +309,14 @@ <description> </description> </method> + <method name="remove_scene_import_plugin"> + <return type="void"> + </return> + <argument index="0" name="scene_importer" type="EditorSceneImporter"> + </argument> + <description> + </description> + </method> <method name="save_external_data" qualifiers="virtual"> <return type="void"> </return> diff --git a/doc/classes/EditorSceneImporter.xml b/doc/classes/EditorSceneImporter.xml new file mode 100644 index 0000000000..69fe4050f4 --- /dev/null +++ b/doc/classes/EditorSceneImporter.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorSceneImporter" inherits="Reference" category="Core" version="3.0-beta"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="_get_extensions" qualifiers="virtual"> + <return type="Array"> + </return> + <description> + </description> + </method> + <method name="_get_import_flags" qualifiers="virtual"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="_import_animation" qualifiers="virtual"> + <return type="Animation"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="flags" type="int"> + </argument> + <argument index="2" name="bake_fps" type="int"> + </argument> + <description> + </description> + </method> + <method name="_import_scene" qualifiers="virtual"> + <return type="Node"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="flags" type="int"> + </argument> + <argument index="2" name="bake_fps" type="int"> + </argument> + <description> + </description> + </method> + <method name="import_animation_from_other_importer"> + <return type="Animation"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="flags" type="int"> + </argument> + <argument index="2" name="bake_fps" type="int"> + </argument> + <description> + </description> + </method> + <method name="import_scene_from_other_importer"> + <return type="Node"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="flags" type="int"> + </argument> + <argument index="2" name="bake_fps" type="int"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + <constant name="IMPORT_SCENE" value="1"> + </constant> + <constant name="IMPORT_ANIMATION" value="2"> + </constant> + <constant name="IMPORT_ANIMATION_DETECT_LOOP" value="4"> + </constant> + <constant name="IMPORT_ANIMATION_OPTIMIZE" value="8"> + </constant> + <constant name="IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS" value="16"> + </constant> + <constant name="IMPORT_ANIMATION_KEEP_VALUE_TRACKS" value="32"> + </constant> + <constant name="IMPORT_GENERATE_TANGENT_ARRAYS" value="256"> + </constant> + <constant name="IMPORT_FAIL_ON_MISSING_DEPENDENCIES" value="512"> + </constant> + <constant name="IMPORT_MATERIALS_IN_INSTANCES" value="1024"> + </constant> + <constant name="IMPORT_USE_COMPRESSION" value="2048"> + </constant> + </constants> +</class> diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index 8057e95d44..3387b4a2ed 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -103,6 +103,9 @@ </member> <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="FileDialog.Mode"> </member> + <member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title"> + If [code]true[/code], changing the [code]mode[/code] property will set the window title accordingly (e. g. setting mode to [code]MODE_OPEN_FILE[/code] will change the window title to "Open a File"). + </member> <member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files"> </member> </members> diff --git a/doc/classes/KinematicBody.xml b/doc/classes/KinematicBody.xml index c5204fd0bf..43db8ed43a 100644 --- a/doc/classes/KinematicBody.xml +++ b/doc/classes/KinematicBody.xml @@ -102,6 +102,12 @@ </method> </methods> <members> + <member name="axis_lock_x" type="bool" setter="set_axis_lock_x" getter="get_axis_lock_x"> + </member> + <member name="axis_lock_y" type="bool" setter="set_axis_lock_y" getter="get_axis_lock_y"> + </member> + <member name="axis_lock_z" type="bool" setter="set_axis_lock_z" getter="get_axis_lock_z"> + </member> <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin"> If the body is at least this close to another body, this body will consider them to be colliding. </member> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index c681886546..465b68171e 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -49,6 +49,10 @@ </description> </method> </methods> + <members> + <member name="lightmap_size_hint" type="Vector2" setter="set_lightmap_size_hint" getter="get_lightmap_size_hint"> + </member> + </members> <constants> <constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType"> Render array as points (one vertex equals one point). diff --git a/doc/classes/MeshInstance.xml b/doc/classes/MeshInstance.xml index f754341fef..9273e87430 100644 --- a/doc/classes/MeshInstance.xml +++ b/doc/classes/MeshInstance.xml @@ -4,7 +4,7 @@ Node that instances meshes into a scenario. </brief_description> <description> - MeshInstance is a [Node] that takes a [Mesh] resource and adds it to the current scenario by creating an instance of it. This is the class most often used to get 3D geometry rendered and can be used to instance a single [Mesh] in many places. This allows to reuse geometry and save on resources. When a [Mesh] has to be instanced more than thousands of times at close proximity, consider using a [MultiMesh] in a [MultiMeshInstance] instead. + MeshInstance is a node that takes a [Mesh] resource and adds it to the current scenario by creating an instance of it. This is the class most often used to get 3D geometry rendered and can be used to instance a single [Mesh] in many places. This allows to reuse geometry and save on resources. When a [Mesh] has to be instanced more than thousands of times at close proximity, consider using a [MultiMesh] in a [MultiMeshInstance] instead. </description> <tutorials> </tutorials> @@ -15,20 +15,21 @@ <return type="void"> </return> <description> - This helper creates a [StaticBody] child [Node] with a [ConvexPolygonShape] [CollisionShape] calculated from the mesh geometry. It's mainly used for testing. + This helper creates a [StaticBody] child node with a [ConvexPolygonShape] collision shape calculated from the mesh geometry. It's mainly used for testing. </description> </method> <method name="create_debug_tangents"> <return type="void"> </return> <description> + This helper creates a [MeshInstance] child node with gizmos at every vertex calculated from the mesh geometry. It's mainly used for testing. </description> </method> <method name="create_trimesh_collision"> <return type="void"> </return> <description> - This helper creates a [StaticBody] child [Node] with a [ConcavePolygonShape] [CollisionShape] calculated from the mesh geometry. It's mainly used for testing. + This helper creates a [StaticBody] child node with a [ConcavePolygonShape] collision shape calculated from the mesh geometry. It's mainly used for testing. </description> </method> <method name="get_surface_material" qualifiers="const"> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index e2198c3e15..78591e2bf8 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -498,7 +498,7 @@ <return type="void"> </return> <description> - Removes a node and set all its children as children of the parent node (if exists). All even subscriptions that pass by the removed node will be unsubscribed. + Removes a node and set all its children as children of the parent node (if exists). All event subscriptions that pass by the removed node will be unsubscribed. </description> </method> <method name="remove_child"> diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml index eb7c735277..8f3d77d841 100644 --- a/doc/classes/PhysicsServer.xml +++ b/doc/classes/PhysicsServer.xml @@ -352,7 +352,7 @@ </description> </method> <method name="body_get_axis_lock" qualifiers="const"> - <return type="int" enum="PhysicsServer.BodyAxisLock"> + <return type="bool"> </return> <argument index="0" name="body" type="RID"> </argument> @@ -540,10 +540,11 @@ </return> <argument index="0" name="body" type="RID"> </argument> - <argument index="1" name="axis" type="int" enum="PhysicsServer.BodyAxisLock"> + <argument index="1" name="axis" type="int"> + </argument> + <argument index="2" name="lock" type="bool"> </argument> <description> - Locks velocity along one axis to 0 and only allows rotation along this axis, can also be set to disabled which disables this functionality. </description> </method> <method name="body_set_axis_velocity"> @@ -1519,17 +1520,5 @@ <constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="7" enum="SpaceParameter"> Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision. </constant> - <constant name="BODY_AXIS_LOCK_DISABLED" value="0" enum="BodyAxisLock"> - The [Body] can rotate and move freely. - </constant> - <constant name="BODY_AXIS_LOCK_X" value="1" enum="BodyAxisLock"> - The [Body] cannot move across x axis can only rotate across x axis. - </constant> - <constant name="BODY_AXIS_LOCK_Y" value="2" enum="BodyAxisLock"> - The [Body] cannot move across y axis can only rotate across y axis. - </constant> - <constant name="BODY_AXIS_LOCK_Z" value="3" enum="BodyAxisLock"> - The [Body] cannot move across z axis can only rotate across z axis. - </constant> </constants> </class> diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml index 1bd2e812e6..4fc9e5bd71 100644 --- a/doc/classes/Rect2.xml +++ b/doc/classes/Rect2.xml @@ -37,6 +37,12 @@ Constructs a [code]Rect2[/code] by x, y, width, and height. </description> </method> + <method name="abs"> + <return type="Rect2"> + </return> + <description> + </description> + </method> <method name="clip"> <return type="Rect2"> </return> diff --git a/doc/classes/RigidBody.xml b/doc/classes/RigidBody.xml index cfcd0258e7..77e27cefcc 100644 --- a/doc/classes/RigidBody.xml +++ b/doc/classes/RigidBody.xml @@ -59,8 +59,11 @@ <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity"> RigidBody's rotational velocity. </member> - <member name="axis_lock" type="int" setter="set_axis_lock" getter="get_axis_lock" enum="RigidBody.AxisLock"> - Locks the rotational forces to a particular axis, preventing rotations on other axes. + <member name="axis_lock_x" type="bool" setter="set_axis_lock_x" getter="get_axis_lock_x"> + </member> + <member name="axis_lock_y" type="bool" setter="set_axis_lock_y" getter="get_axis_lock_y"> + </member> + <member name="axis_lock_z" type="bool" setter="set_axis_lock_z" getter="get_axis_lock_z"> </member> <member name="bounce" type="float" setter="set_bounce" getter="get_bounce"> RigidBody's bounciness. @@ -168,13 +171,5 @@ <constant name="MODE_KINEMATIC" value="3" enum="Mode"> Kinematic body. The body behaves like a [KinematicBody], and can only move by user code. </constant> - <constant name="AXIS_LOCK_DISABLED" value="0" enum="AxisLock"> - </constant> - <constant name="AXIS_LOCK_X" value="1" enum="AxisLock"> - </constant> - <constant name="AXIS_LOCK_Y" value="2" enum="AxisLock"> - </constant> - <constant name="AXIS_LOCK_Z" value="3" enum="AxisLock"> - </constant> </constants> </class> diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index 22099a930c..0916d0b928 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -170,6 +170,8 @@ </return> <argument index="0" name="existing" type="ArrayMesh" default="null"> </argument> + <argument index="1" name="flags" type="int" default="97792"> + </argument> <description> Returns a constructed [ArrayMesh] from current information passed in. If an existing [ArrayMesh] is passed in as an argument, will add an extra surface to the existing [ArrayMesh]. </description> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index df48ba3e23..da30c4c7bd 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -305,6 +305,15 @@ Enable text wrapping when it goes beyond he edge of what is visible. </description> </method> + <method name="toggle_fold_line"> + <return type="void"> + </return> + <argument index="0" name="line" type="int"> + </argument> + <description> + Toggle the folding of the code block at the given line. + </description> + </method> <method name="undo"> <return type="void"> </return> @@ -428,6 +437,8 @@ </theme_item> <theme_item name="caret_color" type="Color"> </theme_item> + <theme_item name="code_folding_color" type="Color"> + </theme_item> <theme_item name="completion" type="StyleBox"> </theme_item> <theme_item name="completion_background_color" type="Color"> diff --git a/doc/classes/Texture.xml b/doc/classes/Texture.xml index 855a8f12de..bf27bc4768 100644 --- a/doc/classes/Texture.xml +++ b/doc/classes/Texture.xml @@ -117,22 +117,26 @@ </methods> <constants> <constant name="FLAG_MIPMAPS" value="1" enum="Flags"> - Generate mipmaps, to enable smooth zooming out of the texture. + Generate mipmaps, which are smaller versions of the same texture to use when zoomed out, keeping the aspect ratio. </constant> <constant name="FLAG_REPEAT" value="2" enum="Flags"> - Repeat (instead of clamp to edge). + Repeats texture (instead of clamp to edge). </constant> <constant name="FLAG_FILTER" value="4" enum="Flags"> - Turn on magnifying filter, to enable smooth zooming in of the texture. + Magnifying filter, to enable smooth zooming in of the texture. </constant> <constant name="FLAGS_DEFAULT" value="7" enum="Flags"> Default flags. Generate mipmaps, repeat, and filter are enabled. </constant> <constant name="FLAG_ANISOTROPIC_FILTER" value="8" enum="Flags"> + Anisotropic mipmap filtering. Generates smaller versions of the same texture with different aspect ratios. + More effective on planes often shown going to the horrizon as those textures (Walls or Ground for example) get squashed in the viewport to different aspect ratios and regular mipmaps keep the aspect ratio so they don't optimize storage that well in those cases. </constant> <constant name="FLAG_CONVERT_TO_LINEAR" value="16" enum="Flags"> + Converts texture to SRGB color space. </constant> <constant name="FLAG_MIRRORED_REPEAT" value="32" enum="Flags"> + Repeats texture with alternate sections mirrored. </constant> <constant name="FLAG_VIDEO_SURFACE" value="4096" enum="Flags"> Texture is a video surface. diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index 479c0606f2..1a9dc3a669 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -24,6 +24,7 @@ <argument index="3" name="bottom" type="RID"> </argument> <description> + Sets images to be rendered in the window margin. </description> </method> <method name="black_bars_set_margins"> @@ -38,12 +39,14 @@ <argument index="3" name="bottom" type="int"> </argument> <description> + Sets margin size, where black bars (or images, if [method black_bars_set_images] was used) are rendered. </description> </method> <method name="canvas_create"> <return type="RID"> </return> <description> + Creates a canvas and returns the assigned [RID]. </description> </method> <method name="canvas_item_add_circle"> @@ -58,6 +61,7 @@ <argument index="3" name="color" type="Color"> </argument> <description> + Adds a circle command to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_clip_ignore"> @@ -68,6 +72,7 @@ <argument index="1" name="ignore" type="bool"> </argument> <description> + If ignore is [code]true[/code], the VisualServer does not perform clipping. </description> </method> <method name="canvas_item_add_line"> @@ -86,6 +91,7 @@ <argument index="5" name="antialiased" type="bool" default="false"> </argument> <description> + Adds a line command to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_mesh"> @@ -98,6 +104,7 @@ <argument index="2" name="skeleton" type="RID"> </argument> <description> + Adds a [Mesh] to the [CanvasItem]'s draw commands. Only affects its aabb at the moment. </description> </method> <method name="canvas_item_add_multimesh"> @@ -110,6 +117,7 @@ <argument index="2" name="skeleton" type="RID"> </argument> <description> + Adds a [MultiMesh] to the [CanvasItem]'s draw commands. Only affects its aabb at the moment. </description> </method> <method name="canvas_item_add_nine_patch"> @@ -138,6 +146,8 @@ <argument index="10" name="normal_map" type="RID"> </argument> <description> + Adds a nine patch image to the [CanvasItem]'s draw commands. + See [NinePatchRect] for more explanation. </description> </method> <method name="canvas_item_add_particles"> @@ -156,6 +166,7 @@ <argument index="5" name="v_frames" type="int"> </argument> <description> + Adds a particles system to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_polygon"> @@ -176,6 +187,7 @@ <argument index="6" name="antialiased" type="bool" default="false"> </argument> <description> + Adds a polygon to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_polyline"> @@ -192,6 +204,7 @@ <argument index="4" name="antialiased" type="bool" default="false"> </argument> <description> + Adds a polyline, which is a line from mutliple points with a width, to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_primitive"> @@ -212,6 +225,7 @@ <argument index="6" name="normal_map" type="RID"> </argument> <description> + Adds a primitive to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_rect"> @@ -224,6 +238,7 @@ <argument index="2" name="color" type="Color"> </argument> <description> + Adds a rectangle to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_set_transform"> @@ -234,6 +249,8 @@ <argument index="1" name="transform" type="Transform2D"> </argument> <description> + Adds a [Transform2D] command to the [CanvasItem]'s draw commands. + This sets the extra_matrix uniform when executed. This affects the later command's of the canvas item. </description> </method> <method name="canvas_item_add_texture_rect"> @@ -254,6 +271,7 @@ <argument index="6" name="normal_map" type="RID"> </argument> <description> + Adds a textured rect to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_texture_rect_region"> @@ -276,6 +294,7 @@ <argument index="7" name="clip_uv" type="bool" default="true"> </argument> <description> + Adds a texture rect with region setting to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_add_triangle_array"> @@ -298,6 +317,7 @@ <argument index="7" name="normal_map" type="RID"> </argument> <description> + Adds a triangle array to the [CanvasItem]'s draw commands. </description> </method> <method name="canvas_item_clear"> @@ -306,12 +326,14 @@ <argument index="0" name="item" type="RID"> </argument> <description> + Clears the [CanvasItem] and removes all commands in it. </description> </method> <method name="canvas_item_create"> <return type="RID"> </return> <description> + Creates a new [CanvasItem] and returns its [RID]. </description> </method> <method name="canvas_item_set_clip"> @@ -322,6 +344,7 @@ <argument index="1" name="clip" type="bool"> </argument> <description> + Sets clipping for the [CanvasItem]. </description> </method> <method name="canvas_item_set_copy_to_backbuffer"> @@ -334,6 +357,7 @@ <argument index="2" name="rect" type="Rect2"> </argument> <description> + Sets the [CanvasItem] to copy a rect to the backbuffer. </description> </method> <method name="canvas_item_set_custom_rect"> @@ -346,6 +370,7 @@ <argument index="2" name="rect" type="Rect2" default="Rect2( 0, 0, 0, 0 )"> </argument> <description> + Defines a custom drawing rectangle for the [CanvasItem]. </description> </method> <method name="canvas_item_set_distance_field_mode"> @@ -366,6 +391,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Sets [CanvasItem] to be drawn behind its parent. </description> </method> <method name="canvas_item_set_draw_index"> @@ -376,6 +402,7 @@ <argument index="1" name="index" type="int"> </argument> <description> + Sets the index for the [CanvasItem]. </description> </method> <method name="canvas_item_set_light_mask"> @@ -386,6 +413,7 @@ <argument index="1" name="mask" type="int"> </argument> <description> + The light mask. See [LightOccluder2D] for more information on light masks. </description> </method> <method name="canvas_item_set_material"> @@ -396,6 +424,7 @@ <argument index="1" name="material" type="RID"> </argument> <description> + Sets a new material to the [CanvasItem]. </description> </method> <method name="canvas_item_set_modulate"> @@ -406,6 +435,7 @@ <argument index="1" name="color" type="Color"> </argument> <description> + Sets the color that modulates the [CanvasItem] and its children. </description> </method> <method name="canvas_item_set_parent"> @@ -416,6 +446,7 @@ <argument index="1" name="parent" type="RID"> </argument> <description> + Sets the parent for the [CanvasItem]. </description> </method> <method name="canvas_item_set_self_modulate"> @@ -426,6 +457,7 @@ <argument index="1" name="color" type="Color"> </argument> <description> + Sets the color that modulates the [CanvasItem] without children. </description> </method> <method name="canvas_item_set_sort_children_by_y"> @@ -436,6 +468,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Sets if [CanvasItem]'s children should be sorted by y-position. </description> </method> <method name="canvas_item_set_transform"> @@ -446,6 +479,7 @@ <argument index="1" name="transform" type="Transform2D"> </argument> <description> + Sets the [CanvasItem]'s [Transform2D]. </description> </method> <method name="canvas_item_set_use_parent_material"> @@ -456,6 +490,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Sets if the [CanvasItem] uses its parent's material. </description> </method> <method name="canvas_item_set_visible"> @@ -466,6 +501,7 @@ <argument index="1" name="visible" type="bool"> </argument> <description> + Sets if the canvas item (including its children) is visible. </description> </method> <method name="canvas_item_set_z"> @@ -476,6 +512,7 @@ <argument index="1" name="z" type="int"> </argument> <description> + Sets the [CanvasItem]'s z order position. </description> </method> <method name="canvas_item_set_z_as_relative_to_parent"> @@ -486,6 +523,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + If this is enabled, the z-position of the parent will be added to the childrens z-position. </description> </method> <method name="canvas_light_attach_to_canvas"> @@ -496,12 +534,14 @@ <argument index="1" name="canvas" type="RID"> </argument> <description> + Attaches the canvas light to the canvas. Removes it from its previous canvas. </description> </method> <method name="canvas_light_create"> <return type="RID"> </return> <description> + Creates a canvas light. </description> </method> <method name="canvas_light_occluder_attach_to_canvas"> @@ -512,12 +552,14 @@ <argument index="1" name="canvas" type="RID"> </argument> <description> + Attaches a light occluder to the canvas. Removes it from its previous canvas. </description> </method> <method name="canvas_light_occluder_create"> <return type="RID"> </return> <description> + Creates a light occluder. </description> </method> <method name="canvas_light_occluder_set_enabled"> @@ -528,6 +570,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Enables or disables light occluder. </description> </method> <method name="canvas_light_occluder_set_light_mask"> @@ -538,6 +581,7 @@ <argument index="1" name="mask" type="int"> </argument> <description> + The light mask. See [LightOccluder2D] for more information on light masks </description> </method> <method name="canvas_light_occluder_set_polygon"> @@ -548,6 +592,7 @@ <argument index="1" name="polygon" type="RID"> </argument> <description> + Sets a light occluder's polygon. </description> </method> <method name="canvas_light_occluder_set_transform"> @@ -558,6 +603,7 @@ <argument index="1" name="transform" type="Transform2D"> </argument> <description> + Sets a light occluder's [Transform2D]. </description> </method> <method name="canvas_light_set_color"> @@ -568,6 +614,7 @@ <argument index="1" name="color" type="Color"> </argument> <description> + Sets the color for a light. </description> </method> <method name="canvas_light_set_enabled"> @@ -578,6 +625,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Enables or disables a canvas light. </description> </method> <method name="canvas_light_set_energy"> @@ -588,6 +636,7 @@ <argument index="1" name="energy" type="float"> </argument> <description> + Sets a canvas light's energy. </description> </method> <method name="canvas_light_set_height"> @@ -598,6 +647,7 @@ <argument index="1" name="height" type="float"> </argument> <description> + Sets a canvas light's height. </description> </method> <method name="canvas_light_set_item_cull_mask"> @@ -608,6 +658,7 @@ <argument index="1" name="mask" type="int"> </argument> <description> + The light mask. See [LightOccluder2D] for more information on light masks </description> </method> <method name="canvas_light_set_item_shadow_cull_mask"> @@ -618,6 +669,7 @@ <argument index="1" name="mask" type="int"> </argument> <description> + The shadow mask. binary about wich layers this canvas light affects wich canvas item's shadows. See [LightOccluder2D] for more information on light masks. </description> </method> <method name="canvas_light_set_layer_range"> @@ -630,6 +682,7 @@ <argument index="2" name="max_layer" type="int"> </argument> <description> + The layer range that gets rendered with this light. </description> </method> <method name="canvas_light_set_mode"> @@ -640,6 +693,7 @@ <argument index="1" name="mode" type="int" enum="VisualServer.CanvasLightMode"> </argument> <description> + The mode of the light, see CANVAS_LIGHT_MODE_* constants. </description> </method> <method name="canvas_light_set_scale"> @@ -660,6 +714,7 @@ <argument index="1" name="size" type="int"> </argument> <description> + Sets the width of the shadow buffer, size gets scaled to the next power of two for this. </description> </method> <method name="canvas_light_set_shadow_color"> @@ -670,6 +725,7 @@ <argument index="1" name="color" type="Color"> </argument> <description> + Sets the color of the canvas light's shadow. </description> </method> <method name="canvas_light_set_shadow_enabled"> @@ -680,6 +736,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Enables or disables the canvas light's shadow. </description> </method> <method name="canvas_light_set_shadow_filter"> @@ -690,6 +747,7 @@ <argument index="1" name="filter" type="int" enum="VisualServer.CanvasLightShadowFilter"> </argument> <description> + Sets the canvas light's shadow's filter, see CANVAS_LIGHT_SHADOW_FILTER_* constants. </description> </method> <method name="canvas_light_set_shadow_gradient_length"> @@ -700,6 +758,7 @@ <argument index="1" name="length" type="float"> </argument> <description> + Sets the length of the shadow's gradient. </description> </method> <method name="canvas_light_set_shadow_smooth"> @@ -710,6 +769,7 @@ <argument index="1" name="smooth" type="float"> </argument> <description> + Smoothens the shadow. The lower, the more smooth. </description> </method> <method name="canvas_light_set_texture"> @@ -740,6 +800,7 @@ <argument index="1" name="transform" type="Transform2D"> </argument> <description> + Sets the canvas light's [Transform2D]. </description> </method> <method name="canvas_light_set_z_range"> @@ -758,6 +819,7 @@ <return type="RID"> </return> <description> + Creates a new light occluder polygon. </description> </method> <method name="canvas_occluder_polygon_set_cull_mode"> @@ -768,6 +830,7 @@ <argument index="1" name="mode" type="int" enum="VisualServer.CanvasOccluderPolygonCullMode"> </argument> <description> + Sets an occluder polygons cull mode. See CANVAS_OCCLUDER_POLYGON_CULL_MODE_* constants. </description> </method> <method name="canvas_occluder_polygon_set_shape"> @@ -780,6 +843,7 @@ <argument index="2" name="closed" type="bool"> </argument> <description> + Sets the shape of the occluder polygon. </description> </method> <method name="canvas_occluder_polygon_set_shape_as_lines"> @@ -790,6 +854,7 @@ <argument index="1" name="shape" type="PoolVector2Array"> </argument> <description> + Sets the shape of the occluder polygon as lines. </description> </method> <method name="canvas_set_item_mirroring"> @@ -802,6 +867,7 @@ <argument index="2" name="mirroring" type="Vector2"> </argument> <description> + A copy of the canvas item will be drawn with a local offset of the mirroring [Vector2]. </description> </method> <method name="canvas_set_modulate"> @@ -812,6 +878,7 @@ <argument index="1" name="color" type="Color"> </argument> <description> + Modulates all colors in the given canvas. </description> </method> <method name="draw"> @@ -820,12 +887,14 @@ <argument index="0" name="swap_buffers" type="bool" default="true"> </argument> <description> + Draws a frame. </description> </method> <method name="finish"> <return type="void"> </return> <description> + Removes buffers and clears testcubes. </description> </method> <method name="force_draw"> @@ -834,12 +903,14 @@ <argument index="0" name="swap_buffers" type="bool" default="true"> </argument> <description> + Draws a frame. Same as [method draw]. </description> </method> <method name="force_sync"> <return type="void"> </return> <description> + Syncronizes threads. </description> </method> <method name="free"> @@ -848,6 +919,7 @@ <argument index="0" name="rid" type="RID"> </argument> <description> + Tries to free an object in the VisualServer. </description> </method> <method name="get_render_info"> @@ -856,30 +928,35 @@ <argument index="0" name="info" type="int" enum="VisualServer.RenderInfo"> </argument> <description> + Returns a certain information, see RENDER_INFO_* for options. </description> </method> <method name="get_test_cube"> <return type="RID"> </return> <description> + Returns the id of the test cube. Creates one if none exists. </description> </method> <method name="get_test_texture"> <return type="RID"> </return> <description> + Returns the id of the test texture. Creates one if none exists. </description> </method> <method name="get_white_texture"> <return type="RID"> </return> <description> + Returns the id of a white texture. Creates one if none exists. </description> </method> <method name="has_changed" qualifiers="const"> <return type="bool"> </return> <description> + Returns [code]true[/code] if changes have been made to the VisualServer's data. [method draw] is usually called if this happens. </description> </method> <method name="has_feature" qualifiers="const"> @@ -896,12 +973,14 @@ <argument index="0" name="feature" type="String"> </argument> <description> + Returns true, if the OS supports a certain feature. Features might be s3tc, etc, etc2 and pvrtc, </description> </method> <method name="init"> <return type="void"> </return> <description> + Initializes the visual server. </description> </method> <method name="make_sphere_mesh"> @@ -914,12 +993,14 @@ <argument index="2" name="radius" type="float"> </argument> <description> + Returns a mesh of a sphere with the given amount of horizontal and vertical subdivisions. </description> </method> <method name="material_create"> <return type="RID"> </return> <description> + Returns an empty material. </description> </method> <method name="material_get_param" qualifiers="const"> @@ -930,6 +1011,7 @@ <argument index="1" name="parameter" type="String"> </argument> <description> + Returns the value of a certain material's parameter. </description> </method> <method name="material_get_shader" qualifiers="const"> @@ -938,6 +1020,7 @@ <argument index="0" name="shader_material" type="RID"> </argument> <description> + Returns the shader of a certain material's shader. Returns an empty RID if the material doesn't have a shader. </description> </method> <method name="material_set_line_width"> @@ -948,6 +1031,7 @@ <argument index="1" name="width" type="float"> </argument> <description> + Sets a materials line width. </description> </method> <method name="material_set_next_pass"> @@ -958,6 +1042,7 @@ <argument index="1" name="next_material" type="RID"> </argument> <description> + Sets an objects next material. </description> </method> <method name="material_set_param"> @@ -970,6 +1055,7 @@ <argument index="2" name="value" type="Variant"> </argument> <description> + Sets a materials parameter. </description> </method> <method name="material_set_render_priority"> @@ -980,6 +1066,7 @@ <argument index="1" name="priority" type="int"> </argument> <description> + Sets a material's render priority. </description> </method> <method name="material_set_shader"> @@ -990,6 +1077,7 @@ <argument index="1" name="shader" type="RID"> </argument> <description> + Sets a shader material's shader. </description> </method> <method name="mesh_add_surface_from_arrays"> @@ -1006,6 +1094,7 @@ <argument index="4" name="compress_format" type="int" default="97792"> </argument> <description> + Adds a surface generated from the Arrays to a mesh. See PRIMITIVE_TYPE_* constants for types. </description> </method> <method name="mesh_clear"> @@ -1014,12 +1103,14 @@ <argument index="0" name="mesh" type="RID"> </argument> <description> + Removes all surfaces from a mesh. </description> </method> <method name="mesh_create"> <return type="RID"> </return> <description> + Creates a new mesh. </description> </method> <method name="mesh_get_blend_shape_count" qualifiers="const"> @@ -1028,6 +1119,7 @@ <argument index="0" name="mesh" type="RID"> </argument> <description> + Returns a mesh's blend shape count. </description> </method> <method name="mesh_get_blend_shape_mode" qualifiers="const"> @@ -1036,6 +1128,7 @@ <argument index="0" name="mesh" type="RID"> </argument> <description> + Returns a mesh's blend shape mode. </description> </method> <method name="mesh_get_custom_aabb" qualifiers="const"> @@ -1044,6 +1137,7 @@ <argument index="0" name="mesh" type="RID"> </argument> <description> + Returns a mesh's custom aabb. </description> </method> <method name="mesh_get_surface_count" qualifiers="const"> @@ -1052,6 +1146,7 @@ <argument index="0" name="mesh" type="RID"> </argument> <description> + Returns a mesh's number of surfaces. </description> </method> <method name="mesh_remove_surface"> @@ -1062,6 +1157,7 @@ <argument index="1" name="index" type="int"> </argument> <description> + Removes a mesh's surface. </description> </method> <method name="mesh_set_blend_shape_count"> @@ -1072,6 +1168,7 @@ <argument index="1" name="amount" type="int"> </argument> <description> + Sets a mesh's blend shape count. </description> </method> <method name="mesh_set_blend_shape_mode"> @@ -1082,6 +1179,7 @@ <argument index="1" name="mode" type="int" enum="VisualServer.BlendShapeMode"> </argument> <description> + Sets a mesh's blend shape mode. </description> </method> <method name="mesh_set_custom_aabb"> @@ -1092,6 +1190,7 @@ <argument index="1" name="aabb" type="AABB"> </argument> <description> + Sets a mesh's custom aabb. </description> </method> <method name="mesh_surface_get_aabb" qualifiers="const"> @@ -1102,6 +1201,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns a mesh's surface's aabb. </description> </method> <method name="mesh_surface_get_array" qualifiers="const"> @@ -1112,6 +1212,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns a mesh's surface's vertex buffer. </description> </method> <method name="mesh_surface_get_array_index_len" qualifiers="const"> @@ -1122,6 +1223,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns a mesh's surface's amount of indices. </description> </method> <method name="mesh_surface_get_array_len" qualifiers="const"> @@ -1132,6 +1234,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns a mesh's surface's amount of vertices. </description> </method> <method name="mesh_surface_get_arrays" qualifiers="const"> @@ -1142,6 +1245,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns a mesh's surface's buffer arrays. </description> </method> <method name="mesh_surface_get_blend_shape_arrays" qualifiers="const"> @@ -1152,6 +1256,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns a mesh's surface's arrays for blend shapes </description> </method> <method name="mesh_surface_get_format" qualifiers="const"> @@ -1162,6 +1267,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns the format of a mesh's surface. </description> </method> <method name="mesh_surface_get_index_array" qualifiers="const"> @@ -1172,6 +1278,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns a mesh's surface's index buffer. </description> </method> <method name="mesh_surface_get_material" qualifiers="const"> @@ -1182,6 +1289,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns a mesh's surface's material. </description> </method> <method name="mesh_surface_get_primitive_type" qualifiers="const"> @@ -1192,6 +1300,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns the primitive type of a mesh's surface. </description> </method> <method name="mesh_surface_get_skeleton_aabb" qualifiers="const"> @@ -1202,6 +1311,7 @@ <argument index="1" name="surface" type="int"> </argument> <description> + Returns the aabb of a mesh's surface's skeleton. </description> </method> <method name="mesh_surface_set_material"> @@ -1214,6 +1324,7 @@ <argument index="2" name="material" type="RID"> </argument> <description> + Sets a mesh's surface's material. </description> </method> <method name="request_frame_drawn_callback"> @@ -1240,6 +1351,7 @@ <argument index="2" name="scale" type="bool"> </argument> <description> + Sets a boot image. The color defines the background color and if scale is [code]true[/code], the image will be scaled to fit the screen size. </description> </method> <method name="set_debug_generate_wireframes"> @@ -1262,6 +1374,7 @@ <return type="RID"> </return> <description> + Creates an empty shader. </description> </method> <method name="shader_get_code" qualifiers="const"> @@ -1270,6 +1383,7 @@ <argument index="0" name="shader" type="RID"> </argument> <description> + Returns a shader's code. </description> </method> <method name="shader_get_default_texture_param" qualifiers="const"> @@ -1280,6 +1394,7 @@ <argument index="1" name="name" type="String"> </argument> <description> + Returns a default texture from a shader searched by name. </description> </method> <method name="shader_get_param_list" qualifiers="const"> @@ -1288,6 +1403,7 @@ <argument index="0" name="shader" type="RID"> </argument> <description> + Returns the parameters of a shader. </description> </method> <method name="shader_set_code"> @@ -1298,6 +1414,7 @@ <argument index="1" name="code" type="String"> </argument> <description> + Sets a shader's code. </description> </method> <method name="shader_set_default_texture_param"> @@ -1310,12 +1427,14 @@ <argument index="2" name="texture" type="RID"> </argument> <description> + Sets a shader's default texture. Overwrites the texture given by name. </description> </method> <method name="sky_create"> <return type="RID"> </return> <description> + Creates an empty sky. </description> </method> <method name="sky_set_texture"> @@ -1328,6 +1447,7 @@ <argument index="2" name="radiance_size" type="int"> </argument> <description> + Sets a sky's texture. </description> </method> <method name="sync"> @@ -1350,12 +1470,14 @@ <argument index="4" name="flags" type="int" default="7"> </argument> <description> + Allocates space for a texture's image or video. </description> </method> <method name="texture_create"> <return type="RID"> </return> <description> + Creates an empty texture. </description> </method> <method name="texture_create_from_image"> @@ -1366,12 +1488,14 @@ <argument index="1" name="flags" type="int" default="7"> </argument> <description> + Creates a texture, allocates the space for an image, and fills in the image. </description> </method> <method name="texture_debug_usage"> <return type="Array"> </return> <description> + Returns a list of all the textures and their information. </description> </method> <method name="texture_get_data" qualifiers="const"> @@ -1382,6 +1506,7 @@ <argument index="1" name="cube_side" type="int" enum="VisualServer.CubeMapSide" default="0"> </argument> <description> + Returns a copy of a texture's image unless it's a CubeMap, in wich case it returns the [RID] of the image at one of the cubes sides. </description> </method> <method name="texture_get_flags" qualifiers="const"> @@ -1390,6 +1515,7 @@ <argument index="0" name="texture" type="RID"> </argument> <description> + Returns the flags of a texture. </description> </method> <method name="texture_get_format" qualifiers="const"> @@ -1398,6 +1524,7 @@ <argument index="0" name="texture" type="RID"> </argument> <description> + Returns the format of the texture's image. </description> </method> <method name="texture_get_height" qualifiers="const"> @@ -1406,6 +1533,7 @@ <argument index="0" name="texture" type="RID"> </argument> <description> + Returns the texture's height. </description> </method> <method name="texture_get_path" qualifiers="const"> @@ -1414,6 +1542,7 @@ <argument index="0" name="texture" type="RID"> </argument> <description> + Returns the texture's path. </description> </method> <method name="texture_get_texid" qualifiers="const"> @@ -1422,6 +1551,7 @@ <argument index="0" name="texture" type="RID"> </argument> <description> + Returns the opengl id of the texture's image. </description> </method> <method name="texture_get_width" qualifiers="const"> @@ -1430,6 +1560,7 @@ <argument index="0" name="texture" type="RID"> </argument> <description> + Returns the texture's width. </description> </method> <method name="texture_set_data"> @@ -1442,6 +1573,7 @@ <argument index="2" name="cube_side" type="int" enum="VisualServer.CubeMapSide" default="0"> </argument> <description> + Sets the texture's image data. If it's a CubeMap, it sets the image data at a cube side. </description> </method> <method name="texture_set_flags"> @@ -1452,6 +1584,7 @@ <argument index="1" name="flags" type="int"> </argument> <description> + Sets the texture's flags. See [enum TextureFlags] for options </description> </method> <method name="texture_set_path"> @@ -1462,6 +1595,7 @@ <argument index="1" name="path" type="String"> </argument> <description> + Sets the texture's path. </description> </method> <method name="texture_set_shrink_all_x2_on_set_data"> @@ -1470,6 +1604,7 @@ <argument index="0" name="shrink" type="bool"> </argument> <description> + If [code]true[/code], sets internal processes to shrink all image data to half the size. </description> </method> <method name="texture_set_size_override"> @@ -1482,6 +1617,7 @@ <argument index="2" name="height" type="int"> </argument> <description> + Overwrites the texture's width and height. </description> </method> <method name="textures_keep_original"> @@ -1490,6 +1626,7 @@ <argument index="0" name="enable" type="bool"> </argument> <description> + If [code]true[/code], the image will be stored in the texture's images array if overwritten. </description> </method> <method name="viewport_attach_camera"> @@ -1500,6 +1637,7 @@ <argument index="1" name="camera" type="RID"> </argument> <description> + Sets a viewport's camera. </description> </method> <method name="viewport_attach_canvas"> @@ -1510,6 +1648,7 @@ <argument index="1" name="canvas" type="RID"> </argument> <description> + Sets a viewport's canvas. </description> </method> <method name="viewport_attach_to_screen"> @@ -1522,12 +1661,14 @@ <argument index="2" name="screen" type="int" default="0"> </argument> <description> + Attaches a viewport to a screen. </description> </method> <method name="viewport_create"> <return type="RID"> </return> <description> + Creates an empty viewport. </description> </method> <method name="viewport_detach"> @@ -1536,6 +1677,7 @@ <argument index="0" name="viewport" type="RID"> </argument> <description> + Detaches the viewport from the screen. </description> </method> <method name="viewport_get_render_info"> @@ -1546,6 +1688,7 @@ <argument index="1" name="info" type="int" enum="VisualServer.ViewportRenderInfo"> </argument> <description> + Returns a viewport's render info. for options see VIEWPORT_RENDER_INFO* constants. </description> </method> <method name="viewport_get_texture" qualifiers="const"> @@ -1554,6 +1697,7 @@ <argument index="0" name="viewport" type="RID"> </argument> <description> + Returns the viewport's last rendered frame. </description> </method> <method name="viewport_remove_canvas"> @@ -1564,6 +1708,7 @@ <argument index="1" name="canvas" type="RID"> </argument> <description> + Detaches a viewport from a canvas and vice versa. </description> </method> <method name="viewport_set_active"> @@ -1574,6 +1719,7 @@ <argument index="1" name="active" type="bool"> </argument> <description> + If [code]true[/code], sets the viewport active, else sets it inactive. </description> </method> <method name="viewport_set_canvas_layer"> @@ -1586,6 +1732,7 @@ <argument index="2" name="layer" type="int"> </argument> <description> + Sets the renderlayer for a viewport's canvas. </description> </method> <method name="viewport_set_canvas_transform"> @@ -1598,6 +1745,7 @@ <argument index="2" name="offset" type="Transform2D"> </argument> <description> + Sets the transformation of a viewport's canvas. </description> </method> <method name="viewport_set_clear_mode"> @@ -1608,6 +1756,7 @@ <argument index="1" name="clear_mode" type="int" enum="VisualServer.ViewportClearMode"> </argument> <description> + Sets the clear mode of a viewport. See VIEWPORT_CLEAR_MODE_* constants for options. </description> </method> <method name="viewport_set_debug_draw"> @@ -1618,6 +1767,7 @@ <argument index="1" name="draw" type="int" enum="VisualServer.ViewportDebugDraw"> </argument> <description> + Sets the debug draw mode of a viewport. See VIEWPORT_DEBUG_DRAW_* constants for options. </description> </method> <method name="viewport_set_disable_3d"> @@ -1628,6 +1778,7 @@ <argument index="1" name="disabled" type="bool"> </argument> <description> + If [code]true[/code] a viewport's 3D rendering should be disabled. </description> </method> <method name="viewport_set_disable_environment"> @@ -1638,6 +1789,7 @@ <argument index="1" name="disabled" type="bool"> </argument> <description> + If [code]true[/code] rendering of a viewport's environment should be disabled. </description> </method> <method name="viewport_set_global_canvas_transform"> @@ -1648,6 +1800,7 @@ <argument index="1" name="transform" type="Transform2D"> </argument> <description> + Sets the viewport's global transformation matrix. </description> </method> <method name="viewport_set_hdr"> @@ -1658,6 +1811,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + If [code]true[/code] the viewport should render to hdr. </description> </method> <method name="viewport_set_hide_canvas"> @@ -1668,6 +1822,7 @@ <argument index="1" name="hidden" type="bool"> </argument> <description> + If [code]true[/code] the viewport's canvas should not be rendered. </description> </method> <method name="viewport_set_hide_scenario"> @@ -1688,6 +1843,7 @@ <argument index="1" name="msaa" type="int" enum="VisualServer.ViewportMSAA"> </argument> <description> + Sets the anti-aliasing mode. see [enum ViewportMSAA] for options. </description> </method> <method name="viewport_set_parent_viewport"> @@ -1698,6 +1854,7 @@ <argument index="1" name="parent_viewport" type="RID"> </argument> <description> + Sets the viewport's parent to another viewport. </description> </method> <method name="viewport_set_scenario"> @@ -1708,6 +1865,8 @@ <argument index="1" name="scenario" type="RID"> </argument> <description> + Sets a viewport's scenario. + The scenario contains information about the [enum ScenarioDebugMode], environment information, reflection atlas etc. </description> </method> <method name="viewport_set_shadow_atlas_quadrant_subdivision"> @@ -1720,6 +1879,7 @@ <argument index="2" name="subdivision" type="int"> </argument> <description> + Sets the shadow atlas quadrant's subdivision. </description> </method> <method name="viewport_set_shadow_atlas_size"> @@ -1730,6 +1890,7 @@ <argument index="1" name="size" type="int"> </argument> <description> + Sets the size of the shadow atlas's images. </description> </method> <method name="viewport_set_size"> @@ -1742,6 +1903,7 @@ <argument index="2" name="height" type="int"> </argument> <description> + Sets the viewport's width and height. </description> </method> <method name="viewport_set_transparent_background"> @@ -1752,6 +1914,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + If [code]true[/code] the viewport should render its background as transparent. </description> </method> <method name="viewport_set_update_mode"> @@ -1762,6 +1925,7 @@ <argument index="1" name="update_mode" type="int" enum="VisualServer.ViewportUpdateMode"> </argument> <description> + Sets when the viewport should be updated. See VIEWPORT_UPDATE_MODE_* constants for options. </description> </method> <method name="viewport_set_usage"> @@ -1772,6 +1936,7 @@ <argument index="1" name="usage" type="int" enum="VisualServer.ViewportUsage"> </argument> <description> + Sets what should be rendered in the viewport. See VIEWPORT_USAGE_* constants for options. </description> </method> <method name="viewport_set_use_arvr"> @@ -1782,6 +1947,7 @@ <argument index="1" name="use_arvr" type="bool"> </argument> <description> + If [code]true[/code] the viewport should use augmented or virtual reality technologies. See [ARVRInterface]. </description> </method> <method name="viewport_set_vflip"> @@ -1792,6 +1958,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + If [code]true[/code] the viewport's rendering should be flipped vertically. </description> </method> </methods> @@ -1803,160 +1970,232 @@ </signals> <constants> <constant name="NO_INDEX_ARRAY" value="-1"> + Marks an error that shows that the index array is empty. </constant> <constant name="ARRAY_WEIGHTS_SIZE" value="4"> </constant> <constant name="CANVAS_ITEM_Z_MIN" value="-4096"> + The minimum Z-layer for canvas items. </constant> <constant name="CANVAS_ITEM_Z_MAX" value="4096"> + The maximum Z-layer for canvas items. </constant> <constant name="MAX_GLOW_LEVELS" value="7"> </constant> <constant name="MAX_CURSORS" value="8"> </constant> <constant name="MATERIAL_RENDER_PRIORITY_MIN" value="-128"> + The minimum renderpriority of all materials. </constant> <constant name="MATERIAL_RENDER_PRIORITY_MAX" value="127"> + The maximum renderpriority of all materials. </constant> <constant name="CUBEMAP_LEFT" value="0" enum="CubeMapSide"> + Marks the left side of a cubemap. </constant> <constant name="CUBEMAP_RIGHT" value="1" enum="CubeMapSide"> + Marks the right side of a cubemap. </constant> <constant name="CUBEMAP_BOTTOM" value="2" enum="CubeMapSide"> + Marks the bottom side of a cubemap. </constant> <constant name="CUBEMAP_TOP" value="3" enum="CubeMapSide"> + Marks the top side of a cubemap. </constant> <constant name="CUBEMAP_FRONT" value="4" enum="CubeMapSide"> + Marks the front side of a cubemap. </constant> <constant name="CUBEMAP_BACK" value="5" enum="CubeMapSide"> + Marks the back side of a cubemap. </constant> <constant name="TEXTURE_FLAG_MIPMAPS" value="1" enum="TextureFlags"> + Generate mipmaps, which are smaller versions of the same texture to use when zoomed out, keeping the aspect ratio. </constant> <constant name="TEXTURE_FLAG_REPEAT" value="2" enum="TextureFlags"> + Repeat (instead of clamp to edge). </constant> <constant name="TEXTURE_FLAG_FILTER" value="4" enum="TextureFlags"> + Turn on magnifying filter, to enable smooth zooming in of the texture. </constant> <constant name="TEXTURE_FLAG_ANISOTROPIC_FILTER" value="8" enum="TextureFlags"> + Anisotropic mipmap filtering. Generates smaller versions of the same texture with different aspect ratios. + More effective on planes often shown going to the horrizon as those textures (Walls or Ground for example) get squashed in the viewport to different aspect ratios and regular mipmaps keep the aspect ratio so they don't optimize storage that well in those cases. </constant> <constant name="TEXTURE_FLAG_CONVERT_TO_LINEAR" value="16" enum="TextureFlags"> + Converts texture to SRGB color space. </constant> <constant name="TEXTURE_FLAG_MIRRORED_REPEAT" value="32" enum="TextureFlags"> + Repeat texture with alternate sections mirrored. </constant> <constant name="TEXTURE_FLAG_CUBEMAP" value="2048" enum="TextureFlags"> + Texture is a cubemap. </constant> <constant name="TEXTURE_FLAG_USED_FOR_STREAMING" value="4096" enum="TextureFlags"> + Texture is a video surface. </constant> <constant name="TEXTURE_FLAGS_DEFAULT" value="7" enum="TextureFlags"> + Default flags. Generate mipmaps, repeat, and filter are enabled. </constant> <constant name="SHADER_SPATIAL" value="0" enum="ShaderMode"> + Shader is a 3D shader. </constant> <constant name="SHADER_CANVAS_ITEM" value="1" enum="ShaderMode"> + Shader is a 2D shader. </constant> <constant name="SHADER_PARTICLES" value="2" enum="ShaderMode"> + Shader is a particle shader. </constant> <constant name="SHADER_MAX" value="3" enum="ShaderMode"> + Marks maximum of the shader types array. used internally. </constant> <constant name="ARRAY_VERTEX" value="0" enum="ArrayType"> + Array is a vertex array. </constant> <constant name="ARRAY_NORMAL" value="1" enum="ArrayType"> + Array is a normal array. </constant> <constant name="ARRAY_TANGENT" value="2" enum="ArrayType"> + Array is a tangent array. </constant> <constant name="ARRAY_COLOR" value="3" enum="ArrayType"> + Array is a color array. </constant> <constant name="ARRAY_TEX_UV" value="4" enum="ArrayType"> + Array is a uv coordinates array. </constant> <constant name="ARRAY_TEX_UV2" value="5" enum="ArrayType"> + Array is a uv coordinates array for the second uv coordinates. </constant> <constant name="ARRAY_BONES" value="6" enum="ArrayType"> + Array contains bone information. </constant> <constant name="ARRAY_WEIGHTS" value="7" enum="ArrayType"> + Array is weight information. </constant> <constant name="ARRAY_INDEX" value="8" enum="ArrayType"> + Array is index array. </constant> <constant name="ARRAY_MAX" value="9" enum="ArrayType"> + Marks the maximum of the array types. Used internally. </constant> <constant name="ARRAY_FORMAT_VERTEX" value="1" enum="ArrayFormat"> + Flag used to mark a vertex array. </constant> <constant name="ARRAY_FORMAT_NORMAL" value="2" enum="ArrayFormat"> + Flag used to mark a normal array. </constant> <constant name="ARRAY_FORMAT_TANGENT" value="4" enum="ArrayFormat"> + Flag used to mark a tangent array. </constant> <constant name="ARRAY_FORMAT_COLOR" value="8" enum="ArrayFormat"> + Flag used to mark a color array. </constant> <constant name="ARRAY_FORMAT_TEX_UV" value="16" enum="ArrayFormat"> + Flag used to mark a uv coordinates array. </constant> <constant name="ARRAY_FORMAT_TEX_UV2" value="32" enum="ArrayFormat"> + Flag used to mark a uv coordinates array for the second uv coordinates. </constant> <constant name="ARRAY_FORMAT_BONES" value="64" enum="ArrayFormat"> + Flag used to mark a bone information array. </constant> <constant name="ARRAY_FORMAT_WEIGHTS" value="128" enum="ArrayFormat"> + Flag used to mark a weights array. </constant> <constant name="ARRAY_FORMAT_INDEX" value="256" enum="ArrayFormat"> + Flag used to mark a index array. </constant> <constant name="ARRAY_COMPRESS_VERTEX" value="512" enum="ArrayFormat"> + Flag used to mark a compressed (half float) vertex array. </constant> <constant name="ARRAY_COMPRESS_NORMAL" value="1024" enum="ArrayFormat"> + Flag used to mark a compressed (half float) normal array. </constant> <constant name="ARRAY_COMPRESS_TANGENT" value="2048" enum="ArrayFormat"> + Flag used to mark a compressed (half float) tangent array. </constant> <constant name="ARRAY_COMPRESS_COLOR" value="4096" enum="ArrayFormat"> + Flag used to mark a compressed (half float) color array. </constant> <constant name="ARRAY_COMPRESS_TEX_UV" value="8192" enum="ArrayFormat"> + Flag used to mark a compressed (half float) uv coordinates array. </constant> <constant name="ARRAY_COMPRESS_TEX_UV2" value="16384" enum="ArrayFormat"> + Flag used to mark a compressed (half float) uv coordinates array for the second uv coordinates. </constant> <constant name="ARRAY_COMPRESS_BONES" value="32768" enum="ArrayFormat"> </constant> <constant name="ARRAY_COMPRESS_WEIGHTS" value="65536" enum="ArrayFormat"> + Flag used to mark a compressed (half float) weight array. </constant> <constant name="ARRAY_COMPRESS_INDEX" value="131072" enum="ArrayFormat"> </constant> <constant name="ARRAY_FLAG_USE_2D_VERTICES" value="262144" enum="ArrayFormat"> + Flag used to mark that the array contains 2D vertices. </constant> <constant name="ARRAY_FLAG_USE_16_BIT_BONES" value="524288" enum="ArrayFormat"> + Flag used to mark that the array uses 16 bit bones instead of 8 bit. </constant> <constant name="ARRAY_COMPRESS_DEFAULT" value="97792" enum="ArrayFormat"> + Used to set flags ARRAY_COMPRESS_VERTEX, ARRAY_COMPRESS_NORMAL, ARRAY_COMPRESS_TANGENT, ARRAY_COMPRESS_COLOR, ARRAY_COMPRESS_TEX_UV, ARRAY_COMPRESS_TEX_UV2 and ARRAY_COMPRESS_WEIGHTS quickly. </constant> <constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType"> + Primitive to draw consists of points. </constant> <constant name="PRIMITIVE_LINES" value="1" enum="PrimitiveType"> + Primitive to draw consists of lines. </constant> <constant name="PRIMITIVE_LINE_STRIP" value="2" enum="PrimitiveType"> + Primitive to draw consists of a line strip from start to end. </constant> <constant name="PRIMITIVE_LINE_LOOP" value="3" enum="PrimitiveType"> + Primitive to draw consists of a line loop (a line strip with a line between the last and the first vertex). </constant> <constant name="PRIMITIVE_TRIANGLES" value="4" enum="PrimitiveType"> + Primitive to draw consists of triangles. </constant> <constant name="PRIMITIVE_TRIANGLE_STRIP" value="5" enum="PrimitiveType"> + Primitive to draw consists of a triangle strip (the last 3 verticies are always combined to make a triangle). </constant> <constant name="PRIMITIVE_TRIANGLE_FAN" value="6" enum="PrimitiveType"> + Primitive to draw consists of a triangle strip (the last 2 verticies are always combined with the first to make a triangle). </constant> <constant name="PRIMITIVE_MAX" value="7" enum="PrimitiveType"> + Marks the primitive types endpoint. used internally. </constant> <constant name="BLEND_SHAPE_MODE_NORMALIZED" value="0" enum="BlendShapeMode"> </constant> <constant name="BLEND_SHAPE_MODE_RELATIVE" value="1" enum="BlendShapeMode"> </constant> <constant name="LIGHT_DIRECTIONAL" value="0" enum="LightType"> + Is a directional (sun) light. </constant> <constant name="LIGHT_OMNI" value="1" enum="LightType"> + is an omni light. </constant> <constant name="LIGHT_SPOT" value="2" enum="LightType"> + is an spot light. </constant> <constant name="LIGHT_PARAM_ENERGY" value="0" enum="LightParam"> + The light's energy. </constant> <constant name="LIGHT_PARAM_SPECULAR" value="2" enum="LightParam"> + The light's influence on specularity. </constant> <constant name="LIGHT_PARAM_RANGE" value="3" enum="LightParam"> + The light's range. </constant> <constant name="LIGHT_PARAM_ATTENUATION" value="4" enum="LightParam"> + The light's attenuation. </constant> <constant name="LIGHT_PARAM_SPOT_ANGLE" value="5" enum="LightParam"> + The spotlight's angle. </constant> <constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="6" enum="LightParam"> + The spotlight's attenuation. </constant> <constant name="LIGHT_PARAM_CONTACT_SHADOW_SIZE" value="7" enum="LightParam"> + Scales the shadow color. </constant> <constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="8" enum="LightParam"> </constant> @@ -1973,6 +2212,7 @@ <constant name="LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE" value="14" enum="LightParam"> </constant> <constant name="LIGHT_PARAM_MAX" value="15" enum="LightParam"> + The light parameters endpoint. Used internally. </constant> <constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode"> </constant> @@ -1983,28 +2223,40 @@ <constant name="VIEWPORT_UPDATE_ALWAYS" value="3" enum="ViewportUpdateMode"> </constant> <constant name="VIEWPORT_CLEAR_ALWAYS" value="0" enum="ViewportClearMode"> + The viewport is always cleared before drawing. </constant> <constant name="VIEWPORT_CLEAR_NEVER" value="1" enum="ViewportClearMode"> + The viewport is never cleared before drawing. </constant> <constant name="VIEWPORT_CLEAR_ONLY_NEXT_FRAME" value="2" enum="ViewportClearMode"> + The viewport is cleared once, then the clear mode is set to [VIEWPORT_CLEAR_NEVER]. </constant> <constant name="VIEWPORT_MSAA_DISABLED" value="0" enum="ViewportMSAA"> + Multisample antialiasing is disabled. </constant> <constant name="VIEWPORT_MSAA_2X" value="1" enum="ViewportMSAA"> + Multisample antialiasing is set to 2X. </constant> <constant name="VIEWPORT_MSAA_4X" value="2" enum="ViewportMSAA"> + Multisample antialiasing is set to 4X. </constant> <constant name="VIEWPORT_MSAA_8X" value="3" enum="ViewportMSAA"> + Multisample antialiasing is set to 8X. </constant> <constant name="VIEWPORT_MSAA_16X" value="4" enum="ViewportMSAA"> + Multisample antialiasing is set to 16X. </constant> <constant name="VIEWPORT_USAGE_2D" value="0" enum="ViewportUsage"> + The Viewport does not render 3D but samples. </constant> <constant name="VIEWPORT_USAGE_2D_NO_SAMPLING" value="1" enum="ViewportUsage"> + The Viewport does not render 3D and does not sample. </constant> <constant name="VIEWPORT_USAGE_3D" value="2" enum="ViewportUsage"> + The Viewport renders 3D with effects. </constant> <constant name="VIEWPORT_USAGE_3D_NO_EFFECTS" value="3" enum="ViewportUsage"> + The Viewport renders 3D but without effects. </constant> <constant name="VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME" value="0" enum="ViewportRenderInfo"> </constant> @@ -2019,14 +2271,19 @@ <constant name="VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME" value="5" enum="ViewportRenderInfo"> </constant> <constant name="VIEWPORT_RENDER_INFO_MAX" value="6" enum="ViewportRenderInfo"> + Marks end of VIEWPORT_RENDER_INFO* constants. Used internally. </constant> <constant name="VIEWPORT_DEBUG_DRAW_DISABLED" value="0" enum="ViewportDebugDraw"> + Debug draw is disabled. Default setting. </constant> <constant name="VIEWPORT_DEBUG_DRAW_UNSHADED" value="1" enum="ViewportDebugDraw"> + Debug draw sets objects to unshaded. </constant> <constant name="VIEWPORT_DEBUG_DRAW_OVERDRAW" value="2" enum="ViewportDebugDraw"> + Overwrites clear color to [code](0,0,0,0)[/code]. </constant> <constant name="VIEWPORT_DEBUG_DRAW_WIREFRAME" value="3" enum="ViewportDebugDraw"> + Debug draw draws objects in wireframe. </constant> <constant name="SCENARIO_DEBUG_DISABLED" value="0" enum="ScenarioDebugMode"> </constant> @@ -2037,38 +2294,53 @@ <constant name="SCENARIO_DEBUG_SHADELESS" value="3" enum="ScenarioDebugMode"> </constant> <constant name="INSTANCE_NONE" value="0" enum="InstanceType"> + The instance does not have a type. </constant> <constant name="INSTANCE_MESH" value="1" enum="InstanceType"> + The instance is a mesh. </constant> <constant name="INSTANCE_MULTIMESH" value="2" enum="InstanceType"> + The instance is a multimesh. </constant> <constant name="INSTANCE_IMMEDIATE" value="3" enum="InstanceType"> + The instance is an immediate geometry. </constant> <constant name="INSTANCE_PARTICLES" value="4" enum="InstanceType"> + The instance is a particle emitter. </constant> <constant name="INSTANCE_LIGHT" value="5" enum="InstanceType"> + The instance is a light. </constant> <constant name="INSTANCE_REFLECTION_PROBE" value="6" enum="InstanceType"> </constant> <constant name="INSTANCE_GI_PROBE" value="7" enum="InstanceType"> </constant> <constant name="INSTANCE_MAX" value="8" enum="InstanceType"> + The max value for INSTANCE_* constants, used internally. </constant> <constant name="INSTANCE_GEOMETRY_MASK" value="30" enum="InstanceType"> + A combination of the flags of geometry instances (mesh, multimesh, immediate and particles). </constant> <constant name="NINE_PATCH_STRETCH" value="0" enum="NinePatchAxisMode"> + The nine patch gets stretched where needed. </constant> <constant name="NINE_PATCH_TILE" value="1" enum="NinePatchAxisMode"> + The nine patch gets filled with tiles where needed. </constant> <constant name="NINE_PATCH_TILE_FIT" value="2" enum="NinePatchAxisMode"> + The nine patch gets filled with tiles where needed and stretches them a bit if needed. </constant> <constant name="CANVAS_LIGHT_MODE_ADD" value="0" enum="CanvasLightMode"> + Adds light color additive to the canvas. </constant> <constant name="CANVAS_LIGHT_MODE_SUB" value="1" enum="CanvasLightMode"> + Adds light color subtractive to the canvas. </constant> <constant name="CANVAS_LIGHT_MODE_MIX" value="2" enum="CanvasLightMode"> + The light adds color depending on transparency. </constant> <constant name="CANVAS_LIGHT_MODE_MASK" value="3" enum="CanvasLightMode"> + The light adds color depending on mask. </constant> <constant name="CANVAS_LIGHT_FILTER_NONE" value="0" enum="CanvasLightShadowFilter"> </constant> @@ -2083,30 +2355,42 @@ <constant name="CANVAS_LIGHT_FILTER_PCF13" value="5" enum="CanvasLightShadowFilter"> </constant> <constant name="CANVAS_OCCLUDER_POLYGON_CULL_DISABLED" value="0" enum="CanvasOccluderPolygonCullMode"> + Culling of the canvas occluder is disabled. </constant> <constant name="CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE" value="1" enum="CanvasOccluderPolygonCullMode"> + Culling of the canvas occluder is clockwise. </constant> <constant name="CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE" value="2" enum="CanvasOccluderPolygonCullMode"> + Culling of the canvas occluder is counterclockwise. </constant> <constant name="INFO_OBJECTS_IN_FRAME" value="0" enum="RenderInfo"> + The amount of objects in the frame. </constant> <constant name="INFO_VERTICES_IN_FRAME" value="1" enum="RenderInfo"> + The amount of vertices in the frame. </constant> <constant name="INFO_MATERIAL_CHANGES_IN_FRAME" value="2" enum="RenderInfo"> + The amount of modified materials in the frame. </constant> <constant name="INFO_SHADER_CHANGES_IN_FRAME" value="3" enum="RenderInfo"> + The amount of shader rebinds in the frame. </constant> <constant name="INFO_SURFACE_CHANGES_IN_FRAME" value="4" enum="RenderInfo"> + The amount of surface changes in the frame. </constant> <constant name="INFO_DRAW_CALLS_IN_FRAME" value="5" enum="RenderInfo"> + The amount of draw calls in frame. </constant> <constant name="INFO_USAGE_VIDEO_MEM_TOTAL" value="6" enum="RenderInfo"> </constant> <constant name="INFO_VIDEO_MEM_USED" value="7" enum="RenderInfo"> + The amount of vertex memory and texture memory used. </constant> <constant name="INFO_TEXTURE_MEM_USED" value="8" enum="RenderInfo"> + The amount of texture memory used. </constant> <constant name="INFO_VERTEX_MEM_USED" value="9" enum="RenderInfo"> + The amount of vertex memory used. </constant> <constant name="FEATURE_SHADERS" value="0" enum="Features"> </constant> diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 0839f930c9..309497c938 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -527,7 +527,9 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); #ifdef GLES_OVER_GL glEnable(GL_LINE_SMOOTH); - if (pline->lines.size()) { + if (pline->multiline) { + //needs to be different + } else { _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); } glDisable(GL_LINE_SMOOTH); @@ -538,7 +540,23 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur if (pline->antialiased) glEnable(GL_LINE_SMOOTH); #endif - _draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); + + if (pline->multiline) { + int todo = pline->lines.size() / 2; + int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); + int offset = 0; + + while (todo) { + int to_draw = MIN(max_per_call, todo); + _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1); + todo -= to_draw; + offset += to_draw * 2; + } + + } else { + + _draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); + } #ifdef GLES_OVER_GL if (pline->antialiased) @@ -1705,6 +1723,7 @@ void RasterizerCanvasGLES3::initialize() { glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW); //allocate max size glBindBuffer(GL_ARRAY_BUFFER, 0); + data.polygon_buffer_size = poly_size; //quad arrays for (int i = 0; i < 4; i++) { diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 325df8e4f1..21102e8c25 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -81,6 +81,16 @@ static int _get_datatype_size(SL::DataType p_type) { ERR_FAIL_V(0); } +static String _interpstr(SL::DataInterpolation p_interp) { + + switch (p_interp) { + case SL::INTERPOLATION_FLAT: return "flat "; + case SL::INTERPOLATION_NO_PERSPECTIVE: return "noperspective "; + case SL::INTERPOLATION_SMOOTH: return "smooth "; + } + return ""; +} + static String _prestr(SL::DataPrecision p_pres) { switch (p_pres) { @@ -220,7 +230,6 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) { - print_line(String(p_node->functions[fidx].name) + " uses function: " + String(E->get())); if (added.has(E->get())) { continue; //was added already } @@ -383,12 +392,13 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { String vcode; + String interp_mode = _interpstr(E->get().interpolation); vcode += _prestr(E->get().precission); vcode += _typestr(E->get().type); vcode += " " + _mkid(E->key()); vcode += ";\n"; - r_gen_code.vertex_global += "out " + vcode; - r_gen_code.fragment_global += "in " + vcode; + r_gen_code.vertex_global += interp_mode + "out " + vcode; + r_gen_code.fragment_global += interp_mode + "in " + vcode; } Map<StringName, String> function_code; diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index a62c124dfe..fbee08c0fe 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -116,7 +116,7 @@ void main() { #endif } - } else { + } else if(delta > 0.0) { if (restart_phase >= prev_system_phase) { restart=true; #ifdef USE_FRACTIONAL_DELTA diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index 1d70f8ba55..c6757ba98f 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -1124,6 +1124,8 @@ void AnimationKeyEditor::_track_editor_draw() { Ref<Texture> add_key_icon = get_icon("TrackAddKey", "EditorIcons"); Ref<Texture> add_key_icon_hl = get_icon("TrackAddKeyHl", "EditorIcons"); Ref<Texture> down_icon = get_icon("select_arrow", "Tree"); + Ref<Texture> checked = get_icon("checked", "Tree"); + Ref<Texture> unchecked = get_icon("unchecked", "Tree"); Ref<Texture> wrap_icon[2] = { get_icon("InterpWrapClamp", "EditorIcons"), @@ -1170,6 +1172,7 @@ void AnimationKeyEditor::_track_editor_draw() { v_scroll->set_page(fit); } + int left_check_ofs = checked->get_width(); int settings_limit = size.width - right_separator_ofs; int name_limit = settings_limit * name_column_ratio; @@ -1332,6 +1335,7 @@ void AnimationKeyEditor::_track_editor_draw() { valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists); } + // Draw background color of the whole track if (/*mouse_over.over!=MouseOver::OVER_NONE &&*/ idx == mouse_over.track) { Color sepc = hover_color; te->draw_rect(Rect2(ofs + Point2(0, y), Size2(size.width, h - 1)), sepc); @@ -1343,14 +1347,20 @@ void AnimationKeyEditor::_track_editor_draw() { te->draw_rect(Rect2(ofs + Point2(0, y), Size2(size.width - 1, h - 1)), tc); } - te->draw_texture(type_icon[animation->track_get_type(idx)], ofs + Point2(0, y + (h - type_icon[0]->get_height()) / 2).floor()); + // Draw track enabled state check box + Ref<Texture> check_box = animation->track_is_enabled(idx) ? checked : unchecked; + te->draw_texture(check_box, ofs + Point2(0, y + (h - checked->get_height()) / 2).floor()); + + // Draw track type glyph and node path + te->draw_texture(type_icon[animation->track_get_type(idx)], ofs + Point2(left_check_ofs + sep, y + (h - type_icon[0]->get_height()) / 2).floor()); NodePath np = animation->track_get_path(idx); Node *n = root ? root->get_node(np) : (Node *)NULL; Color ncol = color; if (n && editor_selection->is_selected(n)) ncol = track_select_color; - te->draw_string(font, Point2(ofs + Point2(type_icon[0]->get_width() + sep, y + font->get_ascent() + (sep / 2))).floor(), np, ncol, name_limit - (type_icon[0]->get_width() + sep) - 5); + te->draw_string(font, Point2(ofs + Point2(left_check_ofs + sep + type_icon[0]->get_width() + sep, y + font->get_ascent() + (sep / 2))).floor(), np, ncol, name_limit - (type_icon[0]->get_width() + sep) - 5); + // Draw separator line below track area if (!obj) te->draw_line(ofs + Point2(0, y + h / 2), ofs + Point2(name_limit, y + h / 2), invalid_path_color); @@ -1798,6 +1808,7 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) Ref<Texture> down_icon = get_icon("select_arrow", "Tree"); Ref<Texture> hsize_icon = get_icon("Hsize", "EditorIcons"); Ref<Texture> add_key_icon = get_icon("TrackAddKey", "EditorIcons"); + Ref<Texture> check_icon = get_icon("checked", "Tree"); Ref<Texture> wrap_icon[2] = { get_icon("InterpWrapClamp", "EditorIcons"), @@ -1832,6 +1843,7 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) v_scroll->set_page(fit); } + int left_check_ofs = check_icon->get_width(); int settings_limit = size.width - right_separator_ofs; int name_limit = settings_limit * name_column_ratio; @@ -2092,7 +2104,12 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) return; } - if (mpos.x < name_limit - (type_icon[0]->get_width() / 2.0)) { + if (mpos.x < left_check_ofs) { + // Checkbox on the very left to enable/disable tracks. + + animation->track_set_enabled(idx, !animation->track_is_enabled(idx)); + + } else if (mpos.x < name_limit - (type_icon[0]->get_width() / 2.0)) { //name column // area @@ -2103,7 +2120,7 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input) return; } - Rect2 area(ofs.x, ofs.y + ((int(mpos.y) / h) + 1) * h, name_limit, h); + Rect2 area(ofs.x + left_check_ofs + sep, ofs.y + ((int(mpos.y) / h) + 1) * h, name_limit - left_check_ofs - sep, h); track_name->set_text(animation->track_get_path(idx)); track_name->set_position(te->get_global_position() + area.position); track_name->set_size(area.size); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 8f427582ae..676b168371 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -202,8 +202,9 @@ class EditorHelpSearch::IncrementalSearch : public Reference { } public: - IncrementalSearch(EditorHelpSearch *p_search, Tree *p_search_options, const String &p_term) - : search(p_search), search_options(p_search_options) { + IncrementalSearch(EditorHelpSearch *p_search, Tree *p_search_options, const String &p_term) : + search(p_search), + search_options(p_search_options) { def_icon = search->get_icon("Node", "EditorIcons"); doc = EditorHelp::get_doc_data(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 0252358a27..27ed53bb42 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1884,7 +1884,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene")); save_confirmation->popup_centered_minsize(); break; + } else { + tab_closing = editor_data.get_edited_scene(); } + } // fallthrough case SCENE_TAB_CLOSE: case FILE_SAVE_SCENE: { @@ -3366,7 +3369,6 @@ void EditorNode::register_editor_types() { ClassDB::register_class<EditorResourceConversionPlugin>(); ClassDB::register_class<EditorSceneImporter>(); - // FIXME: Is this stuff obsolete, or should it be ported to new APIs? ClassDB::register_class<EditorScenePostImport>(); //ClassDB::register_type<EditorImportExport>(); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index a39e4d6efb..5c4c2b694f 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -565,12 +565,12 @@ void EditorPlugin::save_global_state() {} void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer) { ResourceFormatImporter::get_singleton()->add_importer(p_importer); - EditorFileSystem::get_singleton()->scan(); + EditorFileSystem::get_singleton()->call_deferred("scan"); } void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) { ResourceFormatImporter::get_singleton()->remove_importer(p_importer); - EditorFileSystem::get_singleton()->scan(); + EditorFileSystem::get_singleton()->call_deferred("scan"); } void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) { @@ -587,7 +587,6 @@ void EditorPlugin::add_scene_import_plugin(const Ref<EditorSceneImporter> &p_imp void EditorPlugin::remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) { ResourceImporterScene::get_singleton()->remove_importer(p_importer); - } void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 89a6d3d250..f45d1c1ecc 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -31,11 +31,11 @@ #define EDITOR_PLUGIN_H #include "editor/import/editor_import_plugin.h" +#include "editor/import/resource_importer_scene.h" #include "io/config_file.h" #include "scene/gui/tool_button.h" #include "scene/main/node.h" #include "scene/resources/texture.h" -#include "editor/import/resource_importer_scene.h" #include "undo_redo.h" /** diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 04e09abcea..d199b27b83 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -348,7 +348,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/files/autosave_interval_secs", 0); _initial_set("text_editor/cursor/block_caret", false); - _initial_set("text_editor/cursor/caret_blink", false); + _initial_set("text_editor/cursor/caret_blink", true); _initial_set("text_editor/cursor/caret_blink_speed", 0.65); hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.1"); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 4661fcf668..8b9c261f8b 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -625,6 +625,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("radio_checked", "PopupMenu", theme->get_icon("GuiChecked", "EditorIcons")); theme->set_icon("radio_unchecked", "PopupMenu", theme->get_icon("GuiUnchecked", "EditorIcons")); theme->set_icon("submenu", "PopupMenu", theme->get_icon("ArrowRight", "EditorIcons")); + theme->set_icon("visibility_hidden", "PopupMenu", theme->get_icon("GuiVisibilityHidden", "EditorIcons")); + theme->set_icon("visibility_visible", "PopupMenu", theme->get_icon("GuiVisibilityVisible", "EditorIcons")); + theme->set_icon("visibility_xray", "PopupMenu", theme->get_icon("GuiVisibilityXray", "EditorIcons")); theme->set_constant("vseparation", "PopupMenu", (extra_spacing + default_margin_size) * EDSCALE); // Tree & ItemList background diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index ca6571fdda..9ece36ea80 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -806,6 +806,39 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_ memdelete(da); } +void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const { + //Ensure folder paths end with "/" + String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/"); + String new_path = (p_item.is_file || p_new_path.ends_with("/")) ? p_new_path : (p_new_path + "/"); + + if (new_path == old_path) { + return; + } else if (old_path == "res://") { + EditorNode::get_singleton()->add_io_error(TTR("Cannot move/rename resources root.")); + return; + } else if (!p_item.is_file && new_path.begins_with(old_path)) { + //This check doesn't erroneously catch renaming to a longer name as folder paths always end with "/" + EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.\n") + old_path + "\n"); + return; + } + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + print_line("Duplicating " + old_path + " -> " + new_path); + Error err = da->copy(old_path, new_path); + if (err == OK) { + //Move/Rename any corresponding import settings too + if (p_item.is_file && FileAccess::exists(old_path + ".import")) { + err = da->copy(old_path + ".import", new_path + ".import"); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:\n") + old_path + ".import\n"); + } + } + } else { + EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:\n") + old_path + "\n"); + } + memdelete(da); +} + void FileSystemDock::_update_dependencies_after_move(const Map<String, String> &p_renames) const { //The following code assumes that the following holds: // 1) EditorFileSystem contains the old paths/folder structure from before the rename/move. @@ -888,6 +921,39 @@ void FileSystemDock::_rename_operation_confirm() { _rescan(); } +void FileSystemDock::_duplicate_operation_confirm() { + + String new_name = duplicate_dialog_text->get_text().strip_edges(); + if (new_name.length() == 0) { + EditorNode::get_singleton()->show_warning(TTR("No name provided.")); + return; + } else if (new_name.find("/") != -1 || new_name.find("\\") != -1 || new_name.find(":") != -1) { + EditorNode::get_singleton()->show_warning(TTR("Name contains invalid characters.")); + return; + } + + String old_path = to_duplicate.path.ends_with("/") ? to_duplicate.path.substr(0, to_duplicate.path.length() - 1) : to_rename.path; + String new_path = old_path.get_base_dir().plus_file(new_name); + if (old_path == new_path) { + return; + } + + //Present a more user friendly warning for name conflict + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da->file_exists(new_path) || da->dir_exists(new_path)) { + EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists.")); + memdelete(da); + return; + } + memdelete(da); + + _try_duplicate_item(to_duplicate, new_name); + + //Rescan everything + print_line("call rescan!"); + _rescan(); +} + void FileSystemDock::_move_operation_confirm(const String &p_to_path) { Map<String, String> renames; @@ -1003,6 +1069,27 @@ void FileSystemDock::_file_option(int p_option) { //2) warn } } break; + case FILE_DUPLICATE: { + int idx = files->get_current(); + if (idx < 0 || idx >= files->get_item_count()) + break; + + to_duplicate.path = files->get_item_metadata(idx); + to_duplicate.is_file = !to_duplicate.path.ends_with("/"); + if (to_duplicate.is_file) { + String name = to_duplicate.path.get_file(); + duplicate_dialog->set_title(TTR("Duplicating file:") + " " + name); + duplicate_dialog_text->set_text(name); + duplicate_dialog_text->select(0, name.find_last(".")); + } else { + String name = to_duplicate.path.substr(0, to_duplicate.path.length() - 1).get_file(); + duplicate_dialog->set_title(TTR("Duplicating folder:") + " " + name); + duplicate_dialog_text->set_text(name); + duplicate_dialog_text->select(0, name.length()); + } + duplicate_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE); + duplicate_dialog_text->grab_focus(); + } break; case FILE_INFO: { } break; @@ -1441,10 +1528,14 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { if (!all_files_scenes && filenames.size() == 1) { file_options->add_item(TTR("Open"), FILE_OPEN); file_options->add_separator(); + } + + if (filenames.size() == 1) { file_options->add_item(TTR("Edit Dependencies.."), FILE_DEPENDENCIES); file_options->add_item(TTR("View Owners.."), FILE_OWNERS); file_options->add_separator(); } + } else if (all_folders && foldernames.size() > 0) { file_options->add_item(TTR("Open"), FILE_OPEN); file_options->add_separator(); @@ -1455,6 +1546,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { if (num_items == 1) { file_options->add_item(TTR("Copy Path"), FILE_COPY_PATH); file_options->add_item(TTR("Rename.."), FILE_RENAME); + file_options->add_item(TTR("Duplicate.."), FILE_DUPLICATE); } file_options->add_item(TTR("Move To.."), FILE_MOVE); file_options->add_item(TTR("Delete"), FILE_REMOVE); @@ -1566,6 +1658,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm); ClassDB::bind_method(D_METHOD("_move_operation_confirm"), &FileSystemDock::_move_operation_confirm); ClassDB::bind_method(D_METHOD("_rename_operation_confirm"), &FileSystemDock::_rename_operation_confirm); + ClassDB::bind_method(D_METHOD("_duplicate_operation_confirm"), &FileSystemDock::_duplicate_operation_confirm); ClassDB::bind_method(D_METHOD("_search_changed"), &FileSystemDock::_search_changed); @@ -1739,6 +1832,17 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { rename_dialog->register_text_enter(rename_dialog_text); rename_dialog->connect("confirmed", this, "_rename_operation_confirm"); + duplicate_dialog = memnew(ConfirmationDialog); + VBoxContainer *duplicate_dialog_vb = memnew(VBoxContainer); + duplicate_dialog->add_child(duplicate_dialog_vb); + + duplicate_dialog_text = memnew(LineEdit); + duplicate_dialog_vb->add_margin_child(TTR("Name:"), duplicate_dialog_text); + duplicate_dialog->get_ok()->set_text(TTR("Duplicate")); + add_child(duplicate_dialog); + duplicate_dialog->register_text_enter(duplicate_dialog_text); + duplicate_dialog->connect("confirmed", this, "_duplicate_operation_confirm"); + make_dir_dialog = memnew(ConfirmationDialog); make_dir_dialog->set_title(TTR("Create Folder")); VBoxContainer *make_folder_dialog_vb = memnew(VBoxContainer); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index b004b1974d..bc8d835ba1 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -70,6 +70,7 @@ private: FILE_MOVE, FILE_RENAME, FILE_REMOVE, + FILE_DUPLICATE, FILE_REIMPORT, FILE_INFO, FILE_NEW_FOLDER, @@ -120,6 +121,8 @@ private: EditorDirDialog *move_dialog; ConfirmationDialog *rename_dialog; LineEdit *rename_dialog_text; + ConfirmationDialog *duplicate_dialog; + LineEdit *duplicate_dialog_text; ConfirmationDialog *make_dir_dialog; LineEdit *make_dir_dialog_text; @@ -136,6 +139,7 @@ private: is_file(p_is_file) {} }; FileOrFolder to_rename; + FileOrFolder to_duplicate; Vector<FileOrFolder> to_move; Vector<String> history; @@ -172,10 +176,12 @@ private: void _get_all_files_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files) const; void _find_remaps(EditorFileSystemDirectory *efsd, const Map<String, String> &renames, Vector<String> &to_remaps) const; void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, Map<String, String> &p_renames) const; + void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const; void _update_dependencies_after_move(const Map<String, String> &p_renames) const; void _make_dir_confirm(); void _rename_operation_confirm(); + void _duplicate_operation_confirm(); void _move_operation_confirm(const String &p_to_path); void _file_option(int p_option); diff --git a/editor/icons/icon_GUI_visibility_hidden.svg b/editor/icons/icon_GUI_visibility_hidden.svg new file mode 100644 index 0000000000..2add2e9eb8 --- /dev/null +++ b/editor/icons/icon_GUI_visibility_hidden.svg @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg2" + inkscape:version="0.91 r13725" + sodipodi:docname="icon_GUI_visibility_hidden.svg"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1027" + id="namedview8" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="18.882384" + inkscape:cy="7.2939487" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" /> + <path + style="color:#000000;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-opacity:1;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + d="M 8.3320312 2.1328125 C 8.1166713 2.129146 7.900423 2.1368613 7.6855469 2.1542969 C 4.8418629 2.3850399 2.1034153 4.4237115 1.0449219 7.5722656 C 0.98765482 7.7577705 0.9856205 7.9559357 1.0390625 8.1425781 C 1.2458895 8.8664725 1.5352035 9.5092453 1.8730469 10.089844 L 12.501953 3.7890625 C 11.256805 2.6845102 9.797893 2.1577685 8.3320312 2.1328125 z M 14.554688 3.3046875 L 0.7421875 11.507812 L 1.4453125 12.695312 L 15.257812 4.4921875 L 14.554688 3.3046875 z M 14.169922 5.8847656 L 3.6171875 12.140625 C 4.9944165 13.294116 6.6188565 13.867188 8 13.867188 C 10.5 13.867188 13.836536 12.077978 14.960938 8.1425781 C 15.012856 7.9619931 15.012856 7.7704285 14.960938 7.5898438 C 14.731965 6.9583712 14.46336 6.3981967 14.169922 5.8847656 z " + id="path6" /> +</svg> diff --git a/editor/icons/icon_GUI_visibility_visible.svg b/editor/icons/icon_GUI_visibility_visible.svg new file mode 100644 index 0000000000..11ae563779 --- /dev/null +++ b/editor/icons/icon_GUI_visibility_visible.svg @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg2" + inkscape:version="0.91 r13725" + sodipodi:docname="icon_visibility_visible.svg"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1027" + id="namedview8" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="15.823281" + inkscape:cy="12.108563" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" /> + <g + transform="translate(0 -1036.4)" + id="g4" + style="fill:#e0e0e0;fill-opacity:1"> + <path + transform="translate(0,1036.4)" + d="M 8,2 C 5.4433,2 2.2093,3.9477 1.0449,7.7051 c -0.0572671,0.1855049 -0.059303,0.3836676 -0.00586,0.57031 1.1244,3.9354 4.4609,5.7246 6.9609,5.7246 2.5000004,0 5.8365004,-1.7892 6.9609004,-5.7246 0.05192,-0.180585 0.05192,-0.372145 0,-0.55273 -1.1003,-3.7876 -4.4066,-5.7227 -6.9609004,-5.7227 z m 0,2 c 2.209139,0 4,1.790861 4,4 0,2.209139 -1.790861,4 -4,4 C 5.790861,12 4,10.209139 4,8 4,5.790861 5.790861,4 8,4 Z M 8,6 C 6.8954305,6 6,6.8954305 6,8 6,9.1045695 6.8954305,10 8,10 9.1045695,10 10,9.1045695 10,8 10,6.8954305 9.1045695,6 8,6 Z" + style="color:#000000;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-opacity:1;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path6" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccsccccssssssssss" /> + </g> +</svg> diff --git a/editor/icons/icon_GUI_visibility_xray.svg b/editor/icons/icon_GUI_visibility_xray.svg new file mode 100644 index 0000000000..1fd9fcf1b5 --- /dev/null +++ b/editor/icons/icon_GUI_visibility_xray.svg @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg2" + inkscape:version="0.91 r13725" + sodipodi:docname="icon_GUI_visibility_xray.svg"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1027" + id="namedview8" + showgrid="false" + inkscape:zoom="7.375" + inkscape:cx="43.019438" + inkscape:cy="-8.9853027" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" /> + <g + transform="translate(0.20338214,-1036.671)" + id="g4" + style="fill:#e0e0e0;fill-opacity:1" /> + <path + id="path4154" + style="opacity:1;fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42799997;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + d="m 5.0107427,7.1191578 c -0.084872,0.2859445 -0.1282828,0.5825859 -0.128907,0.8808593 8.579e-4,0.263009 0.034983,0.5248532 0.101563,0.7792969 l 6.0312493,0 C 11.081887,8.5249547 11.116668,8.2631092 11.118164,8.0000171 11.11754,7.7017437 11.074129,7.4051023 10.989257,7.1191578 Z M 7.9999096,2.000005 c -2.5567,0 -5.7907,1.9477 -6.9551,5.7051 -0.057267,0.1855049 -0.059303,0.3836676 -0.00586,0.57031 1.1244,3.9354 4.4609,5.7246 6.9609,5.7246 2.4999994,0 5.8364994,-1.7892 6.9608994,-5.7246 0.05192,-0.180585 0.05192,-0.372145 0,-0.55273 -1.1003,-3.7876 -4.4066,-5.7227 -6.9608994,-5.7227 z m 0,2 c 2.2091384,0 3.9999994,1.790861 3.9999994,4 0,2.209139 -1.790861,4 -3.9999994,4 -2.209139,0 -4,-1.790861 -4,-4 0,-2.209139 1.790861,-4 4,-4 z" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccccccccsccccsssss" /> +</svg> diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index c38391c71b..c4315f1b83 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -1979,7 +1979,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_ return state.scene; } -Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps) { +Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { ColladaImport state; diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h index 986b5b766f..904080c19b 100644 --- a/editor/import/editor_import_collada.h +++ b/editor/import/editor_import_collada.h @@ -40,7 +40,7 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps); EditorSceneImporterCollada(); }; diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index e801f3e7c3..00eb69a568 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -1597,8 +1597,11 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node if (n->mesh >= 0) { ERR_FAIL_INDEX(n->mesh, state.meshes.size()); MeshInstance *mi = memnew(MeshInstance); - const GLTFMesh &mesh = state.meshes[n->mesh]; + GLTFMesh &mesh = state.meshes[n->mesh]; mi->set_mesh(mesh.mesh); + if (mesh.mesh->get_name() == "") { + mesh.mesh->set_name(n->name); + } for (int i = 0; i < mesh.blend_weights.size(); i++) { mi->set("blend_shapes/" + mesh.mesh->get_blend_shape_name(i), mesh.blend_weights[i]); } diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index 0c8000427e..91c584a05a 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -296,7 +296,7 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps); EditorSceneImporterGLTF(); }; diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h index 09dc8ac8a1..e66ea47b69 100644 --- a/editor/import/resource_importer_obj.h +++ b/editor/import/resource_importer_obj.h @@ -40,7 +40,7 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps); EditorOBJImporter(); }; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 4ef8ec48a0..08d2897250 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -47,8 +47,6 @@ #include "scene/resources/ray_shape.h" #include "scene/resources/sphere_shape.h" - - uint32_t EditorSceneImporter::get_import_flags() const { if (get_script_instance()) { @@ -60,80 +58,73 @@ uint32_t EditorSceneImporter::get_import_flags() const { void EditorSceneImporter::get_extensions(List<String> *r_extensions) const { if (get_script_instance()) { - Array arr= get_script_instance()->call("_get_extensions"); - for(int i=0;i<arr.size();i++) { + Array arr = get_script_instance()->call("_get_extensions"); + for (int i = 0; i < arr.size(); i++) { r_extensions->push_back(arr[i]); } return; } ERR_FAIL(); - } Node *EditorSceneImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { if (get_script_instance()) { - return get_script_instance()->call("_import_scene",p_path,p_flags,p_bake_fps); + return get_script_instance()->call("_import_scene", p_path, p_flags, p_bake_fps); } ERR_FAIL_V(NULL); - } -Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps) { +Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { if (get_script_instance()) { - return get_script_instance()->call("_import_animation",p_path,p_flags); + return get_script_instance()->call("_import_animation", p_path, p_flags); } ERR_FAIL_V(NULL); - } //for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf), //and you want to load the resulting file -Node* EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - - return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this,p_path,p_flags,p_bake_fps); +Node *EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { + return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps); } Ref<Animation> EditorSceneImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this,p_path,p_flags,p_bake_fps); - + return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps); } void EditorSceneImporter::_bind_methods() { - ClassDB::bind_method(D_METHOD("import_scene_from_other_importer","path","flags","bake_fps"),&EditorSceneImporter::import_scene_from_other_importer); - ClassDB::bind_method(D_METHOD("import_animation_from_other_importer","path","flags","bake_fps"),&EditorSceneImporter::import_animation_from_other_importer); + ClassDB::bind_method(D_METHOD("import_scene_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_scene_from_other_importer); + ClassDB::bind_method(D_METHOD("import_animation_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_animation_from_other_importer); BIND_VMETHOD(MethodInfo(Variant::INT, "_get_import_flags")); BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_extensions")); - MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene",PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); - mi.return_val.class_name="Node"; + MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); + mi.return_val.class_name = "Node"; BIND_VMETHOD(mi); - mi = MethodInfo(Variant::OBJECT, "_import_animation",PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); - mi.return_val.class_name="Animation"; + mi = MethodInfo(Variant::OBJECT, "_import_animation", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); + mi.return_val.class_name = "Animation"; BIND_VMETHOD(mi); - BIND_CONSTANT( IMPORT_SCENE ); - BIND_CONSTANT( IMPORT_ANIMATION ); - BIND_CONSTANT( IMPORT_ANIMATION_DETECT_LOOP ); - BIND_CONSTANT( IMPORT_ANIMATION_OPTIMIZE ); - BIND_CONSTANT( IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS ); - BIND_CONSTANT( IMPORT_ANIMATION_KEEP_VALUE_TRACKS ); - BIND_CONSTANT( IMPORT_GENERATE_TANGENT_ARRAYS ); - BIND_CONSTANT( IMPORT_FAIL_ON_MISSING_DEPENDENCIES ); - BIND_CONSTANT( IMPORT_MATERIALS_IN_INSTANCES ); - BIND_CONSTANT( IMPORT_USE_COMPRESSION ); - + BIND_CONSTANT(IMPORT_SCENE); + BIND_CONSTANT(IMPORT_ANIMATION); + BIND_CONSTANT(IMPORT_ANIMATION_DETECT_LOOP); + BIND_CONSTANT(IMPORT_ANIMATION_OPTIMIZE); + BIND_CONSTANT(IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS); + BIND_CONSTANT(IMPORT_ANIMATION_KEEP_VALUE_TRACKS); + BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS); + BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES); + BIND_CONSTANT(IMPORT_MATERIALS_IN_INSTANCES); + BIND_CONSTANT(IMPORT_USE_COMPRESSION); } - ///////////////////////////////// void EditorScenePostImport::_bind_methods() { @@ -201,6 +192,10 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const return false; } + if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) { + return false; + } + return true; } @@ -961,6 +956,36 @@ static String _make_extname(const String &p_str) { return ext_name; } +void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) { + + List<PropertyInfo> pi; + p_node->get_property_list(&pi); + + MeshInstance *mi = Object::cast_to<MeshInstance>(p_node); + + if (mi) { + + Ref<ArrayMesh> mesh = mi->get_mesh(); + + if (mesh.is_valid() && !meshes.has(mesh)) { + Spatial *s = mi; + while (s->get_parent_spatial()) { + s = s->get_parent_spatial(); + } + + if (s == mi) { + meshes[mesh] = s->get_transform(); + } else { + meshes[mesh] = s->get_transform() * mi->get_relative_transform(s); + } + } + } + for (int i = 0; i < p_node->get_child_count(); i++) { + + _find_meshes(p_node->get_child(i), meshes); + } +} + void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) { List<PropertyInfo> pi; @@ -1140,7 +1165,8 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? 1 : 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.05)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); @@ -1171,17 +1197,16 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_ Node *n = p_node->get_child(i); _replace_owner(n, p_scene, p_new_owner); } - } -Node* ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps) { +Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { Ref<EditorSceneImporter> importer; String ext = p_path.get_extension().to_lower(); for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) { - if (E->get().ptr()==p_exception) + if (E->get().ptr() == p_exception) continue; List<String> extensions; E->get()->get_extensions(&extensions); @@ -1199,42 +1224,41 @@ Node* ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporte break; } - ERR_FAIL_COND_V(!importer.is_valid(),NULL); + ERR_FAIL_COND_V(!importer.is_valid(), NULL); List<String> missing; Error err; - return importer->import_scene(p_path,p_flags,p_bake_fps,&missing,&err); + return importer->import_scene(p_path, p_flags, p_bake_fps, &missing, &err); } -Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps) { - +Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { - Ref<EditorSceneImporter> importer; - String ext = p_path.get_extension().to_lower(); + Ref<EditorSceneImporter> importer; + String ext = p_path.get_extension().to_lower(); - for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) { + for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) { - if (E->get().ptr()==p_exception) - continue; - List<String> extensions; - E->get()->get_extensions(&extensions); + if (E->get().ptr() == p_exception) + continue; + List<String> extensions; + E->get()->get_extensions(&extensions); - for (List<String>::Element *F = extensions.front(); F; F = F->next()) { + for (List<String>::Element *F = extensions.front(); F; F = F->next()) { - if (F->get().to_lower() == ext) { + if (F->get().to_lower() == ext) { - importer = E->get(); - break; - } - } + importer = E->get(); + break; + } + } - if (importer.is_valid()) - break; - } + if (importer.is_valid()) + break; + } - ERR_FAIL_COND_V(!importer.is_valid(),NULL); + ERR_FAIL_COND_V(!importer.is_valid(), NULL); - return importer->import_animation(p_path,p_flags,p_bake_fps); + return importer->import_animation(p_path, p_flags, p_bake_fps); } Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { @@ -1371,6 +1395,37 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } } + if (light_bake_mode == 2 /* || generate LOD */) { + + Map<Ref<ArrayMesh>, Transform> meshes; + _find_meshes(scene, meshes); + + if (light_bake_mode == 2) { + + float texel_size = p_options["meshes/lightmap_texel_size"]; + texel_size = MAX(0.001, texel_size); + + EditorProgress progress("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size()); + int step = 0; + for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) { + + Ref<ArrayMesh> mesh = E->key(); + String name = mesh->get_name(); + if (name == "") { //should not happen but.. + name = "Mesh " + itos(step); + } + + progress.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step); + + Error err = mesh->lightmap_unwrap(E->get(), texel_size); + if (err != OK) { + EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry."); + } + step++; + } + } + } + if (external_animations || external_materials || external_meshes) { Map<Ref<Animation>, Ref<Animation> > anim_map; Map<Ref<Material>, Ref<Material> > mat_map; diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index fc6ce05fa4..933585a48c 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -40,13 +40,13 @@ class Material; class EditorSceneImporter : public Reference { GDCLASS(EditorSceneImporter, Reference); -protected: +protected: static void _bind_methods(); - - Node* import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); + Node *import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); Ref<Animation> import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); + public: enum ImportFlags { IMPORT_SCENE = 1, @@ -62,11 +62,10 @@ public: }; - virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps); EditorSceneImporter() {} }; @@ -136,6 +135,8 @@ public: virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; virtual int get_import_order() const { return 100; } //after everything + void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes); + void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes); Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map, LightBakeMode p_light_bake_mode); @@ -147,8 +148,8 @@ public: virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); - Node* import_scene_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps); - Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception,const String &p_path, uint32_t p_flags, int p_bake_fps); + Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); + Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); ResourceImporterScene(); }; diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index eee54f3cd2..3ab8f318a7 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -915,6 +915,11 @@ void EditorAssetLibrary::_search(int p_page) { _api_request("asset", REQUESTING_SEARCH, args); } +void EditorAssetLibrary::_search_text_entered(const String &p_text) { + + _search(); +} + HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int p_page_len, int p_total_items, int p_current_items) { HBoxContainer *hbc = memnew(HBoxContainer); @@ -1280,6 +1285,7 @@ void EditorAssetLibrary::_bind_methods() { ClassDB::bind_method("_select_category", &EditorAssetLibrary::_select_category); ClassDB::bind_method("_image_request_completed", &EditorAssetLibrary::_image_request_completed); ClassDB::bind_method("_search", &EditorAssetLibrary::_search, DEFVAL(0)); + ClassDB::bind_method("_search_text_entered", &EditorAssetLibrary::_search_text_entered); ClassDB::bind_method("_install_asset", &EditorAssetLibrary::_install_asset); ClassDB::bind_method("_manage_plugins", &EditorAssetLibrary::_manage_plugins); ClassDB::bind_method("_asset_open", &EditorAssetLibrary::_asset_open); @@ -1309,7 +1315,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { filter = memnew(LineEdit); search_hb->add_child(filter); filter->set_h_size_flags(SIZE_EXPAND_FILL); - filter->connect("text_entered", this, "_search"); + filter->connect("text_entered", this, "_search_text_entered"); search = memnew(Button(TTR("Search"))); search->connect("pressed", this, "_search"); search_hb->add_child(search); diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index 90d597e70a..5536fbb2ec 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -284,6 +284,7 @@ class EditorAssetLibrary : public PanelContainer { void _search(int p_page = 0); void _rerun_search(int p_ignore); + void _search_text_entered(const String &p_text = ""); void _api_request(const String &p_request, RequestType p_request_type, const String &p_arguments = ""); void _http_request_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); void _http_download_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 8eee9c7e7c..150c184e90 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4342,6 +4342,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { drag = DRAG_NONE; bone_last_frame = 0; additive_selection = false; + + // Update the menus checkboxes + call_deferred("set_state", get_state()); } CanvasItemEditor *CanvasItemEditor::singleton = NULL; @@ -4486,15 +4489,24 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(ResourceCache::get(path))); Size2 texture_size = texture->get_size(); - editor_data->get_undo_redo().add_do_method(parent, "add_child", child); - editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); + if (parent) { + editor_data->get_undo_redo().add_do_method(parent, "add_child", child); + editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); + editor_data->get_undo_redo().add_do_reference(child); + editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); + } else { // if we haven't parent, lets try to make a child as a parent. + editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child); + editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); + editor_data->get_undo_redo().add_do_reference(child); + editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL); + } - String new_name = parent->validate_child_name(child); - ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); - editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + if (parent) { + String new_name = parent->validate_child_name(child); + ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); + editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); + editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + } // handle with different property for texture String property = "texture"; @@ -4527,8 +4539,8 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & } // locate at preview position - Point2 pos; - if (parent->has_method("get_global_position")) { + Point2 pos = Point2(0, 0); + if (parent && parent->has_method("get_global_position")) { pos = parent->call("get_global_position"); } Transform2D trans = canvas->get_canvas_transform(); @@ -4689,6 +4701,18 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian return false; } +void CanvasItemEditorViewport::_show_resource_type_selector() { + List<BaseButton *> btn_list; + button_group->get_buttons(&btn_list); + + for (int i = 0; i < btn_list.size(); i++) { + CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]); + check->set_pressed(check->get_text() == default_type); + } + selector->set_title(vformat(TTR("Add %s"), default_type)); + selector->popup_centered_minsize(); +} + void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) { bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT); bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT); @@ -4705,10 +4729,8 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p if (root_node) { list.push_back(root_node); } else { - accept->get_ok()->set_text(TTR("OK :(")); - accept->set_text(TTR("No parent to instance a child at.")); - accept->popup_centered_minsize(); - _remove_preview(); + drop_pos = p_point; + _show_resource_type_selector(); return; } } @@ -4727,15 +4749,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p drop_pos = p_point; if (is_alt) { - List<BaseButton *> btn_list; - button_group->get_buttons(&btn_list); - - for (int i = 0; i < btn_list.size(); i++) { - CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]); - check->set_pressed(check->get_text() == default_type); - } - selector->set_title(vformat(TTR("Add %s"), default_type)); - selector->popup_centered_minsize(); + _show_resource_type_selector(); } else { _perform_drop_data(); } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 457833e1a7..4be09a16e9 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -578,6 +578,7 @@ class CanvasItemEditorViewport : public Control { void _create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point); bool _create_instance(Node *parent, String &path, const Point2 &p_point); void _perform_drop_data(); + void _show_resource_type_selector(); static void _bind_methods(); diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp index 84fc0cecf2..9d116349c0 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_editor_plugin.cpp @@ -195,7 +195,139 @@ void MeshInstanceEditor::_menu_option(int p_option) { outline_dialog->popup_centered(Vector2(200, 90)); } break; + case MENU_OPTION_CREATE_UV2: { + + Ref<ArrayMesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh.")); + err_dialog->popup_centered_minsize(); + return; + } + + Error err = mesh->lightmap_unwrap(node->get_global_transform()); + if (err != OK) { + err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?")); + err_dialog->popup_centered_minsize(); + return; + } + + } break; + case MENU_OPTION_DEBUG_UV1: { + Ref<Mesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("No mesh to debug.")); + err_dialog->popup_centered_minsize(); + return; + } + _create_uv_lines(0); + } break; + case MENU_OPTION_DEBUG_UV2: { + Ref<Mesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("No mesh to debug.")); + err_dialog->popup_centered_minsize(); + return; + } + _create_uv_lines(1); + } break; + } +} + +struct MeshInstanceEditorEdgeSort { + + Vector2 a; + Vector2 b; + + bool operator<(const MeshInstanceEditorEdgeSort &p_b) const { + if (a == p_b.a) + return b < p_b.b; + else + return a < p_b.a; + } + + MeshInstanceEditorEdgeSort() {} + MeshInstanceEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) { + if (p_a < p_b) { + a = p_a; + b = p_b; + } else { + b = p_a; + a = p_b; + } + } +}; + +void MeshInstanceEditor::_create_uv_lines(int p_layer) { + + Ref<Mesh> mesh = node->get_mesh(); + ERR_FAIL_COND(!mesh.is_valid()); + + Set<MeshInstanceEditorEdgeSort> edges; + uv_lines.clear(); + for (int i = 0; i < mesh->get_surface_count(); i++) { + if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) + continue; + Array a = mesh->surface_get_arrays(i); + + PoolVector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2]; + if (uv.size() == 0) { + err_dialog->set_text(TTR("Model has no UV in this layer")); + err_dialog->popup_centered_minsize(); + return; + } + + PoolVector<Vector2>::Read r = uv.read(); + + PoolVector<int> indices = a[Mesh::ARRAY_INDEX]; + PoolVector<int>::Read ri; + + int ic; + bool use_indices; + + if (indices.size()) { + ic = indices.size(); + ri = indices.read(); + use_indices = true; + } else { + ic = uv.size(); + use_indices = false; + } + + for (int j = 0; j < ic; j += 3) { + + for (int k = 0; k < 3; k++) { + + MeshInstanceEditorEdgeSort edge; + if (use_indices) { + edge.a = r[ri[j + k]]; + edge.b = r[ri[j + ((k + 1) % 3)]]; + } else { + edge.a = r[j + k]; + edge.b = r[j + ((k + 1) % 3)]; + } + + if (edges.has(edge)) + continue; + + uv_lines.push_back(edge.a); + uv_lines.push_back(edge.b); + edges.insert(edge); + } + } } + + debug_uv_dialog->popup_centered_minsize(); +} + +void MeshInstanceEditor::_debug_uv_draw() { + + if (uv_lines.size() == 0) + return; + + debug_uv->set_clip_contents(true); + debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), Color(0.2, 0.2, 0.0)); + debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size()); + debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7)); } void MeshInstanceEditor::_create_outline_mesh() { @@ -244,6 +376,7 @@ void MeshInstanceEditor::_bind_methods() { ClassDB::bind_method("_menu_option", &MeshInstanceEditor::_menu_option); ClassDB::bind_method("_create_outline_mesh", &MeshInstanceEditor::_create_outline_mesh); + ClassDB::bind_method("_debug_uv_draw", &MeshInstanceEditor::_debug_uv_draw); } MeshInstanceEditor::MeshInstanceEditor() { @@ -263,6 +396,10 @@ MeshInstanceEditor::MeshInstanceEditor() { options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Outline Mesh.."), MENU_OPTION_CREATE_OUTLINE_MESH); + options->get_popup()->add_separator(); + options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1); + options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2); + options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2); options->get_popup()->connect("id_pressed", this, "_menu_option"); @@ -286,6 +423,14 @@ MeshInstanceEditor::MeshInstanceEditor() { err_dialog = memnew(AcceptDialog); add_child(err_dialog); + + debug_uv_dialog = memnew(AcceptDialog); + debug_uv_dialog->set_title("UV Channel Debug"); + add_child(debug_uv_dialog); + debug_uv = memnew(Control); + debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE); + debug_uv->connect("draw", this, "_debug_uv_draw"); + debug_uv_dialog->add_child(debug_uv); } void MeshInstanceEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/mesh_instance_editor_plugin.h b/editor/plugins/mesh_instance_editor_plugin.h index fa851458ce..68c149f98a 100644 --- a/editor/plugins/mesh_instance_editor_plugin.h +++ b/editor/plugins/mesh_instance_editor_plugin.h @@ -47,6 +47,9 @@ class MeshInstanceEditor : public Node { MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE, MENU_OPTION_CREATE_NAVMESH, MENU_OPTION_CREATE_OUTLINE_MESH, + MENU_OPTION_CREATE_UV2, + MENU_OPTION_DEBUG_UV1, + MENU_OPTION_DEBUG_UV2, }; MeshInstance *node; @@ -58,11 +61,18 @@ class MeshInstanceEditor : public Node { AcceptDialog *err_dialog; + AcceptDialog *debug_uv_dialog; + Control *debug_uv; + Vector<Vector2> uv_lines; + void _menu_option(int p_option); void _create_outline_mesh(); + void _create_uv_lines(int p_layer); friend class MeshInstanceEditorPlugin; + void _debug_uv_draw(); + protected: void _node_removed(Node *p_node); static void _bind_methods(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 6a869aaadb..95f2739927 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1015,14 +1015,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); } break; - case EDIT_FOLD_LINE: { + case EDIT_TOGGLE_FOLD_LINE: { - tx->fold_line(tx->cursor_get_line()); - tx->update(); - } break; - case EDIT_UNFOLD_LINE: { - - tx->unfold_line(tx->cursor_get_line()); + tx->toggle_fold_line(tx->cursor_get_line()); tx->update(); } break; case EDIT_FOLD_ALL_LINES: { @@ -1517,13 +1512,9 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); } - if (p_can_fold) { - // can fold - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); - } else if (p_is_folded) { - // can unfold - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); - } + if (p_can_fold || p_is_folded) + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + if (p_color) { context_menu->add_separator(); context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR); @@ -1587,9 +1578,8 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); edit_menu->get_popup()->add_separator(); #ifdef OSX_ENABLED @@ -1668,8 +1658,7 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), 0); ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD | KEY_K); ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_B); - ED_SHORTCUT("script_text_editor/fold_line", TTR("Fold Line"), KEY_MASK_ALT | KEY_LEFT); - ED_SHORTCUT("script_text_editor/unfold_line", TTR("Unfold Line"), KEY_MASK_ALT | KEY_RIGHT); + ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KEY_MASK_ALT | KEY_F); ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), 0); ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0); #ifdef OSX_ENABLED diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 722015ef3e..e3b81e7c3f 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -91,8 +91,7 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_TO_UPPERCASE, EDIT_TO_LOWERCASE, EDIT_CAPITALIZE, - EDIT_FOLD_LINE, - EDIT_UNFOLD_LINE, + EDIT_TOGGLE_FOLD_LINE, EDIT_FOLD_ALL_LINES, EDIT_UNFOLD_ALL_LINES, SEARCH_FIND, diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index b855d2d4c4..80638c6f1e 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2624,7 +2624,6 @@ void SpatialEditorViewport::_menu_option(int p_option) { view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false); - } break; case VIEW_DISPLAY_WIREFRAME: { @@ -3756,6 +3755,10 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { } } +int SpatialEditor::get_skeleton_visibility_state() const { + return view_menu->get_popup()->get_item_state(view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON)); +} + void SpatialEditor::update_transform_gizmo() { List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -3800,6 +3803,21 @@ void SpatialEditor::update_transform_gizmo() { } } +void _update_all_gizmos(Node *p_node) { + for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { + Spatial *spatial_node = Object::cast_to<Spatial>(p_node->get_child(i)); + if (spatial_node) { + spatial_node->update_gizmo(); + } + + _update_all_gizmos(p_node->get_child(i)); + } +} + +void SpatialEditor::update_all_gizmos() { + _update_all_gizmos(SceneTree::get_singleton()->get_root()); +} + Object *SpatialEditor::_get_editor_data(Object *p_what) { Spatial *sp = Object::cast_to<Spatial>(p_what); @@ -4247,6 +4265,28 @@ void SpatialEditor::_menu_item_pressed(int p_option) { _refresh_menu_icons(); } break; + case MENU_VISIBILITY_SKELETON: { + + const int idx = view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON); + view_menu->get_popup()->toggle_item_statable(idx); + + // Change icon + const int state = view_menu->get_popup()->get_item_state(idx); + switch (state) { + case 0: + view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden")); + break; + case 1: + view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible")); + break; + case 2: + view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray")); + break; + } + + update_all_gizmos(); + + } break; } } @@ -4699,6 +4739,7 @@ void SpatialEditor::_notification(int p_what) { view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON), view_menu->get_popup()->get_icon("visibility_visible")); _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT); @@ -5035,6 +5076,10 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS); + p->add_separator(); + p->add_statable_item(TTR("Skeleton Gizmo visibility"), 3, 1, MENU_VISIBILITY_SKELETON); + p->add_separator(); + p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true); p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 0c2571017b..8369a5de54 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -92,7 +92,7 @@ class SpatialEditorViewport : public Control { VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_OVERDRAW, - VIEW_DISPLAY_SHADELESS, + VIEW_DISPLAY_SHADELESS }; public: @@ -488,7 +488,8 @@ private: MENU_VIEW_GRID, MENU_VIEW_CAMERA_SETTINGS, MENU_LOCK_SELECTED, - MENU_UNLOCK_SELECTED + MENU_UNLOCK_SELECTED, + MENU_VISIBILITY_SKELETON }; Button *tool_button[TOOL_MAX]; @@ -591,7 +592,10 @@ public: Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; } Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; } + int get_skeleton_visibility_state() const; + void update_transform_gizmo(); + void update_all_gizmos(); void select_gizmo_highlight_axis(int p_axis); void set_custom_camera(Node *p_camera) { custom_camera = p_camera; } diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index eb2faa1ab1..b8c57fd959 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -343,7 +343,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { split->add_child(property_editor); helper = memnew(AutotileEditorHelper(this)); - property_editor->edit(helper); + property_editor->call_deferred("edit", helper); // Editor diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index eed1efaf9c..b3743dbdf8 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -430,24 +430,19 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: } else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || hint == PROPERTY_HINT_LAYERS_2D_RENDER || hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || hint == PROPERTY_HINT_LAYERS_3D_RENDER) { - String title; String basename; switch (hint) { case PROPERTY_HINT_LAYERS_2D_RENDER: basename = "layer_names/2d_render"; - title = "2D Render Layers"; break; case PROPERTY_HINT_LAYERS_2D_PHYSICS: basename = "layer_names/2d_physics"; - title = "2D Physics Layers"; break; case PROPERTY_HINT_LAYERS_3D_RENDER: basename = "layer_names/3d_render"; - title = "3D Render Layers"; break; case PROPERTY_HINT_LAYERS_3D_PHYSICS: basename = "layer_names/3d_physics"; - title = "3D Physics Layers"; break; } @@ -469,11 +464,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: show(); - value_label[0]->set_text(title); - value_label[0]->show(); - value_label[0]->set_position(Vector2(4, 4) * EDSCALE); - - checks20gc->set_position(Vector2(4, 4) * EDSCALE + Vector2(0, value_label[0]->get_size().height + 4 * EDSCALE)); + checks20gc->set_position(Vector2(4, 4) * EDSCALE); checks20gc->set_size(checks20gc->get_minimum_size()); set_size(Vector2(4, 4) * EDSCALE + checks20gc->get_position() + checks20gc->get_size()); @@ -656,7 +647,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: } } - if (type) + if (type != Variant::NIL) property_select->select_property_from_basic_type(type, v); updating = false; @@ -1948,6 +1939,7 @@ CustomPropertyEditor::CustomPropertyEditor() { type_button->get_popup()->connect("id_pressed", this, "_type_create_selected"); menu = memnew(PopupMenu); + menu->set_pass_on_modal_close_click(false); add_child(menu); menu->connect("id_pressed", this, "_menu_option"); @@ -2811,13 +2803,12 @@ void PropertyEditor::update_tree() { TreeItem *sep = tree->create_item(root); current_category = sep; String type = p.name; - //* + if (has_icon(type, "EditorIcons")) sep->set_icon(0, get_icon(type, "EditorIcons")); else sep->set_icon(0, get_icon("Object", "EditorIcons")); - //*/ sep->set_text(0, type); sep->set_expand_right(0, true); sep->set_selectable(0, false); @@ -2943,38 +2934,36 @@ void PropertyEditor::update_tree() { } if (use_doc_hints) { - StringName setter; - StringName type; - if (ClassDB::get_setter_and_type_for_property(obj->get_class_name(), p.name, type, setter)) { - String descr; - bool found = false; - Map<StringName, Map<StringName, String> >::Element *E = descr_cache.find(type); - if (E) { + StringName classname = obj->get_class_name(); + StringName propname = p.name; + String descr; + bool found = false; - Map<StringName, String>::Element *F = E->get().find(setter); - if (F) { - found = true; - descr = F->get(); - } + Map<StringName, Map<StringName, String> >::Element *E = descr_cache.find(classname); + if (E) { + Map<StringName, String>::Element *F = E->get().find(propname); + if (F) { + found = true; + descr = F->get(); } - if (!found) { + } - DocData *dd = EditorHelp::get_doc_data(); - Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(type); - if (E) { - for (int i = 0; i < E->get().methods.size(); i++) { - if (E->get().methods[i].name == setter.operator String()) { - descr = E->get().methods[i].description.strip_edges().word_wrap(80); - } + if (!found) { + DocData *dd = EditorHelp::get_doc_data(); + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(classname); + if (E) { + for (int i = 0; i < E->get().properties.size(); i++) { + if (E->get().properties[i].name == propname.operator String()) { + descr = E->get().properties[i].description.strip_edges().word_wrap(80); } } - - descr_cache[type][setter] = descr; } - item->set_tooltip(0, TTR("Property:") + " " + p.name + "\n\n" + descr); + descr_cache[classname][propname] = descr; } + + item->set_tooltip(0, TTR("Property:") + " " + p.name + "\n\n" + descr); } Dictionary d; @@ -4288,6 +4277,7 @@ PropertyEditor::PropertyEditor() { set_physics_process(true); custom_editor = memnew(CustomPropertyEditor); + custom_editor->set_pass_on_modal_close_click(false); add_child(custom_editor); tree->connect("custom_popup_edited", this, "_custom_editor_request"); @@ -4374,7 +4364,7 @@ class SectionedPropertyEditorFilter : public Object { PropertyInfo pi = E->get(); int sp = pi.name.find("/"); - if (pi.name == "resource_path" || pi.name == "resource_name" || pi.name.begins_with("script/")) //skip resource stuff + if (pi.name == "resource_path" || pi.name == "resource_name" || pi.name == "resource_local_to_scene" || pi.name.begins_with("script/")) //skip resource stuff continue; if (sp == -1) { @@ -4524,7 +4514,7 @@ void SectionedPropertyEditor::update_category_list() { else if (!(pi.usage & PROPERTY_USAGE_EDITOR)) continue; - if (pi.name.find(":") != -1 || pi.name == "script" || pi.name == "resource_name" || pi.name == "resource_path") + if (pi.name.find(":") != -1 || pi.name == "script" || pi.name == "resource_name" || pi.name == "resource_path" || pi.name == "resource_local_to_scene") continue; if (search_box && search_box->get_text() != String() && pi.name.findn(search_box->get_text()) == -1) diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index 86de7c56e1..77b73e4635 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -363,23 +363,6 @@ void PropertySelector::_item_selected() { at_class = ClassDB::get_parent_class(at_class); } - - if (text == String()) { - - StringName setter; - StringName type; - if (ClassDB::get_setter_and_type_for_property(class_type, name, type, setter)) { - Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(type); - if (E) { - for (int i = 0; i < E->get().methods.size(); i++) { - if (E->get().methods[i].name == setter.operator String()) { - text = E->get().methods[i].description; - } - } - } - } - } - } else { String at_class = class_type; @@ -516,6 +499,7 @@ void PropertySelector::select_property_from_script(const Ref<Script> &p_script, search_box->grab_focus(); _update_search(); } + void PropertySelector::select_property_from_basic_type(Variant::Type p_type, const String &p_current) { ERR_FAIL_COND(p_type == Variant::NIL); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 3ffc61cb45..43010ed985 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -1316,6 +1316,34 @@ void SkeletonSpatialGizmo::redraw() { Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/skeleton"); Ref<Material> material = create_material("skeleton_material", gizmo_color); + SpatialMaterial *sm = Object::cast_to<SpatialMaterial>(material.ptr()); + + { // Reset + Color c(sm->get_albedo()); + c.a = 1; + sm->set_albedo(c); + } + if (sm) { + switch (SpatialEditor::get_singleton()->get_skeleton_visibility_state()) { + case 0: { + // Hidden + Color c(sm->get_albedo()); + c.a = 0; + sm->set_albedo(c); + sm->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + } break; + case 1: + // Visible + sm->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, false); + sm->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN); + sm->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false); + break; + case 2: + // x-ray + sm->set_on_top_of_alpha(); + break; + } + } Ref<SurfaceTool> surface_tool(memnew(SurfaceTool)); diff --git a/main/main.cpp b/main/main.cpp index b2f091e76a..1328807121 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -819,7 +819,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false); } - use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", true); + video_mode.use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", true); GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation", 2); GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation.mobile", 3); @@ -993,8 +993,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) { // also init our arvr_server from here arvr_server = memnew(ARVRServer); - OS::get_singleton()->set_use_vsync(use_vsync); - register_core_singletons(); MAIN_PRINT("Main: Setup Logo"); diff --git a/main/splash_sponsors.png b/main/splash_sponsors.png Binary files differnew file mode 100644 index 0000000000..d8677f1749 --- /dev/null +++ b/main/splash_sponsors.png diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format index d2d65a7428..8ef4e27748 100755 --- a/misc/hooks/pre-commit-clang-format +++ b/misc/hooks/pre-commit-clang-format @@ -31,7 +31,7 @@ PARSE_EXTS=true # File types to parse. Only effective when PARSE_EXTS is true. # FILE_EXTS=".c .h .cpp .hpp" -FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc" +FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc *.java" # Use pygmentize instead of cat to parse diff with highlighting. # Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac) diff --git a/misc/travis/clang-format.sh b/misc/travis/clang-format.sh index 2b30cf5ada..d1e37cc10e 100755 --- a/misc/travis/clang-format.sh +++ b/misc/travis/clang-format.sh @@ -11,7 +11,7 @@ else RANGE=HEAD fi -FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/ | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc)$") +FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/ | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java)$") echo "Checking files:\n$FILES" # create a random filename to store our generated patch diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 26c879fddb..339dccce33 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -723,15 +723,15 @@ void BulletPhysicsServer::body_set_axis_velocity(RID p_body, const Vector3 &p_ax body->set_linear_velocity(v); } -void BulletPhysicsServer::body_set_axis_lock(RID p_body, PhysicsServer::BodyAxisLock p_lock) { +void BulletPhysicsServer::body_set_axis_lock(RID p_body, int axis, bool p_lock) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND(!body); - body->set_axis_lock(p_lock); + body->set_axis_lock(axis, p_lock); } -PhysicsServer::BodyAxisLock BulletPhysicsServer::body_get_axis_lock(RID p_body) const { +bool BulletPhysicsServer::body_get_axis_lock(RID p_body) const { const RigidBodyBullet *body = rigid_body_owner.get(p_body); - ERR_FAIL_COND_V(!body, BODY_AXIS_LOCK_DISABLED); + ERR_FAIL_COND_V(!body, 0); return body->get_axis_lock(); } diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index ad8137ee2f..ed5acb9041 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -226,8 +226,8 @@ public: virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity); - virtual void body_set_axis_lock(RID p_body, BodyAxisLock p_lock); - virtual BodyAxisLock body_get_axis_lock(RID p_body) const; + virtual void body_set_axis_lock(RID p_body, int axis, bool p_lock); + virtual bool body_get_axis_lock(RID p_body) const; virtual void body_add_collision_exception(RID p_body, RID p_body_b); virtual void body_remove_collision_exception(RID p_body, RID p_body_b); diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h index 5750dc2acd..9d2fb1fce4 100644 --- a/modules/bullet/godot_result_callbacks.h +++ b/modules/bullet/godot_result_callbacks.h @@ -50,14 +50,21 @@ struct GodotFilterCallback : public btOverlapFilterCallback { struct GodotClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { const Set<RID> *m_exclude; bool m_pickRay; + int m_shapeId; public: GodotClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld, const Set<RID> *p_exclude) : btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld), m_exclude(p_exclude), - m_pickRay(false) {} + m_pickRay(false), + m_shapeId(0) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; + + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace) { + m_shapeId = rayResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID + return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); + } }; // store all colliding object diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index b134bd3a36..843bdab31f 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -277,7 +277,7 @@ RigidBodyBullet::RigidBodyBullet() : setupBulletCollisionObject(btBody); set_mode(PhysicsServer::BODY_MODE_RIGID); - set_axis_lock(PhysicsServer::BODY_AXIS_LOCK_DISABLED); + set_axis_lock(0, locked_axis[0]); areasWhereIam.resize(maxAreasWhereIam); for (int i = areasWhereIam.size() - 1; 0 <= i; --i) { @@ -498,25 +498,25 @@ void RigidBodyBullet::set_mode(PhysicsServer::BodyMode p_mode) { switch (p_mode) { case PhysicsServer::BODY_MODE_KINEMATIC: mode = PhysicsServer::BODY_MODE_KINEMATIC; - set_axis_lock(axis_lock); // Reload axis lock + set_axis_lock(0, locked_axis[0]); // Reload axis lock _internal_set_mass(0); init_kinematic_utilities(); break; case PhysicsServer::BODY_MODE_STATIC: mode = PhysicsServer::BODY_MODE_STATIC; - set_axis_lock(axis_lock); // Reload axis lock + set_axis_lock(0, locked_axis[0]); // Reload axis lock _internal_set_mass(0); break; case PhysicsServer::BODY_MODE_RIGID: { mode = PhysicsServer::BODY_MODE_RIGID; - set_axis_lock(axis_lock); // Reload axis lock + set_axis_lock(0, locked_axis[0]); // Reload axis lock _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; } case PhysicsServer::BODY_MODE_CHARACTER: { mode = PhysicsServer::BODY_MODE_CHARACTER; - set_axis_lock(axis_lock); // Reload axis lock + set_axis_lock(0, locked_axis[0]); // Reload axis lock _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; @@ -655,22 +655,14 @@ Vector3 RigidBodyBullet::get_applied_torque() const { return gTotTorq; } -void RigidBodyBullet::set_axis_lock(PhysicsServer::BodyAxisLock p_lock) { - axis_lock = p_lock; +void RigidBodyBullet::set_axis_lock(int axis, bool p_lock) { + locked_axis[axis] = p_lock; - if (PhysicsServer::BODY_AXIS_LOCK_DISABLED == axis_lock) { - btBody->setLinearFactor(btVector3(1., 1., 1.)); + btBody->setLinearFactor(btVector3(locked_axis[0] ? 0 : 1., locked_axis[1] ? 0 : 1., locked_axis[2] ? 0 : 1.)); + if (locked_axis[0] || locked_axis[1] || locked_axis[2]) + btBody->setAngularFactor(btVector3(locked_axis[0] ? 1. : 0, locked_axis[1] ? 1. : 0, locked_axis[2] ? 1. : 0)); + else btBody->setAngularFactor(btVector3(1., 1., 1.)); - } else if (PhysicsServer::BODY_AXIS_LOCK_X == axis_lock) { - btBody->setLinearFactor(btVector3(0., 1., 1.)); - btBody->setAngularFactor(btVector3(1., 0., 0.)); - } else if (PhysicsServer::BODY_AXIS_LOCK_Y == axis_lock) { - btBody->setLinearFactor(btVector3(1., 0., 1.)); - btBody->setAngularFactor(btVector3(0., 1., 0.)); - } else if (PhysicsServer::BODY_AXIS_LOCK_Z == axis_lock) { - btBody->setLinearFactor(btVector3(1., 1., 0.)); - btBody->setAngularFactor(btVector3(0., 0., 1.)); - } if (PhysicsServer::BODY_MODE_CHARACTER == mode) { /// When character lock angular @@ -678,17 +670,8 @@ void RigidBodyBullet::set_axis_lock(PhysicsServer::BodyAxisLock p_lock) { } } -PhysicsServer::BodyAxisLock RigidBodyBullet::get_axis_lock() const { - btVector3 vec = btBody->getLinearFactor(); - if (0. == vec.x()) { - return PhysicsServer::BODY_AXIS_LOCK_X; - } else if (0. == vec.y()) { - return PhysicsServer::BODY_AXIS_LOCK_Y; - } else if (0. == vec.z()) { - return PhysicsServer::BODY_AXIS_LOCK_Z; - } else { - return PhysicsServer::BODY_AXIS_LOCK_DISABLED; - } +bool RigidBodyBullet::get_axis_lock() const { + return locked_axis; } void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) { diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index c54b5784b5..fde8b21e17 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -184,7 +184,7 @@ private: KinematicUtilities *kinematic_utilities; PhysicsServer::BodyMode mode; - PhysicsServer::BodyAxisLock axis_lock; + bool locked_axis[3] = { false, false, false }; GodotMotionState *godotMotionState; btRigidBody *btBody; real_t mass; @@ -269,8 +269,8 @@ public: void set_applied_torque(const Vector3 &p_torque); Vector3 get_applied_torque() const; - void set_axis_lock(PhysicsServer::BodyAxisLock p_lock); - PhysicsServer::BodyAxisLock get_axis_lock() const; + void set_axis_lock(int axis, bool p_lock); + bool get_axis_lock() const; /// Doc: /// http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Anti_tunneling_by_Motion_Clamping diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index c1f6e81734..3ce4b294db 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -97,7 +97,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V B_TO_G(btResult.m_hitNormalWorld.normalize(), r_result.normal); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btResult.m_collisionObject->getUserPointer()); if (gObj) { - r_result.shape = 0; + r_result.shape = btResult.m_shapeId; r_result.rid = gObj->get_self(); r_result.collider_id = gObj->get_instance_id(); r_result.collider = 0 == r_result.collider_id ? NULL : ObjectDB::get_instance(r_result.collider_id); diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 365def75bc..1cb35ec006 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -99,12 +99,16 @@ static Set<String> get_gdnative_singletons(EditorFileSystemDirectory *p_dir) { } static void actual_discoverer_handler() { + EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->get_filesystem(); Set<String> file_paths = get_gdnative_singletons(dir); bool changed = false; - Array current_files = ProjectSettings::get_singleton()->get("gdnative/singletons"); + Array current_files; + if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) { + current_files = ProjectSettings::get_singleton()->get("gdnative/singletons"); + } Array files; files.resize(file_paths.size()); int i = 0; @@ -128,7 +132,6 @@ static void actual_discoverer_handler() { if (changed) { ProjectSettings::get_singleton()->set("gdnative/singletons", files); - ProjectSettings::get_singleton()->save(); } } diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index d2ce318f82..ee23f0ea0f 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -515,7 +515,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } else { v = "of type '" + _get_var_type(index) + "'"; } - err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '"+_get_var_type(value)+"'"; + err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'"; OPCODE_BREAK; } #endif @@ -574,7 +574,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (!valid) { String err_type; - err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "') with value of type '"+_get_var_type(value)+"'."; + err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'."; OPCODE_BREAK; } #endif diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index e48b03968b..599f204184 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3389,6 +3389,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _set_error("Can't export null type."); return; } + if (type == Variant::OBJECT) { + _set_error("Can't export raw object type."); + return; + } current_export.type = type; current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; tokenizer->advance(); diff --git a/modules/thekla_unwrap/SCsub b/modules/thekla_unwrap/SCsub index 2b1349a15f..1d4b086848 100644 --- a/modules/thekla_unwrap/SCsub +++ b/modules/thekla_unwrap/SCsub @@ -47,7 +47,8 @@ if env['builtin_thekla_atlas']: "nvmesh/param/SingleFaceMap.cpp", "nvmesh/param/Util.cpp", "nvmesh/weld/VertexWeld.cpp", - "nvmesh/weld/Snap.cpp" + "nvmesh/weld/Snap.cpp", + "thekla/thekla_atlas.cpp" ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] diff --git a/modules/thekla_unwrap/register_types.cpp b/modules/thekla_unwrap/register_types.cpp index 8a9f8341e8..01b834f8cb 100644 --- a/modules/thekla_unwrap/register_types.cpp +++ b/modules/thekla_unwrap/register_types.cpp @@ -28,7 +28,88 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "register_types.h" +#include "thirdparty/thekla_atlas/thekla/thekla_atlas.h" +#include <stdio.h> +#include <stdlib.h> +extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y); -void register_thekla_unwrap_types() {} +bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) { -void unregister_thekla_unwrap_types() {} + //set up input mesh + Thekla::Atlas_Input_Mesh input_mesh; + input_mesh.face_array = new Thekla::Atlas_Input_Face[p_index_count / 3]; + for (int i = 0; i < p_index_count / 3; i++) { + input_mesh.face_array[i].vertex_index[0] = p_indices[i * 3 + 0]; + input_mesh.face_array[i].vertex_index[1] = p_indices[i * 3 + 1]; + input_mesh.face_array[i].vertex_index[2] = p_indices[i * 3 + 2]; + printf("face %i - %i, %i, %i - mat %i\n", i, input_mesh.face_array[i].vertex_index[0], input_mesh.face_array[i].vertex_index[1], input_mesh.face_array[i].vertex_index[2], p_face_materials[i]); + input_mesh.face_array[i].material_index = p_face_materials[i]; + } + input_mesh.vertex_array = new Thekla::Atlas_Input_Vertex[p_vertex_count]; + for (int i = 0; i < p_vertex_count; i++) { + input_mesh.vertex_array[i].first_colocal = i; //wtf + for (int j = 0; j < 3; j++) { + input_mesh.vertex_array[i].position[j] = p_vertices[i * 3 + j]; + input_mesh.vertex_array[i].normal[j] = p_normals[i * 3 + j]; + } + input_mesh.vertex_array[i].uv[0] = 0; + input_mesh.vertex_array[i].uv[1] = 0; + printf("vertex %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].position[0], input_mesh.vertex_array[i].position[1], input_mesh.vertex_array[i].position[2]); + printf("normal %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].normal[0], input_mesh.vertex_array[i].normal[1], input_mesh.vertex_array[i].normal[2]); + } + input_mesh.face_count = p_index_count / 3; + input_mesh.vertex_count = p_vertex_count; + + //set up options + Thekla::Atlas_Options options; + Thekla::atlas_set_default_options(&options); + options.packer_options.witness.packing_quality = 1; + options.packer_options.witness.texel_area = 1.0 / p_texel_size; + + //generate + Thekla::Atlas_Error err; + Thekla::Atlas_Output_Mesh *output = atlas_generate(&input_mesh, &options, &err); + + delete[] input_mesh.face_array; + delete[] input_mesh.vertex_array; + + if (err != Thekla::Atlas_Error_Success) { + printf("error with atlas\n"); + } else { + *r_vertex = (int *)malloc(sizeof(int) * output->vertex_count); + *r_uv = (float *)malloc(sizeof(float) * output->vertex_count * 3); + *r_index = (int *)malloc(sizeof(int) * output->index_count); + + // printf("w: %i, h: %i\n", output->atlas_width, output->atlas_height); + for (int i = 0; i < output->vertex_count; i++) { + (*r_vertex)[i] = output->vertex_array[i].xref; + (*r_uv)[i * 2 + 0] = output->vertex_array[i].uv[0] / output->atlas_width; + (*r_uv)[i * 2 + 1] = output->vertex_array[i].uv[1] / output->atlas_height; + // printf("uv: %f,%f\n", (*r_uv)[i * 2 + 0], (*r_uv)[i * 2 + 1]); + } + *r_vertex_count = output->vertex_count; + + for (int i = 0; i < output->index_count; i++) { + (*r_index)[i] = output->index_array[i]; + } + + *r_index_count = output->index_count; + + *r_size_hint_x = output->atlas_height; + *r_size_hint_y = output->atlas_width; + } + + if (output) { + atlas_free(output); + } + + return err == Thekla::Atlas_Error_Success; +} + +void register_thekla_unwrap_types() { + + array_mesh_lightmap_unwrap_callback = thekla_mesh_lightmap_unwrap_callback; +} + +void unregister_thekla_unwrap_types() { +} diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index bb6c32e9e0..53d93798d9 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2047,6 +2047,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o function.argument_count = func_node->get_argument_count(); function.max_stack += function.argument_count; function.flow_stack_size = func_node->is_stack_less() ? 0 : func_node->get_stack_size(); + max_input_args = MAX(max_input_args, function.argument_count); } //multiple passes are required to set up this complex thing.. diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 67e00f4952..255413bf2c 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1557,12 +1557,15 @@ public: encode_uint32(cl.size(), &clf[0]); for (int i = 0; i < cl.size(); i++) { + print_line(itos(i) + " param: " + cl[i]); CharString txt = cl[i].utf8(); int base = clf.size(); - clf.resize(base + 4 + txt.length()); - encode_uint32(txt.length(), &clf[base]); - copymem(&clf[base + 4], txt.ptr(), txt.length()); - print_line(itos(i) + " param: " + cl[i]); + int length = txt.length(); + if (!length) + continue; + clf.resize(base + 4 + length); + encode_uint32(length, &clf[base]); + copymem(&clf[base + 4], txt.ptr(), length); } zip_fileinfo zipfi = get_zip_fileinfo(); diff --git a/platform/android/java/src/org/godotengine/godot/Dictionary.java b/platform/android/java/src/org/godotengine/godot/Dictionary.java index ed91fedd85..2bc9c083aa 100644 --- a/platform/android/java/src/org/godotengine/godot/Dictionary.java +++ b/platform/android/java/src/org/godotengine/godot/Dictionary.java @@ -32,7 +32,6 @@ package org.godotengine.godot; import java.util.HashMap; import java.util.Set; - public class Dictionary extends HashMap<String, Object> { protected String[] keys_cache; @@ -40,7 +39,7 @@ public class Dictionary extends HashMap<String, Object> { public String[] get_keys() { String[] ret = new String[size()]; - int i=0; + int i = 0; Set<String> keys = keySet(); for (String key : keys) { @@ -54,7 +53,7 @@ public class Dictionary extends HashMap<String, Object> { public Object[] get_values() { Object[] ret = new Object[size()]; - int i=0; + int i = 0; Set<String> keys = keySet(); for (String key : keys) { @@ -71,7 +70,7 @@ public class Dictionary extends HashMap<String, Object> { public void set_values(Object[] vals) { - int i=0; + int i = 0; for (String key : keys_cache) { put(key, vals[i]); i++; diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 4daf06142d..3939ceb2e7 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -90,35 +90,34 @@ import android.os.Bundle; import android.os.Messenger; import android.os.SystemClock; - -public class Godot extends Activity implements SensorEventListener, IDownloaderClient -{ +public class Godot extends Activity implements SensorEventListener, IDownloaderClient { static final int MAX_SINGLETONS = 64; private IStub mDownloaderClientStub; - private IDownloaderService mRemoteService; - private TextView mStatusText; - private TextView mProgressFraction; - private TextView mProgressPercent; - private TextView mAverageSpeed; - private TextView mTimeRemaining; - private ProgressBar mPB; - - private View mDashboard; - private View mCellMessage; - - private Button mPauseButton; - private Button mWiFiSettingsButton; - - private boolean use_32_bits=false; - private boolean use_immersive=false; - private boolean mStatePaused; - private int mState; - private boolean keep_screen_on=true; + private IDownloaderService mRemoteService; + private TextView mStatusText; + private TextView mProgressFraction; + private TextView mProgressPercent; + private TextView mAverageSpeed; + private TextView mTimeRemaining; + private ProgressBar mPB; + + private View mDashboard; + private View mCellMessage; + + private Button mPauseButton; + private Button mWiFiSettingsButton; + + private boolean use_32_bits = false; + private boolean use_immersive = false; + private boolean mStatePaused; + private int mState; + private boolean keep_screen_on = true; static private Intent mCurrentIntent; - @Override public void onNewIntent(Intent intent) { + @Override + public void onNewIntent(Intent intent) { mCurrentIntent = intent; } @@ -127,43 +126,43 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } private void setState(int newState) { - if (mState != newState) { - mState = newState; - mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState)); - } - } - - private void setButtonPausedState(boolean paused) { - mStatePaused = paused; - int stringResourceID = paused ? com.godot.game.R.string.text_button_resume : - com.godot.game.R.string.text_button_pause; - mPauseButton.setText(stringResourceID); - } + if (mState != newState) { + mState = newState; + mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState)); + } + } + + private void setButtonPausedState(boolean paused) { + mStatePaused = paused; + int stringResourceID = paused ? com.godot.game.R.string.text_button_resume : + com.godot.game.R.string.text_button_pause; + mPauseButton.setText(stringResourceID); + } static public class SingletonBase { protected void registerClass(String p_name, String[] p_methods) { - GodotLib.singleton(p_name,this); + GodotLib.singleton(p_name, this); Class clazz = getClass(); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { - boolean found=false; - Log.d("XXX","METHOD: %s\n" + method.getName()); + boolean found = false; + Log.d("XXX", "METHOD: %s\n" + method.getName()); for (String s : p_methods) { - Log.d("XXX", "METHOD CMP WITH: %s\n" + s); + Log.d("XXX", "METHOD CMP WITH: %s\n" + s); if (s.equals(method.getName())) { - found=true; - Log.d("XXX","METHOD CMP VALID"); + found = true; + Log.d("XXX", "METHOD CMP VALID"); break; } } if (!found) continue; - Log.d("XXX","METHOD FOUND: %s\n" + method.getName()); + Log.d("XXX", "METHOD FOUND: %s\n" + method.getName()); List<String> ptr = new ArrayList<String>(); @@ -175,17 +174,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC String[] pt = new String[ptr.size()]; ptr.toArray(pt); - GodotLib.method(p_name,method.getName(),method.getReturnType().getName(),pt); - - + GodotLib.method(p_name, method.getName(), method.getReturnType().getName(), pt); } - Godot.singletons[Godot.singleton_count++]=this; + Godot.singletons[Godot.singleton_count++] = this; } protected void onMainActivityResult(int requestCode, int resultCode, Intent data) { - - } protected void onMainPause() {} @@ -200,22 +195,20 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC public void registerMethods() {} } -/* + /* protected List<SingletonBase> singletons = new ArrayList<SingletonBase>(); protected void instanceSingleton(SingletonBase s) { s.registerMethods(); singletons.add(s); } - -*/ + */ private String[] command_line; private boolean use_apk_expansion; public GodotView mView; - private boolean godot_initialized=false; - + private boolean godot_initialized = false; private SensorManager mSensorManager; private Sensor mAccelerometer; @@ -226,36 +219,34 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC public FrameLayout layout; public RelativeLayout adLayout; - static public GodotIO io; public static void setWindowTitle(String title) { //setTitle(title); } - static SingletonBase singletons[] = new SingletonBase[MAX_SINGLETONS]; - static int singleton_count=0; - + static int singleton_count = 0; public interface ResultCallback { public void callback(int requestCode, int resultCode, Intent data); - }; + } public ResultCallback result_callback; private PaymentsManager mPaymentsManager = null; - @Override protected void onActivityResult (int requestCode, int resultCode, Intent data) { - if(requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE){ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE) { mPaymentsManager.processPurchaseResponse(resultCode, data); - }else if (result_callback != null) { + } else if (result_callback != null) { result_callback.callback(requestCode, resultCode, data); result_callback = null; }; - for(int i=0;i<singleton_count;i++) { + for (int i = 0; i < singleton_count; i++) { - singletons[i].onMainActivityResult(requestCode,resultCode,data); + singletons[i].onMainActivityResult(requestCode, resultCode, data); } }; @@ -265,38 +256,38 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC //setContentView(mView); layout = new FrameLayout(this); - layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); + layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); setContentView(layout); // GodotEditText layout GodotEditText edittext = new GodotEditText(this); - edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT)); - // ...add to FrameLayout - layout.addView(edittext); + edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); + // ...add to FrameLayout + layout.addView(edittext); - mView = new GodotView(getApplication(),io,use_gl2,use_32_bits, this); - layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); + mView = new GodotView(getApplication(), io, use_gl2, use_32_bits, this); + layout.addView(mView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); edittext.setView(mView); io.setEdit(edittext); final Godot godot = this; mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - Point fullSize = new Point(); - godot.getWindowManager().getDefaultDisplay().getSize(fullSize); - Rect gameSize = new Rect(); - godot.mView.getWindowVisibleDisplayFrame(gameSize); - - final int keyboardHeight = fullSize.y - gameSize.bottom; - Log.d("GODOT", "setVirtualKeyboardHeight: " + keyboardHeight); - GodotLib.setVirtualKeyboardHeight(keyboardHeight); - } + @Override + public void onGlobalLayout() { + Point fullSize = new Point(); + godot.getWindowManager().getDefaultDisplay().getSize(fullSize); + Rect gameSize = new Rect(); + godot.mView.getWindowVisibleDisplayFrame(gameSize); + + final int keyboardHeight = fullSize.y - gameSize.bottom; + Log.d("GODOT", "setVirtualKeyboardHeight: " + keyboardHeight); + GodotLib.setVirtualKeyboardHeight(keyboardHeight); + } }); // Ad layout adLayout = new RelativeLayout(this); - adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); + adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); layout.addView(adLayout); final String[] current_command_line = command_line; @@ -313,12 +304,11 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC }); } }); - } public void setKeepScreenOn(final boolean p_enabled) { keep_screen_on = p_enabled; - if (mView != null){ + if (mView != null) { runOnUiThread(new Runnable() { @Override public void run() { @@ -335,12 +325,12 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC AlertDialog.Builder builder = new AlertDialog.Builder(getInstance()); builder.setMessage(message).setTitle(title); builder.setPositiveButton( - "OK", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); + "OK", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); AlertDialog dialog = builder.create(); dialog.show(); } @@ -349,91 +339,86 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC private static Godot _self; - public static Godot getInstance(){ + public static Godot getInstance() { return Godot._self; } - private String[] getCommandLine() { - InputStream is; - try { - is = getAssets().open("_cl_"); - byte[] len = new byte[4]; - int r = is.read(len); - if (r<4) { - Log.d("XXX","**ERROR** Wrong cmdline length.\n"); - Log.d("GODOT", "**ERROR** Wrong cmdline length.\n"); - return new String[0]; - } - int argc=((int)(len[3]&0xFF)<<24) | ((int)(len[2]&0xFF)<<16) | ((int)(len[1]&0xFF)<<8) | ((int)(len[0]&0xFF)); - String[] cmdline = new String[argc]; - - for(int i=0;i<argc;i++) { - r = is.read(len); - if (r<4) { - - Log.d("GODOT", "**ERROR** Wrong cmdline param length.\n"); - return new String[0]; - } - int strlen=((int)(len[3]&0xFF)<<24) | ((int)(len[2]&0xFF)<<16) | ((int)(len[1]&0xFF)<<8) | ((int)(len[0]&0xFF)); - if (strlen>65535) { - Log.d("GODOT", "**ERROR** Wrong command len\n"); - return new String[0]; - } - byte[] arg = new byte[strlen]; - r = is.read(arg); - if (r==strlen) { - cmdline[i]=new String(arg,"UTF-8"); - } + InputStream is; + try { + is = getAssets().open("_cl_"); + byte[] len = new byte[4]; + int r = is.read(len); + if (r < 4) { + Log.d("XXX", "**ERROR** Wrong cmdline length.\n"); + Log.d("GODOT", "**ERROR** Wrong cmdline length.\n"); + return new String[0]; + } + int argc = ((int)(len[3] & 0xFF) << 24) | ((int)(len[2] & 0xFF) << 16) | ((int)(len[1] & 0xFF) << 8) | ((int)(len[0] & 0xFF)); + String[] cmdline = new String[argc]; + + for (int i = 0; i < argc; i++) { + r = is.read(len); + if (r < 4) { + + Log.d("GODOT", "**ERROR** Wrong cmdline param length.\n"); + return new String[0]; + } + int strlen = ((int)(len[3] & 0xFF) << 24) | ((int)(len[2] & 0xFF) << 16) | ((int)(len[1] & 0xFF) << 8) | ((int)(len[0] & 0xFF)); + if (strlen > 65535) { + Log.d("GODOT", "**ERROR** Wrong command len\n"); + return new String[0]; + } + byte[] arg = new byte[strlen]; + r = is.read(arg); + if (r == strlen) { + cmdline[i] = new String(arg, "UTF-8"); + } } return cmdline; } catch (Exception e) { - e.printStackTrace(); - Log.d("GODOT", "**ERROR** Exception " + e.getClass().getName() + ":" + e.getMessage()); + e.printStackTrace(); + Log.d("GODOT", "**ERROR** Exception " + e.getClass().getName() + ":" + e.getMessage()); return new String[0]; } - - } - String expansion_pack_path; - private void initializeGodot() { - if (expansion_pack_path!=null) { + if (expansion_pack_path != null) { String[] new_cmdline; - int cll=0; - if (command_line!=null) { - Log.d("GODOT", "initializeGodot: command_line: is not null" ); - new_cmdline = new String[ command_line.length + 2 ]; - cll=command_line.length; - for(int i=0;i<command_line.length;i++) { - new_cmdline[i]=command_line[i]; + int cll = 0; + if (command_line != null) { + Log.d("GODOT", "initializeGodot: command_line: is not null"); + new_cmdline = new String[command_line.length + 2]; + cll = command_line.length; + for (int i = 0; i < command_line.length; i++) { + new_cmdline[i] = command_line[i]; } } else { - Log.d("GODOT", "initializeGodot: command_line: is null" ); - new_cmdline = new String[ 2 ]; + Log.d("GODOT", "initializeGodot: command_line: is null"); + new_cmdline = new String[2]; } - new_cmdline[cll]="--main_pack"; - new_cmdline[cll+1]=expansion_pack_path; - command_line=new_cmdline; + new_cmdline[cll] = "--main_pack"; + new_cmdline[cll + 1] = expansion_pack_path; + command_line = new_cmdline; } io = new GodotIO(this); io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID); - GodotLib.io=io; - Log.d("GODOT", "command_line is null? " + ((command_line == null)?"yes":"no")); + GodotLib.io = io; + Log.d("GODOT", "command_line is null? " + ((command_line == null) ? "yes" : "no")); /*if(command_line != null){ Log.d("GODOT", "Command Line:"); for(int w=0;w <command_line.length;w++){ Log.d("GODOT"," " + command_line[w]); } }*/ - mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); + mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); mGravity = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); @@ -449,18 +434,15 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mPaymentsManager = PaymentsManager.createManager(this).initService(); - godot_initialized=true; - + godot_initialized = true; } @Override public void onServiceConnected(Messenger m) { - mRemoteService = DownloaderServiceMarshaller.CreateProxy(m); - mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger()); + mRemoteService = DownloaderServiceMarshaller.CreateProxy(m); + mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger()); } - - @Override protected void onCreate(Bundle icicle) { @@ -474,59 +456,58 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC //check for apk expansion API if (true) { - boolean md5mismatch = false; + boolean md5mismatch = false; command_line = getCommandLine(); - String main_pack_md5=null; - String main_pack_key=null; + String main_pack_md5 = null; + String main_pack_key = null; List<String> new_args = new LinkedList<String>(); + for (int i = 0; i < command_line.length; i++) { - for(int i=0;i<command_line.length;i++) { - - boolean has_extra = i< command_line.length -1; + boolean has_extra = i < command_line.length - 1; if (command_line[i].equals("--use_depth_32")) { - use_32_bits=true; + use_32_bits = true; } else if (command_line[i].equals("--use_immersive")) { - use_immersive=true; - if(Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+ + use_immersive = true; + if (Build.VERSION.SDK_INT >= 19.0) { // check if the application runs on an android 4.4+ window.getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar - | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | // hide nav bar + View.SYSTEM_UI_FLAG_FULLSCREEN | // hide status bar + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); UiChangeListener(); } } else if (command_line[i].equals("--use_apk_expansion")) { - use_apk_expansion=true; + use_apk_expansion = true; } else if (has_extra && command_line[i].equals("--apk_expansion_md5")) { - main_pack_md5=command_line[i+1]; + main_pack_md5 = command_line[i + 1]; i++; } else if (has_extra && command_line[i].equals("--apk_expansion_key")) { - main_pack_key=command_line[i+1]; + main_pack_key = command_line[i + 1]; SharedPreferences prefs = getSharedPreferences("app_data_keys", MODE_PRIVATE); Editor editor = prefs.edit(); editor.putString("store_public_key", main_pack_key); editor.commit(); i++; - } else if (command_line[i].trim().length()!=0){ + } else if (command_line[i].trim().length() != 0) { new_args.add(command_line[i]); } } - if (new_args.isEmpty()){ - command_line=null; - }else{ + if (new_args.isEmpty()) { + command_line = null; + } else { command_line = new_args.toArray(new String[new_args.size()]); - } - if (use_apk_expansion && main_pack_md5!=null && main_pack_key!=null) { + } + if (use_apk_expansion && main_pack_md5 != null && main_pack_key != null) { //check that environment is ok! - if (!Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED )) { + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { Log.d("GODOT", "**ERROR! No media mounted!"); //show popup and die } @@ -534,7 +515,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC // Build the full path to the app's expansion files try { expansion_pack_path = Helpers.getSaveFilePath(getApplicationContext()); - expansion_pack_path+="/"+"main."+getPackageManager().getPackageInfo(getPackageName(), 0).versionCode+"."+this.getPackageName()+".obb"; + expansion_pack_path += "/main." + getPackageManager().getPackageInfo(getPackageName(), 0).versionCode + "." + this.getPackageName() + ".obb"; } catch (Exception e) { e.printStackTrace(); } @@ -542,20 +523,20 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC File f = new File(expansion_pack_path); boolean pack_valid = true; - Log.d("GODOT","**PACK** - Path "+expansion_pack_path); + Log.d("GODOT", "**PACK** - Path " + expansion_pack_path); if (!f.exists()) { - pack_valid=false; - Log.d("GODOT","**PACK** - File does not exist"); + pack_valid = false; + Log.d("GODOT", "**PACK** - File does not exist"); - } else if( obbIsCorrupted(expansion_pack_path, main_pack_md5)){ + } else if (obbIsCorrupted(expansion_pack_path, main_pack_md5)) { Log.d("GODOT", "**PACK** - Expansion pack (obb) is corrupted"); pack_valid = false; - try{ - f.delete(); - }catch(Exception e){ - Log.d("GODOT", "**PACK** - Error deleting corrupted expansion pack (obb)"); + try { + f.delete(); + } catch (Exception e) { + Log.d("GODOT", "**PACK** - Error deleting corrupted expansion pack (obb)"); } } @@ -564,12 +545,12 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC Intent notifierIntent = new Intent(this, this.getClass()); notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | - Intent.FLAG_ACTIVITY_CLEAR_TOP); + Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, - notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, + notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT); - int startResult; + int startResult; try { Log.d("GODOT", "INITIALIZING DOWNLOAD"); startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired( @@ -578,36 +559,34 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC GodotDownloaderService.class); Log.d("GODOT", "DOWNLOAD SERVICE FINISHED:" + startResult); - if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { - Log.d("GODOT", "DOWNLOAD REQUIRED"); - // This is where you do set up to display the download - // progress (next step) - mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this, - GodotDownloaderService.class); - - setContentView(com.godot.game.R.layout.downloading_expansion); - mPB = (ProgressBar) findViewById(com.godot.game.R.id.progressBar); - mStatusText = (TextView) findViewById(com.godot.game.R.id.statusText); - mProgressFraction = (TextView) findViewById(com.godot.game.R.id.progressAsFraction); - mProgressPercent = (TextView) findViewById(com.godot.game.R.id.progressAsPercentage); - mAverageSpeed = (TextView) findViewById(com.godot.game.R.id.progressAverageSpeed); - mTimeRemaining = (TextView) findViewById(com.godot.game.R.id.progressTimeRemaining); - mDashboard = findViewById(com.godot.game.R.id.downloaderDashboard); - mCellMessage = findViewById(com.godot.game.R.id.approveCellular); - mPauseButton = (Button) findViewById(com.godot.game.R.id.pauseButton); - mWiFiSettingsButton = (Button) findViewById(com.godot.game.R.id.wifiSettingsButton); - - return; - } else{ - Log.d("GODOT", "NO DOWNLOAD REQUIRED"); - } + if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { + Log.d("GODOT", "DOWNLOAD REQUIRED"); + // This is where you do set up to display the download + // progress (next step) + mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this, + GodotDownloaderService.class); + + setContentView(com.godot.game.R.layout.downloading_expansion); + mPB = (ProgressBar)findViewById(com.godot.game.R.id.progressBar); + mStatusText = (TextView)findViewById(com.godot.game.R.id.statusText); + mProgressFraction = (TextView)findViewById(com.godot.game.R.id.progressAsFraction); + mProgressPercent = (TextView)findViewById(com.godot.game.R.id.progressAsPercentage); + mAverageSpeed = (TextView)findViewById(com.godot.game.R.id.progressAverageSpeed); + mTimeRemaining = (TextView)findViewById(com.godot.game.R.id.progressTimeRemaining); + mDashboard = findViewById(com.godot.game.R.id.downloaderDashboard); + mCellMessage = findViewById(com.godot.game.R.id.approveCellular); + mPauseButton = (Button)findViewById(com.godot.game.R.id.pauseButton); + mWiFiSettingsButton = (Button)findViewById(com.godot.game.R.id.wifiSettingsButton); + + return; + } else { + Log.d("GODOT", "NO DOWNLOAD REQUIRED"); + } } catch (NameNotFoundException e) { // TODO Auto-generated catch block Log.d("GODOT", "Error downloading expansion package:" + e.getMessage()); } - } - } } @@ -615,28 +594,26 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC initializeGodot(); - //instanceSingleton( new GodotFacebook(this) ); - - } + @Override + protected void onDestroy() { - @Override protected void onDestroy(){ - - if(mPaymentsManager != null ) mPaymentsManager.destroy(); - for(int i=0;i<singleton_count;i++) { + if (mPaymentsManager != null) mPaymentsManager.destroy(); + for (int i = 0; i < singleton_count; i++) { singletons[i].onMainDestroy(); } super.onDestroy(); } - @Override protected void onPause() { + @Override + protected void onPause() { super.onPause(); - if (!godot_initialized){ + if (!godot_initialized) { if (null != mDownloaderClientStub) { - mDownloaderClientStub.disconnect(this); - } + mDownloaderClientStub.disconnect(this); + } return; } mView.onPause(); @@ -648,17 +625,18 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC }); mSensorManager.unregisterListener(this); - for(int i=0;i<singleton_count;i++) { + for (int i = 0; i < singleton_count; i++) { singletons[i].onMainPause(); } } - @Override protected void onResume() { + @Override + protected void onResume() { super.onResume(); - if (!godot_initialized){ + if (!godot_initialized) { if (null != mDownloaderClientStub) { - mDownloaderClientStub.connect(this); - } + mDownloaderClientStub.connect(this); + } return; } @@ -674,59 +652,58 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME); - if(use_immersive && Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+ + if (use_immersive && Build.VERSION.SDK_INT >= 19.0) { // check if the application runs on an android 4.4+ Window window = getWindow(); window.getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar - | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | // hide nav bar + View.SYSTEM_UI_FLAG_FULLSCREEN | // hide status bar + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } - for(int i=0;i<singleton_count;i++) { + for (int i = 0; i < singleton_count; i++) { singletons[i].onMainResume(); } - - - } public void UiChangeListener() { final View decorView = getWindow().getDecorView(); - decorView.setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() { + decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { decorView.setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } } }); } - @Override public void onSensorChanged(SensorEvent event) { - Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay(); + @Override + public void onSensorChanged(SensorEvent event) { + Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay(); int displayRotation = display.getRotation(); float[] adjustedValues = new float[3]; final int axisSwap[][] = { - { 1, -1, 0, 1 }, // ROTATION_0 - {-1, -1, 1, 0 }, // ROTATION_90 - {-1, 1, 0, 1 }, // ROTATION_180 - { 1, 1, 1, 0 } }; // ROTATION_270 + { 1, -1, 0, 1 }, // ROTATION_0 + { -1, -1, 1, 0 }, // ROTATION_90 + { -1, 1, 0, 1 }, // ROTATION_180 + { 1, 1, 1, 0 } + }; // ROTATION_270 final int[] as = axisSwap[displayRotation]; - adjustedValues[0] = (float)as[0] * event.values[ as[2] ]; - adjustedValues[1] = (float)as[1] * event.values[ as[3] ]; - adjustedValues[2] = event.values[2]; + adjustedValues[0] = (float)as[0] * event.values[as[2]]; + adjustedValues[1] = (float)as[1] * event.values[as[3]]; + adjustedValues[2] = event.values[2]; final float x = adjustedValues[0]; final float y = adjustedValues[1]; @@ -738,27 +715,28 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC @Override public void run() { if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) { - GodotLib.accelerometer(-x,y,-z); + GodotLib.accelerometer(-x, y, -z); } if (typeOfSensor == Sensor.TYPE_GRAVITY) { - GodotLib.gravity(-x,y,-z); + GodotLib.gravity(-x, y, -z); } if (typeOfSensor == Sensor.TYPE_MAGNETIC_FIELD) { - GodotLib.magnetometer(-x,y,-z); + GodotLib.magnetometer(-x, y, -z); } if (typeOfSensor == Sensor.TYPE_GYROSCOPE) { - GodotLib.gyroscope(x,-y,z); + GodotLib.gyroscope(x, -y, z); } } }); } } - @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) { + @Override + public final void onAccuracyChanged(Sensor sensor, int accuracy) { // Do something here if sensor accuracy changes. } -/* + /* @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) { @@ -772,12 +750,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC return false; } -*/ + */ - @Override public void onBackPressed() { + @Override + public void onBackPressed() { boolean shouldQuit = true; - for(int i=0;i<singleton_count;i++) { + for (int i = 0; i < singleton_count; i++) { if (singletons[i].onMainBackPressed()) { shouldQuit = false; } @@ -799,71 +778,68 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC System.exit(0); } + private boolean obbIsCorrupted(String f, String main_pack_md5) { + try { - private boolean obbIsCorrupted(String f, String main_pack_md5){ - - try { - - InputStream fis = new FileInputStream(f); + InputStream fis = new FileInputStream(f); - // Create MD5 Hash - byte[] buffer = new byte[16384]; - - MessageDigest complete = MessageDigest.getInstance("MD5"); - int numRead; - do { - numRead = fis.read(buffer); - if (numRead > 0) { - complete.update(buffer, 0, numRead); - } - } while (numRead != -1); + // Create MD5 Hash + byte[] buffer = new byte[16384]; + MessageDigest complete = MessageDigest.getInstance("MD5"); + int numRead; + do { + numRead = fis.read(buffer); + if (numRead > 0) { + complete.update(buffer, 0, numRead); + } + } while (numRead != -1); - fis.close(); - byte[] messageDigest = complete.digest(); + fis.close(); + byte[] messageDigest = complete.digest(); - // Create Hex String - StringBuffer hexString = new StringBuffer(); - for (int i=0; i<messageDigest.length; i++) { - String s = Integer.toHexString(0xFF & messageDigest[i]); + // Create Hex String + StringBuffer hexString = new StringBuffer(); + for (int i = 0; i < messageDigest.length; i++) { + String s = Integer.toHexString(0xFF & messageDigest[i]); - if (s.length()==1) { - s="0"+s; - } - hexString.append(s); - } - String md5str = hexString.toString(); + if (s.length() == 1) { + s = "0" + s; + } + hexString.append(s); + } + String md5str = hexString.toString(); - //Log.d("GODOT","**PACK** - My MD5: "+hexString+" - APK md5: "+main_pack_md5); - if (!md5str.equals(main_pack_md5)) { - Log.d("GODOT","**PACK MD5 MISMATCH???** - MD5 Found: "+md5str+" "+Integer.toString(md5str.length())+" - MD5 Expected: "+main_pack_md5+" "+Integer.toString(main_pack_md5.length())); - return true; - } - return false; - } catch (Exception e) { - e.printStackTrace(); - Log.d("GODOT","**PACK FAIL**"); - return true; - } + //Log.d("GODOT","**PACK** - My MD5: "+hexString+" - APK md5: "+main_pack_md5); + if (!md5str.equals(main_pack_md5)) { + Log.d("GODOT", "**PACK MD5 MISMATCH???** - MD5 Found: " + md5str + " " + Integer.toString(md5str.length()) + " - MD5 Expected: " + main_pack_md5 + " " + Integer.toString(main_pack_md5.length())); + return true; + } + return false; + } catch (Exception e) { + e.printStackTrace(); + Log.d("GODOT", "**PACK FAIL**"); + return true; + } } //@Override public boolean dispatchTouchEvent (MotionEvent event) { public boolean gotTouchEvent(final MotionEvent event) { super.onTouchEvent(event); - final int evcount=event.getPointerCount(); - if (evcount==0) + final int evcount = event.getPointerCount(); + if (evcount == 0) return true; if (mView != null) { - final int[] arr = new int[event.getPointerCount()*3]; + final int[] arr = new int[event.getPointerCount() * 3]; - for(int i=0;i<event.getPointerCount();i++) { + for (int i = 0; i < event.getPointerCount(); i++) { - arr[i*3+0]=(int)event.getPointerId(i); - arr[i*3+1]=(int)event.getX(i); - arr[i*3+2]=(int)event.getY(i); + arr[i * 3 + 0] = (int)event.getPointerId(i); + arr[i * 3 + 1] = (int)event.getX(i); + arr[i * 3 + 2] = (int)event.getY(i); } //System.out.printf("gaction: %d\n",event.getAction()); @@ -871,13 +847,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mView.queueEvent(new Runnable() { @Override public void run() { - switch(action) { + switch (action) { case MotionEvent.ACTION_DOWN: { - GodotLib.touch(0,0,evcount,arr); + GodotLib.touch(0, 0, evcount, arr); //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY()); } break; case MotionEvent.ACTION_MOVE: { - GodotLib.touch(1,0,evcount,arr); + GodotLib.touch(1, 0, evcount, arr); /* for(int i=0;i<event.getPointerCount();i++) { System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i)); @@ -887,17 +863,17 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC case MotionEvent.ACTION_POINTER_UP: { final int indexPointUp = event.getActionIndex(); final int pointer_idx = event.getPointerId(indexPointUp); - GodotLib.touch(4,pointer_idx,evcount,arr); + GodotLib.touch(4, pointer_idx, evcount, arr); //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx)); } break; case MotionEvent.ACTION_POINTER_DOWN: { int pointer_idx = event.getActionIndex(); - GodotLib.touch(3,pointer_idx,evcount,arr); + GodotLib.touch(3, pointer_idx, evcount, arr); //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx)); } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { - GodotLib.touch(2,0,evcount,arr); + GodotLib.touch(2, 0, evcount, arr); /* for(int i=0;i<event.getPointerCount();i++) { System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i)); @@ -911,14 +887,16 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC return true; } - @Override public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) { + @Override + public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) { String s = event.getCharacters(); if (s == null || s.length() == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event); final char[] cc = s.toCharArray(); int cnt = 0; - for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0); + for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0) + ; if (cnt == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event); final Activity me = this; queueEvent(new Runnable() { @@ -939,7 +917,6 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC private void queueEvent(Runnable runnable) { // TODO Auto-generated method stub - } public PaymentsManager getPaymentsManager() { @@ -952,7 +929,6 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } */ - // Audio /** @@ -960,110 +936,106 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC * to show the state as being indeterminate at times. This sample can be * considered a guideline. */ - @Override - public void onDownloadStateChanged(int newState) { - Log.d("GODOT", "onDownloadStateChanged:" + newState); - setState(newState); - boolean showDashboard = true; - boolean showCellMessage = false; - boolean paused; - boolean indeterminate; - switch (newState) { - case IDownloaderClient.STATE_IDLE: - Log.d("GODOT", "DOWNLOAD STATE IDLE"); - // STATE_IDLE means the service is listening, so it's - // safe to start making calls via mRemoteService. - paused = false; - indeterminate = true; - break; - case IDownloaderClient.STATE_CONNECTING: - case IDownloaderClient.STATE_FETCHING_URL: - Log.d("GODOT", "DOWNLOAD STATE CONNECTION / FETCHING URL"); - showDashboard = true; - paused = false; - indeterminate = true; - break; - case IDownloaderClient.STATE_DOWNLOADING: - Log.d("GODOT", "DOWNLOAD STATE DOWNLOADING"); - paused = false; - showDashboard = true; - indeterminate = false; - break; - - case IDownloaderClient.STATE_FAILED_CANCELED: - case IDownloaderClient.STATE_FAILED: - case IDownloaderClient.STATE_FAILED_FETCHING_URL: - case IDownloaderClient.STATE_FAILED_UNLICENSED: - Log.d("GODOT", "DOWNLOAD STATE: FAILED, CANCELLED, UNLICENSED OR FAILED TO FETCH URL"); - paused = true; - showDashboard = false; - indeterminate = false; - break; - case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION: - case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION: - Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY MISSING CELLULAR PERMISSION"); - showDashboard = false; - paused = true; - indeterminate = false; - showCellMessage = true; - break; - - case IDownloaderClient.STATE_PAUSED_BY_REQUEST: - Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY USER"); - paused = true; - indeterminate = false; - break; - case IDownloaderClient.STATE_PAUSED_ROAMING: - case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE: - Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY ROAMING OR SDCARD UNAVAILABLE"); - paused = true; - indeterminate = false; - break; - case IDownloaderClient.STATE_COMPLETED: - Log.d("GODOT", "DOWNLOAD STATE: COMPLETED"); - showDashboard = false; - paused = false; - indeterminate = false; -// validateXAPKZipFiles(); - initializeGodot(); - return; - default: - Log.d("GODOT", "DOWNLOAD STATE: DEFAULT"); - paused = true; - indeterminate = true; - showDashboard = true; - } - int newDashboardVisibility = showDashboard ? View.VISIBLE : View.GONE; - if (mDashboard.getVisibility() != newDashboardVisibility) { - mDashboard.setVisibility(newDashboardVisibility); - } - int cellMessageVisibility = showCellMessage ? View.VISIBLE : View.GONE; - if (mCellMessage.getVisibility() != cellMessageVisibility) { - mCellMessage.setVisibility(cellMessageVisibility); - } - - mPB.setIndeterminate(indeterminate); - setButtonPausedState(paused); - } + @Override + public void onDownloadStateChanged(int newState) { + Log.d("GODOT", "onDownloadStateChanged:" + newState); + setState(newState); + boolean showDashboard = true; + boolean showCellMessage = false; + boolean paused; + boolean indeterminate; + switch (newState) { + case IDownloaderClient.STATE_IDLE: + Log.d("GODOT", "DOWNLOAD STATE IDLE"); + // STATE_IDLE means the service is listening, so it's + // safe to start making calls via mRemoteService. + paused = false; + indeterminate = true; + break; + case IDownloaderClient.STATE_CONNECTING: + case IDownloaderClient.STATE_FETCHING_URL: + Log.d("GODOT", "DOWNLOAD STATE CONNECTION / FETCHING URL"); + showDashboard = true; + paused = false; + indeterminate = true; + break; + case IDownloaderClient.STATE_DOWNLOADING: + Log.d("GODOT", "DOWNLOAD STATE DOWNLOADING"); + paused = false; + showDashboard = true; + indeterminate = false; + break; + + case IDownloaderClient.STATE_FAILED_CANCELED: + case IDownloaderClient.STATE_FAILED: + case IDownloaderClient.STATE_FAILED_FETCHING_URL: + case IDownloaderClient.STATE_FAILED_UNLICENSED: + Log.d("GODOT", "DOWNLOAD STATE: FAILED, CANCELLED, UNLICENSED OR FAILED TO FETCH URL"); + paused = true; + showDashboard = false; + indeterminate = false; + break; + case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION: + case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION: + Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY MISSING CELLULAR PERMISSION"); + showDashboard = false; + paused = true; + indeterminate = false; + showCellMessage = true; + break; + + case IDownloaderClient.STATE_PAUSED_BY_REQUEST: + Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY USER"); + paused = true; + indeterminate = false; + break; + case IDownloaderClient.STATE_PAUSED_ROAMING: + case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE: + Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY ROAMING OR SDCARD UNAVAILABLE"); + paused = true; + indeterminate = false; + break; + case IDownloaderClient.STATE_COMPLETED: + Log.d("GODOT", "DOWNLOAD STATE: COMPLETED"); + showDashboard = false; + paused = false; + indeterminate = false; + // validateXAPKZipFiles(); + initializeGodot(); + return; + default: + Log.d("GODOT", "DOWNLOAD STATE: DEFAULT"); + paused = true; + indeterminate = true; + showDashboard = true; + } + int newDashboardVisibility = showDashboard ? View.VISIBLE : View.GONE; + if (mDashboard.getVisibility() != newDashboardVisibility) { + mDashboard.setVisibility(newDashboardVisibility); + } + int cellMessageVisibility = showCellMessage ? View.VISIBLE : View.GONE; + if (mCellMessage.getVisibility() != cellMessageVisibility) { + mCellMessage.setVisibility(cellMessageVisibility); + } + mPB.setIndeterminate(indeterminate); + setButtonPausedState(paused); + } @Override public void onDownloadProgress(DownloadProgressInfo progress) { mAverageSpeed.setText(getString(com.godot.game.R.string.kilobytes_per_second, - Helpers.getSpeedString(progress.mCurrentSpeed))); - mTimeRemaining.setText(getString(com.godot.game.R.string.time_remaining, - Helpers.getTimeRemaining(progress.mTimeRemaining))); - - progress.mOverallTotal = progress.mOverallTotal; - mPB.setMax((int) (progress.mOverallTotal >> 8)); - mPB.setProgress((int) (progress.mOverallProgress >> 8)); - mProgressPercent.setText(Long.toString(progress.mOverallProgress - * 100 / - progress.mOverallTotal) + "%"); - mProgressFraction.setText(Helpers.getDownloadProgressString - (progress.mOverallProgress, - progress.mOverallTotal)); - + Helpers.getSpeedString(progress.mCurrentSpeed))); + mTimeRemaining.setText(getString(com.godot.game.R.string.time_remaining, + Helpers.getTimeRemaining(progress.mTimeRemaining))); + + progress.mOverallTotal = progress.mOverallTotal; + mPB.setMax((int)(progress.mOverallTotal >> 8)); + mPB.setProgress((int)(progress.mOverallProgress >> 8)); + mProgressPercent.setText(Long.toString(progress.mOverallProgress * 100 / + progress.mOverallTotal) + + "%"); + mProgressFraction.setText(Helpers.getDownloadProgressString(progress.mOverallProgress, + progress.mOverallTotal)); } - } diff --git a/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java b/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java index 2c668dd586..568c7a4140 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java +++ b/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java @@ -46,14 +46,14 @@ import android.util.Log; */ public class GodotDownloaderAlarmReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - Log.d("GODOT", "Alarma recivida"); - try { - DownloaderClientMarshaller.startDownloadServiceIfRequired(context, intent, GodotDownloaderService.class); - } catch (NameNotFoundException e) { - e.printStackTrace(); - Log.d("GODOT", "Exception: " + e.getClass().getName() + ":" + e.getMessage()); + @Override + public void onReceive(Context context, Intent intent) { + Log.d("GODOT", "Alarma recivida"); + try { + DownloaderClientMarshaller.startDownloadServiceIfRequired(context, intent, GodotDownloaderService.class); + } catch (NameNotFoundException e) { + e.printStackTrace(); + Log.d("GODOT", "Exception: " + e.getClass().getName() + ":" + e.getMessage()); + } } - } } diff --git a/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java b/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java index 97ba7826fb..b8b3b925c5 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java +++ b/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java @@ -40,46 +40,45 @@ import com.google.android.vending.expansion.downloader.impl.DownloaderService; * DownloaderService from the Downloader library. */ public class GodotDownloaderService extends DownloaderService { - // stuff for LVL -- MODIFY FOR YOUR APPLICATION! - private static final String BASE64_PUBLIC_KEY = "REPLACE THIS WITH YOUR PUBLIC KEY"; - // used by the preference obfuscater - private static final byte[] SALT = new byte[] { - 1, 43, -12, -1, 54, 98, - -100, -12, 43, 2, -8, -4, 9, 5, -106, -108, -33, 45, -1, 84 - }; + // stuff for LVL -- MODIFY FOR YOUR APPLICATION! + private static final String BASE64_PUBLIC_KEY = "REPLACE THIS WITH YOUR PUBLIC KEY"; + // used by the preference obfuscater + private static final byte[] SALT = new byte[] { + 1, 43, -12, -1, 54, 98, + -100, -12, 43, 2, -8, -4, 9, 5, -106, -108, -33, 45, -1, 84 + }; - /** + /** * This public key comes from your Android Market publisher account, and it * used by the LVL to validate responses from Market on your behalf. */ - @Override - public String getPublicKey() { - SharedPreferences prefs = getApplicationContext().getSharedPreferences("app_data_keys", Context.MODE_PRIVATE); - Log.d("GODOT", "getting public key:" + prefs.getString("store_public_key", null)); - return prefs.getString("store_public_key", null); - - //return BASE64_PUBLIC_KEY; - } + @Override + public String getPublicKey() { + SharedPreferences prefs = getApplicationContext().getSharedPreferences("app_data_keys", Context.MODE_PRIVATE); + Log.d("GODOT", "getting public key:" + prefs.getString("store_public_key", null)); + return prefs.getString("store_public_key", null); - /** + //return BASE64_PUBLIC_KEY; + } + + /** * This is used by the preference obfuscater to make sure that your * obfuscated preferences are different than the ones used by other * applications. */ - @Override - public byte[] getSALT() { - return SALT; - } + @Override + public byte[] getSALT() { + return SALT; + } - /** + /** * Fill this in with the class name for your alarm receiver. We do this * because receivers must be unique across all of Android (it's a good idea * to make sure that your receiver is in your unique package) */ - @Override - public String getAlarmReceiverClassName() { - Log.d("GODOT", "getAlarmReceiverClassName()"); - return GodotDownloaderAlarmReceiver.class.getName(); - } - + @Override + public String getAlarmReceiverClassName() { + Log.d("GODOT", "getAlarmReceiverClassName()"); + return GodotDownloaderAlarmReceiver.class.getName(); + } } diff --git a/platform/android/java/src/org/godotengine/godot/GodotIO.java b/platform/android/java/src/org/godotengine/godot/GodotIO.java index 989fd2b609..12a2467a29 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/src/org/godotengine/godot/GodotIO.java @@ -56,7 +56,6 @@ import org.godotengine.godot.input.*; public class GodotIO { - AssetManager am; Godot activity; GodotEditText edit; @@ -64,35 +63,32 @@ public class GodotIO { Context applicationContext; MediaPlayer mediaPlayer; - final int SCREEN_LANDSCAPE=0; - final int SCREEN_PORTRAIT=1; - final int SCREEN_REVERSE_LANDSCAPE=2; - final int SCREEN_REVERSE_PORTRAIT=3; - final int SCREEN_SENSOR_LANDSCAPE=4; - final int SCREEN_SENSOR_PORTRAIT=5; - final int SCREEN_SENSOR=6; + final int SCREEN_LANDSCAPE = 0; + final int SCREEN_PORTRAIT = 1; + final int SCREEN_REVERSE_LANDSCAPE = 2; + final int SCREEN_REVERSE_PORTRAIT = 3; + final int SCREEN_SENSOR_LANDSCAPE = 4; + final int SCREEN_SENSOR_PORTRAIT = 5; + final int SCREEN_SENSOR = 6; ///////////////////////// /// FILES ///////////////////////// - public int last_file_id=1; + public int last_file_id = 1; class AssetData { - - public boolean eof=false; + public boolean eof = false; public String path; public InputStream is; public int len; public int pos; } + HashMap<Integer, AssetData> streams; - HashMap<Integer,AssetData> streams; - - - public int file_open(String path,boolean write) { + public int file_open(String path, boolean write) { //System.out.printf("file_open: Attempt to Open %s\n",path); @@ -100,7 +96,6 @@ public class GodotIO { if (write) return -1; - AssetData ad = new AssetData(); try { @@ -113,76 +108,73 @@ public class GodotIO { } try { - ad.len=ad.is.available(); + ad.len = ad.is.available(); } catch (Exception e) { - System.out.printf("Exception availabling on file_open: %s\n",path); + System.out.printf("Exception availabling on file_open: %s\n", path); return -1; } - ad.path=path; - ad.pos=0; + ad.path = path; + ad.pos = 0; ++last_file_id; - streams.put(last_file_id,ad); + streams.put(last_file_id, ad); return last_file_id; } public int file_get_size(int id) { if (!streams.containsKey(id)) { - System.out.printf("file_get_size: Invalid file id: %d\n",id); + System.out.printf("file_get_size: Invalid file id: %d\n", id); return -1; } return streams.get(id).len; - } - public void file_seek(int id,int bytes) { + public void file_seek(int id, int bytes) { if (!streams.containsKey(id)) { - System.out.printf("file_get_size: Invalid file id: %d\n",id); + System.out.printf("file_get_size: Invalid file id: %d\n", id); return; } //seek sucks AssetData ad = streams.get(id); - if (bytes>ad.len) - bytes=ad.len; - if (bytes<0) - bytes=0; + if (bytes > ad.len) + bytes = ad.len; + if (bytes < 0) + bytes = 0; try { - if (bytes > (int)ad.pos) { - int todo=bytes-(int)ad.pos; - while(todo>0) { - todo-=ad.is.skip(todo); - } - ad.pos=bytes; - } else if (bytes<(int)ad.pos) { + if (bytes > (int)ad.pos) { + int todo = bytes - (int)ad.pos; + while (todo > 0) { + todo -= ad.is.skip(todo); + } + ad.pos = bytes; + } else if (bytes < (int)ad.pos) { - ad.is=am.open(ad.path); + ad.is = am.open(ad.path); - ad.pos=bytes; - int todo=bytes; - while(todo>0) { - todo-=ad.is.skip(todo); + ad.pos = bytes; + int todo = bytes; + while (todo > 0) { + todo -= ad.is.skip(todo); + } } - } - ad.eof=false; + ad.eof = false; } catch (IOException e) { - System.out.printf("Exception on file_seek: %s\n",e); + System.out.printf("Exception on file_seek: %s\n", e); return; } - - } public int file_tell(int id) { if (!streams.containsKey(id)) { - System.out.printf("file_read: Can't tell eof for invalid file id: %d\n",id); + System.out.printf("file_read: Can't tell eof for invalid file id: %d\n", id); return 0; } @@ -192,7 +184,7 @@ public class GodotIO { public boolean file_eof(int id) { if (!streams.containsKey(id)) { - System.out.printf("file_read: Can't check eof for invalid file id: %d\n",id); + System.out.printf("file_read: Can't check eof for invalid file id: %d\n", id); return false; } @@ -203,73 +195,65 @@ public class GodotIO { public byte[] file_read(int id, int bytes) { if (!streams.containsKey(id)) { - System.out.printf("file_read: Can't read invalid file id: %d\n",id); + System.out.printf("file_read: Can't read invalid file id: %d\n", id); return new byte[0]; } - AssetData ad = streams.get(id); if (ad.pos + bytes > ad.len) { - bytes=ad.len-ad.pos; - ad.eof=true; + bytes = ad.len - ad.pos; + ad.eof = true; } - - if (bytes==0) { + if (bytes == 0) { return new byte[0]; } - - - byte[] buf1=new byte[bytes]; - int r=0; + byte[] buf1 = new byte[bytes]; + int r = 0; try { r = ad.is.read(buf1); } catch (IOException e) { - System.out.printf("Exception on file_read: %s\n",e); + System.out.printf("Exception on file_read: %s\n", e); return new byte[bytes]; } - if (r==0) { + if (r == 0) { return new byte[0]; } - ad.pos+=r; + ad.pos += r; - if (r<bytes) { + if (r < bytes) { - byte[] buf2=new byte[r]; - for(int i=0;i<r;i++) - buf2[i]=buf1[i]; + byte[] buf2 = new byte[r]; + for (int i = 0; i < r; i++) + buf2[i] = buf1[i]; return buf2; } else { return buf1; } - } public void file_close(int id) { if (!streams.containsKey(id)) { - System.out.printf("file_close: Can't close invalid file id: %d\n",id); + System.out.printf("file_close: Can't close invalid file id: %d\n", id); return; } streams.remove(id); - } - ///////////////////////// /// DIRECTORIES ///////////////////////// - class AssetDir { public String[] files; @@ -277,49 +261,48 @@ public class GodotIO { public String path; } - public int last_dir_id=1; + public int last_dir_id = 1; - HashMap<Integer,AssetDir> dirs; + HashMap<Integer, AssetDir> dirs; public int dir_open(String path) { AssetDir ad = new AssetDir(); - ad.current=0; - ad.path=path; + ad.current = 0; + ad.path = path; try { ad.files = am.list(path); // no way to find path is directory or file exactly. // but if ad.files.length==0, then it's an empty directory or file. - if (ad.files.length==0) { + if (ad.files.length == 0) { return -1; } } catch (IOException e) { - System.out.printf("Exception on dir_open: %s\n",e); + System.out.printf("Exception on dir_open: %s\n", e); return -1; } //System.out.printf("Opened dir: %s\n",path); ++last_dir_id; - dirs.put(last_dir_id,ad); + dirs.put(last_dir_id, ad); return last_dir_id; - } public boolean dir_is_dir(int id) { if (!dirs.containsKey(id)) { - System.out.printf("dir_next: invalid dir id: %d\n",id); + System.out.printf("dir_next: invalid dir id: %d\n", id); return false; } AssetDir ad = dirs.get(id); //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length); int idx = ad.current; - if (idx>0) + if (idx > 0) idx--; - if (idx>=ad.files.length) + if (idx >= ad.files.length) return false; String fname = ad.files[idx]; @@ -327,7 +310,7 @@ public class GodotIO { if (ad.path.equals("")) am.open(fname); else - am.open(ad.path+"/"+fname); + am.open(ad.path + "/" + fname); return false; } catch (Exception e) { return true; @@ -337,46 +320,41 @@ public class GodotIO { public String dir_next(int id) { if (!dirs.containsKey(id)) { - System.out.printf("dir_next: invalid dir id: %d\n",id); + System.out.printf("dir_next: invalid dir id: %d\n", id); return ""; } AssetDir ad = dirs.get(id); //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length); - if (ad.current>=ad.files.length) { + if (ad.current >= ad.files.length) { ad.current++; return ""; } String r = ad.files[ad.current]; ad.current++; return r; - } public void dir_close(int id) { if (!dirs.containsKey(id)) { - System.out.printf("dir_close: invalid dir id: %d\n",id); + System.out.printf("dir_close: invalid dir id: %d\n", id); return; } dirs.remove(id); } - - GodotIO(Godot p_activity) { - am=p_activity.getAssets(); - activity=p_activity; - streams=new HashMap<Integer,AssetData>(); - dirs=new HashMap<Integer,AssetDir>(); + am = p_activity.getAssets(); + activity = p_activity; + streams = new HashMap<Integer, AssetData>(); + dirs = new HashMap<Integer, AssetDir>(); applicationContext = activity.getApplicationContext(); - } - ///////////////////////// // AUDIO ///////////////////////// @@ -400,7 +378,7 @@ public class GodotIO { desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, - channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM); + channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM); audioStartThread(); @@ -412,10 +390,10 @@ public class GodotIO { public void audioStartThread() { mAudioThread = new Thread(new Runnable() { - public void run() { - mAudioTrack.play(); - GodotLib.audio(); - } + public void run() { + mAudioTrack.play(); + GodotLib.audio(); + } }); // I'd take REALTIME if I could get it! @@ -424,15 +402,15 @@ public class GodotIO { } public void audioWriteShortBuffer(short[] buffer) { - for (int i = 0; i < buffer.length; ) { + for (int i = 0; i < buffer.length;) { int result = mAudioTrack.write(buffer, i, buffer.length - i); if (result > 0) { i += result; } else if (result == 0) { try { - Thread.sleep(1); - } catch(InterruptedException e) { - // Nom nom + Thread.sleep(1); + } catch (InterruptedException e) { + // Nom nom } } else { Log.w("Godot", "Godot audio: error return from write(short)"); @@ -441,18 +419,16 @@ public class GodotIO { } } - - public void audioQuit() { if (mAudioThread != null) { try { mAudioThread.join(); - } catch(Exception e) { + } catch (Exception e) { Log.v("Godot", "Problem stopping audio thread: " + e); } mAudioThread = null; - //Log.v("Godot", "Finished waiting for audio thread"); + //Log.v("Godot", "Finished waiting for audio thread"); } if (mAudioTrack != null) { @@ -473,20 +449,18 @@ public class GodotIO { // MISCELLANEOUS OS IO ///////////////////////// - - public int openURI(String p_uri) { try { Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri); String path = p_uri; - String type=""; + String type = ""; if (path.startsWith("/")) { //absolute path to filesystem, prepend file:// - path="file://"+path; + path = "file://" + path; if (p_uri.endsWith(".png") || p_uri.endsWith(".jpg") || p_uri.endsWith(".gif") || p_uri.endsWith(".webp")) { - type="image/*"; + type = "image/*"; } } @@ -531,7 +505,7 @@ public class GodotIO { } public void showKeyboard(String p_existing_text) { - if(edit != null) + if (edit != null) edit.showKeyboard(p_existing_text); //InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); @@ -539,21 +513,21 @@ public class GodotIO { }; public void hideKeyboard() { - if(edit != null) + if (edit != null) edit.hideKeyboard(); - InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); - View v = activity.getCurrentFocus(); - if (v != null) { - inputMgr.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); - } else { - inputMgr.hideSoftInputFromWindow(new View(activity).getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); - } + InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); + View v = activity.getCurrentFocus(); + if (v != null) { + inputMgr.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } else { + inputMgr.hideSoftInputFromWindow(new View(activity).getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } }; public void setScreenOrientation(int p_orientation) { - switch(p_orientation) { + switch (p_orientation) { case SCREEN_LANDSCAPE: { activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); @@ -576,16 +550,14 @@ public class GodotIO { case SCREEN_SENSOR: { activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); } break; - } }; - + public void setEdit(GodotEditText _edit) { edit = _edit; } - public void playVideo(String p_path) - { + public void playVideo(String p_path) { Uri filePath = Uri.parse(p_path); mediaPlayer = new MediaPlayer(); @@ -594,11 +566,9 @@ public class GodotIO { mediaPlayer.setDataSource(applicationContext, filePath); mediaPlayer.prepare(); mediaPlayer.start(); + } catch (IOException e) { + System.out.println("IOError while playing video"); } - catch(IOException e) - { - System.out.println("IOError while playing video"); - } } public boolean isVideoPlaying() { @@ -621,49 +591,47 @@ public class GodotIO { } } - - public static final int SYSTEM_DIR_DESKTOP=0; - public static final int SYSTEM_DIR_DCIM=1; - public static final int SYSTEM_DIR_DOCUMENTS=2; - public static final int SYSTEM_DIR_DOWNLOADS=3; - public static final int SYSTEM_DIR_MOVIES=4; - public static final int SYSTEM_DIR_MUSIC=5; - public static final int SYSTEM_DIR_PICTURES=6; - public static final int SYSTEM_DIR_RINGTONES=7; - + public static final int SYSTEM_DIR_DESKTOP = 0; + public static final int SYSTEM_DIR_DCIM = 1; + public static final int SYSTEM_DIR_DOCUMENTS = 2; + public static final int SYSTEM_DIR_DOWNLOADS = 3; + public static final int SYSTEM_DIR_MOVIES = 4; + public static final int SYSTEM_DIR_MUSIC = 5; + public static final int SYSTEM_DIR_PICTURES = 6; + public static final int SYSTEM_DIR_RINGTONES = 7; public String getSystemDir(int idx) { - String what=""; - switch(idx) { + String what = ""; + switch (idx) { case SYSTEM_DIR_DESKTOP: { //what=Environment.DIRECTORY_DOCUMENTS; - what=Environment.DIRECTORY_DOWNLOADS; + what = Environment.DIRECTORY_DOWNLOADS; } break; case SYSTEM_DIR_DCIM: { - what=Environment.DIRECTORY_DCIM; + what = Environment.DIRECTORY_DCIM; } break; case SYSTEM_DIR_DOCUMENTS: { - what=Environment.DIRECTORY_DOWNLOADS; + what = Environment.DIRECTORY_DOWNLOADS; //what=Environment.DIRECTORY_DOCUMENTS; } break; case SYSTEM_DIR_DOWNLOADS: { - what=Environment.DIRECTORY_DOWNLOADS; + what = Environment.DIRECTORY_DOWNLOADS; } break; case SYSTEM_DIR_MOVIES: { - what=Environment.DIRECTORY_MOVIES; + what = Environment.DIRECTORY_MOVIES; } break; case SYSTEM_DIR_MUSIC: { - what=Environment.DIRECTORY_MUSIC; + what = Environment.DIRECTORY_MUSIC; } break; case SYSTEM_DIR_PICTURES: { - what=Environment.DIRECTORY_PICTURES; + what = Environment.DIRECTORY_PICTURES; } break; case SYSTEM_DIR_RINGTONES: { - what=Environment.DIRECTORY_RINGTONES; + what = Environment.DIRECTORY_RINGTONES; } break; } @@ -676,10 +644,9 @@ public class GodotIO { protected static final String PREFS_FILE = "device_id.xml"; protected static final String PREFS_DEVICE_ID = "device_id"; - public static String unique_id=""; + public static String unique_id = ""; public String getUniqueID() { - return unique_id; + return unique_id; } - } diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java index 6b84ad6555..873d30eb34 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java @@ -33,43 +33,41 @@ package org.godotengine.godot; public class GodotLib { + public static GodotIO io; - public static GodotIO io; + static { + System.loadLibrary("godot_android"); + } - static { - System.loadLibrary("godot_android"); - } - - /** + /** * @param width the current view width * @param height the current view height */ - public static native void initialize(Godot p_instance,boolean need_reload_hook,Object p_asset_manager, boolean use_apk_expansion); - public static native void setup(String[] p_cmdline); - public static native void resize(int width, int height,boolean reload); - public static native void newcontext(boolean p_32_bits); - public static native void back(); - public static native void step(); - public static native void touch(int what,int pointer,int howmany, int[] arr); - public static native void accelerometer(float x, float y, float z); - public static native void gravity(float x, float y, float z); - public static native void magnetometer(float x, float y, float z); - public static native void gyroscope(float x, float y, float z); - public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed); - public static native void joybutton(int p_device, int p_but, boolean p_pressed); - public static native void joyaxis(int p_device, int p_axis, float p_value); - public static native void joyhat(int p_device, int p_hat_x, int p_hat_y); - public static native void joyconnectionchanged(int p_device, boolean p_connected, String p_name); - public static native void focusin(); - public static native void focusout(); - public static native void audio(); - public static native void singleton(String p_name,Object p_object); - public static native void method(String p_sname,String p_name,String p_ret,String[] p_params); - public static native String getGlobal(String p_key); + public static native void initialize(Godot p_instance, boolean need_reload_hook, Object p_asset_manager, boolean use_apk_expansion); + public static native void setup(String[] p_cmdline); + public static native void resize(int width, int height, boolean reload); + public static native void newcontext(boolean p_32_bits); + public static native void back(); + public static native void step(); + public static native void touch(int what, int pointer, int howmany, int[] arr); + public static native void accelerometer(float x, float y, float z); + public static native void gravity(float x, float y, float z); + public static native void magnetometer(float x, float y, float z); + public static native void gyroscope(float x, float y, float z); + public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed); + public static native void joybutton(int p_device, int p_but, boolean p_pressed); + public static native void joyaxis(int p_device, int p_axis, float p_value); + public static native void joyhat(int p_device, int p_hat_x, int p_hat_y); + public static native void joyconnectionchanged(int p_device, boolean p_connected, String p_name); + public static native void focusin(); + public static native void focusout(); + public static native void audio(); + public static native void singleton(String p_name, Object p_object); + public static native void method(String p_sname, String p_name, String p_ret, String[] p_params); + public static native String getGlobal(String p_key); public static native void callobject(int p_ID, String p_method, Object[] p_params); public static native void calldeferred(int p_ID, String p_method, Object[] p_params); public static native void setVirtualKeyboardHeight(int p_height); - } diff --git a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java index 8fe79fdfc7..61d10ed9e4 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java +++ b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java @@ -40,7 +40,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; - public class GodotPaymentV3 extends Godot.SingletonBase { private Godot activity; @@ -67,8 +66,8 @@ public class GodotPaymentV3 extends Godot.SingletonBase { public GodotPaymentV3(Activity p_activity) { - registerClass("GodotPayments", new String[]{"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume", "querySkuDetails"}); - activity = (Godot) p_activity; + registerClass("GodotPayments", new String[] { "purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume", "querySkuDetails" }); + activity = (Godot)p_activity; mPaymentManager = activity.getPaymentsManager(); mPaymentManager.setBaseSingleton(this); } @@ -89,32 +88,32 @@ public class GodotPaymentV3 extends Godot.SingletonBase { } public void callbackSuccess(String ticket, String signature, String sku) { - GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku}); + GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[] { ticket, signature, sku }); } public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku) { Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > " + ticket + "," + signature + "," + sku); - GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku}); + GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[] { ticket, signature, sku }); } public void callbackSuccessNoUnconsumedPurchases() { - GodotLib.calldeferred(purchaseCallbackId, "consume_not_required", new Object[]{}); + GodotLib.calldeferred(purchaseCallbackId, "consume_not_required", new Object[] {}); } public void callbackFailConsume() { - GodotLib.calldeferred(purchaseCallbackId, "consume_fail", new Object[]{}); + GodotLib.calldeferred(purchaseCallbackId, "consume_fail", new Object[] {}); } public void callbackFail() { - GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{}); + GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[] {}); } public void callbackCancel() { - GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[]{}); + GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[] {}); } public void callbackAlreadyOwned(String sku) { - GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[]{sku}); + GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[] { sku }); } public int getPurchaseCallbackId() { @@ -161,7 +160,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase { // callback for requestPurchased() public void callbackPurchased(String receipt, String signature, String sku) { - GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[]{receipt, signature, sku}); + GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[] { receipt, signature, sku }); } // consume item automatically after purchase. default is true. @@ -210,10 +209,10 @@ public class GodotPaymentV3 extends Godot.SingletonBase { } public void completeSkuDetail() { - GodotLib.calldeferred(purchaseCallbackId, "sku_details_complete", new Object[]{mSkuDetails}); + GodotLib.calldeferred(purchaseCallbackId, "sku_details_complete", new Object[] { mSkuDetails }); } public void errorSkuDetail(String errorMessage) { - GodotLib.calldeferred(purchaseCallbackId, "sku_details_error", new Object[]{errorMessage}); + GodotLib.calldeferred(purchaseCallbackId, "sku_details_error", new Object[] { errorMessage }); } } diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java index b807b952d4..b762aa021a 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/src/org/godotengine/godot/GodotView.java @@ -77,20 +77,19 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { private static Context ctx; private static GodotIO io; - private static boolean firsttime=true; - private static boolean use_gl3=false; - private static boolean use_32=false; + private static boolean firsttime = true; + private static boolean use_gl3 = false; + private static boolean use_32 = false; private Godot activity; - private InputManagerCompat mInputManager; - public GodotView(Context context,GodotIO p_io,boolean p_use_gl3, boolean p_use_32_bits, Godot p_activity) { + public GodotView(Context context, GodotIO p_io, boolean p_use_gl3, boolean p_use_32_bits, Godot p_activity) { super(context); - ctx=context; - io=p_io; - use_gl3=p_use_gl3; - use_32=p_use_32_bits; + ctx = context; + io = p_io; + use_gl3 = p_use_gl3; + use_32 = p_use_32_bits; activity = p_activity; @@ -101,14 +100,15 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { mInputManager = InputManagerCompat.Factory.getInputManager(this.getContext()); mInputManager.registerInputDeviceListener(this, null); init(false, 16, 0); - } + } - public GodotView(Context context, boolean translucent, int depth, int stencil) { + public GodotView(Context context, boolean translucent, int depth, int stencil) { super(context); init(translucent, depth, stencil); - } + } - @Override public boolean onTouchEvent (MotionEvent event) { + @Override + public boolean onTouchEvent(MotionEvent event) { return activity.gotTouchEvent(event); }; @@ -196,16 +196,17 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { ArrayList<joystick> joy_devices = new ArrayList<joystick>(); private int find_joy_device(int device_id) { - for (int i=0; i<joy_devices.size(); i++) { + for (int i = 0; i < joy_devices.size(); i++) { if (joy_devices.get(i).device_id == device_id) { - return i; + return i; } } onInputDeviceAdded(device_id); return joy_devices.size() - 1; } - @Override public void onInputDeviceAdded(int deviceId) { + @Override + public void onInputDeviceAdded(int deviceId) { joystick joy = new joystick(); joy.device_id = deviceId; final int id = joy_devices.size(); @@ -219,8 +220,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { for (InputDevice.MotionRange range : ranges) { if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) { joy.hats.add(range); - } - else { + } else { joy.axes.add(range); } } @@ -231,9 +231,10 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { GodotLib.joyconnectionchanged(id, true, name); } }); - } + } - @Override public void onInputDeviceRemoved(int deviceId) { + @Override + public void onInputDeviceRemoved(int deviceId) { final int id = find_joy_device(deviceId); joy_devices.remove(id); queueEvent(new Runnable() { @@ -244,10 +245,11 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { }); } - @Override public void onInputDeviceChanged(int deviceId) { - + @Override + public void onInputDeviceChanged(int deviceId) { } - @Override public boolean onKeyUp(final int keyCode, KeyEvent event) { + @Override + public boolean onKeyUp(final int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { return true; @@ -282,7 +284,8 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { return super.onKeyUp(keyCode, event); }; - @Override public boolean onKeyDown(final int keyCode, KeyEvent event) { + @Override + public boolean onKeyDown(final int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { activity.onBackPressed(); @@ -326,7 +329,8 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { return super.onKeyDown(keyCode, event); } - @Override public boolean onGenericMotionEvent(MotionEvent event) { + @Override + public boolean onGenericMotionEvent(MotionEvent event) { if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) { @@ -335,7 +339,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { for (int i = 0; i < joy.axes.size(); i++) { InputDevice.MotionRange range = joy.axes.get(i); - final float value = (event.getAxisValue(range.getAxis()) - range.getMin() ) / range.getRange() * 2.0f - 1.0f; + final float value = (event.getAxisValue(range.getAxis()) - range.getMin()) / range.getRange() * 2.0f - 1.0f; //Log.e(TAG, String.format("axis event: %d, value %f", i, value)); final int idx = i; queueEvent(new Runnable() { @@ -346,9 +350,9 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { }); } - for (int i = 0; i < joy.hats.size(); i+=2) { + for (int i = 0; i < joy.hats.size(); i += 2) { final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis())); - final int hatY = Math.round(event.getAxisValue(joy.hats.get(i+1).getAxis())); + final int hatY = Math.round(event.getAxisValue(joy.hats.get(i + 1).getAxis())); //Log.e(TAG, String.format("HAT EVENT %d, %d", hatX, hatY)); queueEvent(new Runnable() { @Override @@ -363,8 +367,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { return super.onGenericMotionEvent(event); }; - - private void init(boolean translucent, int depth, int stencil) { + private void init(boolean translucent, int depth, int stencil) { this.setFocusableInTouchMode(true); /* By default, GLSurfaceView() creates a RGB_565 opaque surface. @@ -388,14 +391,14 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { */ if (use_32) { - setEGLConfigChooser( translucent ? - new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(8, 8, 8, 8, 16, stencil)) : - new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(5, 6, 5, 0, 16, stencil)) ); + setEGLConfigChooser(translucent ? + new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(8, 8, 8, 8, 16, stencil)) : + new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(5, 6, 5, 0, 16, stencil))); } else { - setEGLConfigChooser( translucent ? - new ConfigChooser(8, 8, 8, 8, 16, stencil) : - new ConfigChooser(5, 6, 5, 0, 16, stencil) ); + setEGLConfigChooser(translucent ? + new ConfigChooser(8, 8, 8, 8, 16, stencil) : + new ConfigChooser(5, 6, 5, 0, 16, stencil)); } /* Set the renderer responsible for frame rendering */ @@ -403,33 +406,33 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { } private static class ContextFactory implements GLSurfaceView.EGLContextFactory { - private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { - if (use_gl3) - Log.w(TAG, "creating OpenGL ES 3.0 context :"); - else - Log.w(TAG, "creating OpenGL ES 2.0 context :"); - - checkEglError("Before eglCreateContext", egl); - int[] attrib_list2 = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; - int[] attrib_list3 = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; - EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl3?attrib_list3:attrib_list2); - checkEglError("After eglCreateContext", egl); - return context; - } + private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { + if (use_gl3) + Log.w(TAG, "creating OpenGL ES 3.0 context :"); + else + Log.w(TAG, "creating OpenGL ES 2.0 context :"); + + checkEglError("Before eglCreateContext", egl); + int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; + int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; + EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl3 ? attrib_list3 : attrib_list2); + checkEglError("After eglCreateContext", egl); + return context; + } - public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { - egl.eglDestroyContext(display, context); + public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { + egl.eglDestroyContext(display, context); + } } - } - private static void checkEglError(String prompt, EGL10 egl) { - int error; - while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { - Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); + private static void checkEglError(String prompt, EGL10 egl) { + int error; + while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { + Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); + } } - } - /* Fallback if 32bit View is not supported*/ + /* Fallback if 32bit View is not supported*/ private static class FallbackConfigChooser extends ConfigChooser { private ConfigChooser fallback; @@ -438,17 +441,17 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { this.fallback = fallback; } - @Override + @Override public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { EGLConfig ec = super.chooseConfig(egl, display, configs); if (ec == null) { - Log.w(TAG, "Trying ConfigChooser fallback"); - ec = fallback.chooseConfig(egl, display, configs); - use_32=false; + Log.w(TAG, "Trying ConfigChooser fallback"); + ec = fallback.chooseConfig(egl, display, configs); + use_32 = false; } return ec; - } - } + } + } private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { @@ -467,46 +470,46 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { */ private static int EGL_OPENGL_ES2_BIT = 4; private static int[] s_configAttribs2 = - { - EGL10.EGL_RED_SIZE, 4, - EGL10.EGL_GREEN_SIZE, 4, - EGL10.EGL_BLUE_SIZE, 4, - // EGL10.EGL_DEPTH_SIZE, 16, - // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL10.EGL_NONE - }; + { + EGL10.EGL_RED_SIZE, 4, + EGL10.EGL_GREEN_SIZE, 4, + EGL10.EGL_BLUE_SIZE, 4, + // EGL10.EGL_DEPTH_SIZE, 16, + // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_NONE + }; private static int[] s_configAttribs3 = - { - EGL10.EGL_RED_SIZE, 4, - EGL10.EGL_GREEN_SIZE, 4, - EGL10.EGL_BLUE_SIZE, 4, - // EGL10.EGL_DEPTH_SIZE, 16, - // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //apparently there is no EGL_OPENGL_ES3_BIT - EGL10.EGL_NONE - }; + { + EGL10.EGL_RED_SIZE, 4, + EGL10.EGL_GREEN_SIZE, 4, + EGL10.EGL_BLUE_SIZE, 4, + // EGL10.EGL_DEPTH_SIZE, 16, + // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //apparently there is no EGL_OPENGL_ES3_BIT + EGL10.EGL_NONE + }; public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { /* Get the number of minimally matching EGL configurations */ int[] num_config = new int[1]; - egl.eglChooseConfig(display, use_gl3?s_configAttribs3:s_configAttribs2, null, 0, num_config); + egl.eglChooseConfig(display, use_gl3 ? s_configAttribs3 : s_configAttribs2, null, 0, num_config); int numConfigs = num_config[0]; if (numConfigs <= 0) { - throw new IllegalArgumentException("No configs match configSpec"); + throw new IllegalArgumentException("No configs match configSpec"); } /* Allocate then read the array of minimally matching EGL configs */ EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, use_gl3?s_configAttribs3:s_configAttribs2, configs, numConfigs, num_config); + egl.eglChooseConfig(display, use_gl3 ? s_configAttribs3 : s_configAttribs2, configs, numConfigs, num_config); if (DEBUG) { - printConfigs(egl, display, configs); + printConfigs(egl, display, configs); } /* Now return the "best" one */ @@ -514,54 +517,54 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { } public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, - EGLConfig[] configs) { - for(EGLConfig config : configs) { - int d = findConfigAttrib(egl, display, config, - EGL10.EGL_DEPTH_SIZE, 0); - int s = findConfigAttrib(egl, display, config, - EGL10.EGL_STENCIL_SIZE, 0); - - // We need at least mDepthSize and mStencilSize bits - if (d < mDepthSize || s < mStencilSize) - continue; - - // We want an *exact* match for red/green/blue/alpha - int r = findConfigAttrib(egl, display, config, - EGL10.EGL_RED_SIZE, 0); - int g = findConfigAttrib(egl, display, config, - EGL10.EGL_GREEN_SIZE, 0); - int b = findConfigAttrib(egl, display, config, - EGL10.EGL_BLUE_SIZE, 0); - int a = findConfigAttrib(egl, display, config, - EGL10.EGL_ALPHA_SIZE, 0); - - if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) - return config; + EGLConfig[] configs) { + for (EGLConfig config : configs) { + int d = findConfigAttrib(egl, display, config, + EGL10.EGL_DEPTH_SIZE, 0); + int s = findConfigAttrib(egl, display, config, + EGL10.EGL_STENCIL_SIZE, 0); + + // We need at least mDepthSize and mStencilSize bits + if (d < mDepthSize || s < mStencilSize) + continue; + + // We want an *exact* match for red/green/blue/alpha + int r = findConfigAttrib(egl, display, config, + EGL10.EGL_RED_SIZE, 0); + int g = findConfigAttrib(egl, display, config, + EGL10.EGL_GREEN_SIZE, 0); + int b = findConfigAttrib(egl, display, config, + EGL10.EGL_BLUE_SIZE, 0); + int a = findConfigAttrib(egl, display, config, + EGL10.EGL_ALPHA_SIZE, 0); + + if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) + return config; } return null; } private int findConfigAttrib(EGL10 egl, EGLDisplay display, - EGLConfig config, int attribute, int defaultValue) { + EGLConfig config, int attribute, int defaultValue) { if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { - return mValue[0]; + return mValue[0]; } return defaultValue; } private void printConfigs(EGL10 egl, EGLDisplay display, - EGLConfig[] configs) { + EGLConfig[] configs) { int numConfigs = configs.length; Log.w(TAG, String.format("%d configurations", numConfigs)); for (int i = 0; i < numConfigs; i++) { - Log.w(TAG, String.format("Configuration %d:\n", i)); - printConfig(egl, display, configs[i]); + Log.w(TAG, String.format("Configuration %d:\n", i)); + printConfig(egl, display, configs[i]); } } private void printConfig(EGL10 egl, EGLDisplay display, - EGLConfig config) { + EGLConfig config) { int[] attributes = { EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE, @@ -634,14 +637,15 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { }; int[] value = new int[1]; for (int i = 0; i < attributes.length; i++) { - int attribute = attributes[i]; - String name = names[i]; - if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { - Log.w(TAG, String.format(" %s: %d\n", name, value[0])); - } else { - // Log.w(TAG, String.format(" %s: failed\n", name)); - while (egl.eglGetError() != EGL10.EGL_SUCCESS); - } + int attribute = attributes[i]; + String name = names[i]; + if (egl.eglGetConfigAttrib(display, config, attribute, value)) { + Log.w(TAG, String.format(" %s: %d\n", name, value[0])); + } else { + // Log.w(TAG, String.format(" %s: failed\n", name)); + while (egl.eglGetError() != EGL10.EGL_SUCCESS) + ; + } } } @@ -657,19 +661,18 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { private static class Renderer implements GLSurfaceView.Renderer { - public void onDrawFrame(GL10 gl) { GodotLib.step(); - for(int i=0;i<Godot.singleton_count;i++) { + for (int i = 0; i < Godot.singleton_count; i++) { Godot.singletons[i].onGLDrawFrame(gl); } } public void onSurfaceChanged(GL10 gl, int width, int height) { - GodotLib.resize(width, height,!firsttime); - firsttime=false; - for(int i=0;i<Godot.singleton_count;i++) { + GodotLib.resize(width, height, !firsttime); + firsttime = false; + for (int i = 0; i < Godot.singleton_count; i++) { Godot.singletons[i].onGLSurfaceChanged(gl, width, height); } } diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java index d8a3ac5591..9e062d89c6 100644 --- a/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java +++ b/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java @@ -70,42 +70,37 @@ public class GodotEditText extends EditText { super(context, attrs, defStyle); this.initView(); } - + protected void initView() { - this.setPadding(0, 0, 0, 0); + this.setPadding(0, 0, 0, 0); this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); - + sHandler = new Handler() { @Override public void handleMessage(final Message msg) { switch (msg.what) { - case HANDLER_OPEN_IME_KEYBOARD: - { - GodotEditText edit = (GodotEditText) msg.obj; - String text = edit.mOriginText; - if (edit.requestFocus()) - { - edit.removeTextChangedListener(edit.mInputWrapper); - edit.setText(""); - edit.append(text); - edit.mInputWrapper.setOriginText(text); - edit.addTextChangedListener(edit.mInputWrapper); - final InputMethodManager imm = (InputMethodManager) mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(edit, 0); - } + case HANDLER_OPEN_IME_KEYBOARD: { + GodotEditText edit = (GodotEditText)msg.obj; + String text = edit.mOriginText; + if (edit.requestFocus()) { + edit.removeTextChangedListener(edit.mInputWrapper); + edit.setText(""); + edit.append(text); + edit.mInputWrapper.setOriginText(text); + edit.addTextChangedListener(edit.mInputWrapper); + final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(edit, 0); } - break; - - case HANDLER_CLOSE_IME_KEYBOARD: - { - GodotEditText edit = (GodotEditText) msg.obj; - - edit.removeTextChangedListener(mInputWrapper); - final InputMethodManager imm = (InputMethodManager) mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(edit.getWindowToken(), 0); - edit.mView.requestFocus(); - } - break; + } break; + + case HANDLER_CLOSE_IME_KEYBOARD: { + GodotEditText edit = (GodotEditText)msg.obj; + + edit.removeTextChangedListener(mInputWrapper); + final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(edit.getWindowToken(), 0); + edit.mView.requestFocus(); + } break; } } }; @@ -116,7 +111,7 @@ public class GodotEditText extends EditText { // =========================================================== public void setView(final GodotView view) { this.mView = view; - if(mInputWrapper == null) + if (mInputWrapper == null) mInputWrapper = new GodotTextInputWrapper(mView, this); this.setOnEditorActionListener(mInputWrapper); view.requestFocus(); @@ -125,7 +120,7 @@ public class GodotEditText extends EditText { // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== - @Override + @Override public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) { super.onKeyDown(keyCode, keyEvent); @@ -142,7 +137,7 @@ public class GodotEditText extends EditText { // =========================================================== public void showKeyboard(String p_existing_text) { this.mOriginText = p_existing_text; - + final Message msg = new Message(); msg.what = HANDLER_OPEN_IME_KEYBOARD; msg.obj = this; @@ -155,7 +150,7 @@ public class GodotEditText extends EditText { msg.obj = this; sHandler.sendMessage(msg); } - + // =========================================================== // Inner and Anonymous Classes // =========================================================== diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java index ac424ab9f8..8e34d9e9e7 100644 --- a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -67,7 +67,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene private boolean isFullScreenEdit() { final TextView textField = this.mEdit; - final InputMethodManager imm = (InputMethodManager) textField.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + final InputMethodManager imm = (InputMethodManager)textField.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); return imm.isFullscreenMode(); } @@ -81,7 +81,6 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene @Override public void afterTextChanged(final Editable s) { - } @Override diff --git a/platform/android/java/src/org/godotengine/godot/input/InputManagerCompat.java b/platform/android/java/src/org/godotengine/godot/input/InputManagerCompat.java index 4615d2fbb5..0a876d2b7f 100644 --- a/platform/android/java/src/org/godotengine/godot/input/InputManagerCompat.java +++ b/platform/android/java/src/org/godotengine/godot/input/InputManagerCompat.java @@ -23,118 +23,118 @@ import android.view.InputDevice; import android.view.MotionEvent; public interface InputManagerCompat { - /** - * Gets information about the input device with the specified id. - * - * @param id The device id - * @return The input device or null if not found - */ - public InputDevice getInputDevice(int id); + /** + * Gets information about the input device with the specified id. + * + * @param id The device id + * @return The input device or null if not found + */ + public InputDevice getInputDevice(int id); - /** - * Gets the ids of all input devices in the system. - * - * @return The input device ids. - */ - public int[] getInputDeviceIds(); + /** + * Gets the ids of all input devices in the system. + * + * @return The input device ids. + */ + public int[] getInputDeviceIds(); - /** - * Registers an input device listener to receive notifications about when - * input devices are added, removed or changed. - * - * @param listener The listener to register. - * @param handler The handler on which the listener should be invoked, or - * null if the listener should be invoked on the calling thread's - * looper. - */ - public void registerInputDeviceListener(InputManagerCompat.InputDeviceListener listener, - Handler handler); + /** + * Registers an input device listener to receive notifications about when + * input devices are added, removed or changed. + * + * @param listener The listener to register. + * @param handler The handler on which the listener should be invoked, or + * null if the listener should be invoked on the calling thread's + * looper. + */ + public void registerInputDeviceListener(InputManagerCompat.InputDeviceListener listener, + Handler handler); - /** - * Unregisters an input device listener. - * - * @param listener The listener to unregister. - */ - public void unregisterInputDeviceListener(InputManagerCompat.InputDeviceListener listener); + /** + * Unregisters an input device listener. + * + * @param listener The listener to unregister. + */ + public void unregisterInputDeviceListener(InputManagerCompat.InputDeviceListener listener); - /* - * The following three calls are to simulate V16 behavior on pre-Jellybean - * devices. If you don't call them, your callback will never be called - * pre-API 16. - */ + /* + * The following three calls are to simulate V16 behavior on pre-Jellybean + * devices. If you don't call them, your callback will never be called + * pre-API 16. + */ - /** - * Pass the motion events to the InputManagerCompat. This is used to - * optimize for polling for controllers. If you do not pass these events in, - * polling will cause regular object creation. - * - * @param event the motion event from the app - */ - public void onGenericMotionEvent(MotionEvent event); + /** + * Pass the motion events to the InputManagerCompat. This is used to + * optimize for polling for controllers. If you do not pass these events in, + * polling will cause regular object creation. + * + * @param event the motion event from the app + */ + public void onGenericMotionEvent(MotionEvent event); - /** - * Tell the V9 input manager that it should stop polling for disconnected - * devices. You can call this during onPause in your activity, although you - * might want to call it whenever your game is not active (or whenever you - * don't care about being notified of new input devices) - */ - public void onPause(); + /** + * Tell the V9 input manager that it should stop polling for disconnected + * devices. You can call this during onPause in your activity, although you + * might want to call it whenever your game is not active (or whenever you + * don't care about being notified of new input devices) + */ + public void onPause(); - /** - * Tell the V9 input manager that it should start polling for disconnected - * devices. You can call this during onResume in your activity, although you - * might want to call it less often (only when the gameplay is actually - * active) - */ - public void onResume(); + /** + * Tell the V9 input manager that it should start polling for disconnected + * devices. You can call this during onResume in your activity, although you + * might want to call it less often (only when the gameplay is actually + * active) + */ + public void onResume(); - public interface InputDeviceListener { - /** - * Called whenever the input manager detects that a device has been - * added. This will only be called in the V9 version when a motion event - * is detected. - * - * @param deviceId The id of the input device that was added. - */ - void onInputDeviceAdded(int deviceId); + public interface InputDeviceListener { + /** + * Called whenever the input manager detects that a device has been + * added. This will only be called in the V9 version when a motion event + * is detected. + * + * @param deviceId The id of the input device that was added. + */ + void onInputDeviceAdded(int deviceId); - /** - * Called whenever the properties of an input device have changed since - * they were last queried. This will not be called for the V9 version of - * the API. - * - * @param deviceId The id of the input device that changed. - */ - void onInputDeviceChanged(int deviceId); + /** + * Called whenever the properties of an input device have changed since + * they were last queried. This will not be called for the V9 version of + * the API. + * + * @param deviceId The id of the input device that changed. + */ + void onInputDeviceChanged(int deviceId); - /** - * Called whenever the input manager detects that a device has been - * removed. For the V9 version, this can take some time depending on the - * poll rate. - * - * @param deviceId The id of the input device that was removed. - */ - void onInputDeviceRemoved(int deviceId); - } + /** + * Called whenever the input manager detects that a device has been + * removed. For the V9 version, this can take some time depending on the + * poll rate. + * + * @param deviceId The id of the input device that was removed. + */ + void onInputDeviceRemoved(int deviceId); + } - /** - * Use this to construct a compatible InputManager. - */ - public static class Factory { + /** + * Use this to construct a compatible InputManager. + */ + public static class Factory { - /** - * Constructs and returns a compatible InputManger - * - * @param context the Context that will be used to get the system - * service from - * @return a compatible implementation of InputManager - */ - public static InputManagerCompat getInputManager(Context context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - return new InputManagerV16(context); - } else { - return new InputManagerV9(); - } - } - } + /** + * Constructs and returns a compatible InputManger + * + * @param context the Context that will be used to get the system + * service from + * @return a compatible implementation of InputManager + */ + public static InputManagerCompat getInputManager(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + return new InputManagerV16(context); + } else { + return new InputManagerV9(); + } + } + } } diff --git a/platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java b/platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java index f05701f455..3b88609cc9 100644 --- a/platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java +++ b/platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java @@ -30,78 +30,74 @@ import java.util.Map; @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public class InputManagerV16 implements InputManagerCompat { - private final InputManager mInputManager; - private final Map<InputManagerCompat.InputDeviceListener, V16InputDeviceListener> mListeners; - - public InputManagerV16(Context context) { - mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); - mListeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>(); - } - - @Override - public InputDevice getInputDevice(int id) { - return mInputManager.getInputDevice(id); - } - - @Override - public int[] getInputDeviceIds() { - return mInputManager.getInputDeviceIds(); - } - - static class V16InputDeviceListener implements InputManager.InputDeviceListener { - final InputManagerCompat.InputDeviceListener mIDL; - - public V16InputDeviceListener(InputDeviceListener idl) { - mIDL = idl; - } - - @Override - public void onInputDeviceAdded(int deviceId) { - mIDL.onInputDeviceAdded(deviceId); - } - - @Override - public void onInputDeviceChanged(int deviceId) { - mIDL.onInputDeviceChanged(deviceId); - } - - @Override - public void onInputDeviceRemoved(int deviceId) { - mIDL.onInputDeviceRemoved(deviceId); - } - - } - - @Override - public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { - V16InputDeviceListener v16Listener = new V16InputDeviceListener(listener); - mInputManager.registerInputDeviceListener(v16Listener, handler); - mListeners.put(listener, v16Listener); - } - - @Override - public void unregisterInputDeviceListener(InputDeviceListener listener) { - V16InputDeviceListener curListener = mListeners.remove(listener); - if (null != curListener) - { - mInputManager.unregisterInputDeviceListener(curListener); - } - - } - - @Override - public void onGenericMotionEvent(MotionEvent event) { - // unused in V16 - } - - @Override - public void onPause() { - // unused in V16 - } - - @Override - public void onResume() { - // unused in V16 - } - + private final InputManager mInputManager; + private final Map<InputManagerCompat.InputDeviceListener, V16InputDeviceListener> mListeners; + + public InputManagerV16(Context context) { + mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE); + mListeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>(); + } + + @Override + public InputDevice getInputDevice(int id) { + return mInputManager.getInputDevice(id); + } + + @Override + public int[] getInputDeviceIds() { + return mInputManager.getInputDeviceIds(); + } + + static class V16InputDeviceListener implements InputManager.InputDeviceListener { + final InputManagerCompat.InputDeviceListener mIDL; + + public V16InputDeviceListener(InputDeviceListener idl) { + mIDL = idl; + } + + @Override + public void onInputDeviceAdded(int deviceId) { + mIDL.onInputDeviceAdded(deviceId); + } + + @Override + public void onInputDeviceChanged(int deviceId) { + mIDL.onInputDeviceChanged(deviceId); + } + + @Override + public void onInputDeviceRemoved(int deviceId) { + mIDL.onInputDeviceRemoved(deviceId); + } + } + + @Override + public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { + V16InputDeviceListener v16Listener = new V16InputDeviceListener(listener); + mInputManager.registerInputDeviceListener(v16Listener, handler); + mListeners.put(listener, v16Listener); + } + + @Override + public void unregisterInputDeviceListener(InputDeviceListener listener) { + V16InputDeviceListener curListener = mListeners.remove(listener); + if (null != curListener) { + mInputManager.unregisterInputDeviceListener(curListener); + } + } + + @Override + public void onGenericMotionEvent(MotionEvent event) { + // unused in V16 + } + + @Override + public void onPause() { + // unused in V16 + } + + @Override + public void onResume() { + // unused in V16 + } } diff --git a/platform/android/java/src/org/godotengine/godot/input/InputManagerV9.java b/platform/android/java/src/org/godotengine/godot/input/InputManagerV9.java index 0334c00997..a1418c5899 100644 --- a/platform/android/java/src/org/godotengine/godot/input/InputManagerV9.java +++ b/platform/android/java/src/org/godotengine/godot/input/InputManagerV9.java @@ -31,181 +31,179 @@ import java.util.Map; import java.util.Queue; public class InputManagerV9 implements InputManagerCompat { - private static final String LOG_TAG = "InputManagerV9"; - private static final int MESSAGE_TEST_FOR_DISCONNECT = 101; - private static final long CHECK_ELAPSED_TIME = 3000L; - - private static final int ON_DEVICE_ADDED = 0; - private static final int ON_DEVICE_CHANGED = 1; - private static final int ON_DEVICE_REMOVED = 2; - - private final SparseArray<long[]> mDevices; - private final Map<InputDeviceListener, Handler> mListeners; - private final Handler mDefaultHandler; - - private static class PollingMessageHandler extends Handler { - private final WeakReference<InputManagerV9> mInputManager; - - PollingMessageHandler(InputManagerV9 im) { - mInputManager = new WeakReference<InputManagerV9>(im); - } - - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - switch (msg.what) { - case MESSAGE_TEST_FOR_DISCONNECT: - InputManagerV9 imv = mInputManager.get(); - if (null != imv) { - long time = SystemClock.elapsedRealtime(); - int size = imv.mDevices.size(); - for (int i = 0; i < size; i++) { - long[] lastContact = imv.mDevices.valueAt(i); - if (null != lastContact) { - if (time - lastContact[0] > CHECK_ELAPSED_TIME) { - // check to see if the device has been - // disconnected - int id = imv.mDevices.keyAt(i); - if (null == InputDevice.getDevice(id)) { - // disconnected! - imv.notifyListeners(ON_DEVICE_REMOVED, id); - imv.mDevices.remove(id); - } else { - lastContact[0] = time; - } - } - } - } - sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, - CHECK_ELAPSED_TIME); - } - break; - } - } - - } - - public InputManagerV9() { - mDevices = new SparseArray<long[]>(); - mListeners = new HashMap<InputDeviceListener, Handler>(); - mDefaultHandler = new PollingMessageHandler(this); - // as a side-effect, populates our collection of watched - // input devices - getInputDeviceIds(); - } - - @Override - public InputDevice getInputDevice(int id) { - return InputDevice.getDevice(id); - } - - @Override - public int[] getInputDeviceIds() { - // add any hitherto unknown devices to our - // collection of watched input devices - int[] activeDevices = InputDevice.getDeviceIds(); - long time = SystemClock.elapsedRealtime(); - for ( int id : activeDevices ) { - long[] lastContact = mDevices.get(id); - if ( null == lastContact ) { - // we have a new device - mDevices.put(id, new long[] { time }); - } - } - return activeDevices; - } - - @Override - public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { - mListeners.remove(listener); - if (handler == null) { - handler = mDefaultHandler; - } - mListeners.put(listener, handler); - } - - @Override - public void unregisterInputDeviceListener(InputDeviceListener listener) { - mListeners.remove(listener); - } - - private void notifyListeners(int why, int deviceId) { - // the state of some device has changed - if (!mListeners.isEmpty()) { - // yes... this will cause an object to get created... hopefully - // it won't happen very often - for (InputDeviceListener listener : mListeners.keySet()) { - Handler handler = mListeners.get(listener); - DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId, listener); - handler.post(odc); - } - } - } - - private static class DeviceEvent implements Runnable { - private int mMessageType; - private int mId; - private InputDeviceListener mListener; - private static Queue<DeviceEvent> sEventQueue = new ArrayDeque<DeviceEvent>(); - - private DeviceEvent() { - } - - static DeviceEvent getDeviceEvent(int messageType, int id, - InputDeviceListener listener) { - DeviceEvent curChanged = sEventQueue.poll(); - if (null == curChanged) { - curChanged = new DeviceEvent(); - } - curChanged.mMessageType = messageType; - curChanged.mId = id; - curChanged.mListener = listener; - return curChanged; - } - - @Override - public void run() { - switch (mMessageType) { - case ON_DEVICE_ADDED: - mListener.onInputDeviceAdded(mId); - break; - case ON_DEVICE_CHANGED: - mListener.onInputDeviceChanged(mId); - break; - case ON_DEVICE_REMOVED: - mListener.onInputDeviceRemoved(mId); - break; - default: - Log.e(LOG_TAG, "Unknown Message Type"); - break; - } - // dump this runnable back in the queue - sEventQueue.offer(this); - } - } - - @Override - public void onGenericMotionEvent(MotionEvent event) { - // detect new devices - int id = event.getDeviceId(); - long[] timeArray = mDevices.get(id); - if (null == timeArray) { - notifyListeners(ON_DEVICE_ADDED, id); - timeArray = new long[1]; - mDevices.put(id, timeArray); - } - long time = SystemClock.elapsedRealtime(); - timeArray[0] = time; - } - - @Override - public void onPause() { - mDefaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT); - } - - @Override - public void onResume() { - mDefaultHandler.sendEmptyMessage(MESSAGE_TEST_FOR_DISCONNECT); - } - + private static final String LOG_TAG = "InputManagerV9"; + private static final int MESSAGE_TEST_FOR_DISCONNECT = 101; + private static final long CHECK_ELAPSED_TIME = 3000L; + + private static final int ON_DEVICE_ADDED = 0; + private static final int ON_DEVICE_CHANGED = 1; + private static final int ON_DEVICE_REMOVED = 2; + + private final SparseArray<long[]> mDevices; + private final Map<InputDeviceListener, Handler> mListeners; + private final Handler mDefaultHandler; + + private static class PollingMessageHandler extends Handler { + private final WeakReference<InputManagerV9> mInputManager; + + PollingMessageHandler(InputManagerV9 im) { + mInputManager = new WeakReference<InputManagerV9>(im); + } + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case MESSAGE_TEST_FOR_DISCONNECT: + InputManagerV9 imv = mInputManager.get(); + if (null != imv) { + long time = SystemClock.elapsedRealtime(); + int size = imv.mDevices.size(); + for (int i = 0; i < size; i++) { + long[] lastContact = imv.mDevices.valueAt(i); + if (null != lastContact) { + if (time - lastContact[0] > CHECK_ELAPSED_TIME) { + // check to see if the device has been + // disconnected + int id = imv.mDevices.keyAt(i); + if (null == InputDevice.getDevice(id)) { + // disconnected! + imv.notifyListeners(ON_DEVICE_REMOVED, id); + imv.mDevices.remove(id); + } else { + lastContact[0] = time; + } + } + } + } + sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, + CHECK_ELAPSED_TIME); + } + break; + } + } + } + + public InputManagerV9() { + mDevices = new SparseArray<long[]>(); + mListeners = new HashMap<InputDeviceListener, Handler>(); + mDefaultHandler = new PollingMessageHandler(this); + // as a side-effect, populates our collection of watched + // input devices + getInputDeviceIds(); + } + + @Override + public InputDevice getInputDevice(int id) { + return InputDevice.getDevice(id); + } + + @Override + public int[] getInputDeviceIds() { + // add any hitherto unknown devices to our + // collection of watched input devices + int[] activeDevices = InputDevice.getDeviceIds(); + long time = SystemClock.elapsedRealtime(); + for (int id : activeDevices) { + long[] lastContact = mDevices.get(id); + if (null == lastContact) { + // we have a new device + mDevices.put(id, new long[] { time }); + } + } + return activeDevices; + } + + @Override + public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { + mListeners.remove(listener); + if (handler == null) { + handler = mDefaultHandler; + } + mListeners.put(listener, handler); + } + + @Override + public void unregisterInputDeviceListener(InputDeviceListener listener) { + mListeners.remove(listener); + } + + private void notifyListeners(int why, int deviceId) { + // the state of some device has changed + if (!mListeners.isEmpty()) { + // yes... this will cause an object to get created... hopefully + // it won't happen very often + for (InputDeviceListener listener : mListeners.keySet()) { + Handler handler = mListeners.get(listener); + DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId, listener); + handler.post(odc); + } + } + } + + private static class DeviceEvent implements Runnable { + private int mMessageType; + private int mId; + private InputDeviceListener mListener; + private static Queue<DeviceEvent> sEventQueue = new ArrayDeque<DeviceEvent>(); + + private DeviceEvent() { + } + + static DeviceEvent getDeviceEvent(int messageType, int id, + InputDeviceListener listener) { + DeviceEvent curChanged = sEventQueue.poll(); + if (null == curChanged) { + curChanged = new DeviceEvent(); + } + curChanged.mMessageType = messageType; + curChanged.mId = id; + curChanged.mListener = listener; + return curChanged; + } + + @Override + public void run() { + switch (mMessageType) { + case ON_DEVICE_ADDED: + mListener.onInputDeviceAdded(mId); + break; + case ON_DEVICE_CHANGED: + mListener.onInputDeviceChanged(mId); + break; + case ON_DEVICE_REMOVED: + mListener.onInputDeviceRemoved(mId); + break; + default: + Log.e(LOG_TAG, "Unknown Message Type"); + break; + } + // dump this runnable back in the queue + sEventQueue.offer(this); + } + } + + @Override + public void onGenericMotionEvent(MotionEvent event) { + // detect new devices + int id = event.getDeviceId(); + long[] timeArray = mDevices.get(id); + if (null == timeArray) { + notifyListeners(ON_DEVICE_ADDED, id); + timeArray = new long[1]; + mDevices.put(id, timeArray); + } + long time = SystemClock.elapsedRealtime(); + timeArray[0] = time; + } + + @Override + public void onPause() { + mDefaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT); + } + + @Override + public void onResume() { + mDefaultHandler.sendEmptyMessage(MESSAGE_TEST_FOR_DISCONNECT); + } } diff --git a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java index 8622f4ccff..d6f26e19b2 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java @@ -39,33 +39,32 @@ import android.util.Log; abstract public class ConsumeTask { private Context context; - + private IInAppBillingService mService; - public ConsumeTask(IInAppBillingService mService, Context context ){ + public ConsumeTask(IInAppBillingService mService, Context context) { this.context = context; this.mService = mService; } - - public void consume(final String sku){ + public void consume(final String sku) { //Log.d("XXX", "Consuming product " + sku); PaymentsCache pc = new PaymentsCache(context); Boolean isBlocked = pc.getConsumableFlag("block", sku); String _token = pc.getConsumableValue("token", sku); - //Log.d("XXX", "token " + _token); - if(!isBlocked && _token == null){ + //Log.d("XXX", "token " + _token); + if (!isBlocked && _token == null) { //_token = "inapp:"+context.getPackageName()+":android.test.purchased"; //Log.d("XXX", "Consuming product " + sku + " with token " + _token); - }else if(!isBlocked){ + } else if (!isBlocked) { //Log.d("XXX", "It is not blocked ¿?"); return; - }else if(_token == null){ + } else if (_token == null) { //Log.d("XXX", "No token available"); this.error("No token for sku:" + sku); return; } final String token = _token; - new AsyncTask<String, String, String>(){ + new AsyncTask<String, String, String>() { @Override protected String doInBackground(String... params) { @@ -73,28 +72,27 @@ abstract public class ConsumeTask { //Log.d("XXX", "Requesting to release item."); int response = mService.consumePurchase(3, context.getPackageName(), token); //Log.d("XXX", "release response code: " + response); - if(response == 0 || response == 8){ + if (response == 0 || response == 8) { return null; } } catch (RemoteException e) { return e.getMessage(); - } return "Some error"; } - - protected void onPostExecute(String param){ - if(param == null){ - success( new PaymentsCache(context).getConsumableValue("ticket", sku) ); - }else{ + + protected void onPostExecute(String param) { + if (param == null) { + success(new PaymentsCache(context).getConsumableValue("ticket", sku)); + } else { error(param); } } - - }.execute(); + + } + .execute(); } - + abstract protected void success(String ticket); abstract protected void error(String message); - } diff --git a/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java b/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java index 0afe35510c..31f6396738 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java @@ -36,15 +36,12 @@ import android.os.AsyncTask; import android.os.RemoteException; import android.util.Log; -abstract public class GenericConsumeTask extends AsyncTask<String, String, String>{ +abstract public class GenericConsumeTask extends AsyncTask<String, String, String> { private Context context; private IInAppBillingService mService; - - - - public GenericConsumeTask(Context context, IInAppBillingService mService, String sku, String receipt, String signature, String token){ + public GenericConsumeTask(Context context, IInAppBillingService mService, String sku, String receipt, String signature, String token) { this.context = context; this.mService = mService; this.sku = sku; @@ -52,19 +49,19 @@ abstract public class GenericConsumeTask extends AsyncTask<String, String, Strin this.signature = signature; this.token = token; } - + private String sku; private String receipt; private String signature; private String token; - + @Override protected String doInBackground(String... params) { try { //Log.d("godot", "Requesting to consume an item with token ." + token); int response = mService.consumePurchase(3, context.getPackageName(), token); //Log.d("godot", "consumePurchase response: " + response); - if(response == 0 || response == 8){ + if (response == 0 || response == 8) { return null; } } catch (Exception e) { @@ -72,11 +69,10 @@ abstract public class GenericConsumeTask extends AsyncTask<String, String, Strin } return null; } - - protected void onPostExecute(String sarasa){ + + protected void onPostExecute(String sarasa) { onSuccess(sku, receipt, signature, token); } - - abstract public void onSuccess(String sku, String receipt, String signature, String token); + abstract public void onSuccess(String sku, String receipt, String signature, String token); } diff --git a/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java b/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java index 7318ae2fc6..80f53d16c8 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java @@ -50,28 +50,26 @@ import android.util.Log; abstract public class HandlePurchaseTask { private Activity context; - - public HandlePurchaseTask(Activity context ){ + + public HandlePurchaseTask(Activity context) { this.context = context; } - - - public void handlePurchaseRequest(int resultCode, Intent data){ + + public void handlePurchaseRequest(int resultCode, Intent data) { //Log.d("XXX", "Handling purchase response"); //int responseCode = data.getIntExtra("RESPONSE_CODE", 0); PaymentsCache pc = new PaymentsCache(context); - + String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA"); //Log.d("XXX", "Purchase data:" + purchaseData); String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); //Log.d("XXX", "Purchase signature:" + dataSignature); - + if (resultCode == Activity.RESULT_OK) { - + try { //Log.d("SARLANGA", purchaseData); - - + JSONObject jo = new JSONObject(purchaseData); //String sku = jo.getString("productId"); //alert("You have bought the " + sku + ". Excellent choice, aventurer!"); @@ -82,8 +80,8 @@ abstract public class HandlePurchaseTask { //Integer state = jo.getInt("purchaseState"); String developerPayload = jo.getString("developerPayload"); String purchaseToken = jo.getString("purchaseToken"); - - if(! pc.getConsumableValue("validation_hash", productId).equals(developerPayload) ) { + + if (!pc.getConsumableValue("validation_hash", productId).equals(developerPayload)) { error("Untrusted callback"); return; } @@ -92,13 +90,13 @@ abstract public class HandlePurchaseTask { pc.setConsumableValue("ticket", productId, purchaseData); pc.setConsumableFlag("block", productId, true); pc.setConsumableValue("token", productId, purchaseToken); - + success(productId, dataSignature, purchaseData); return; - } catch (JSONException e) { + } catch (JSONException e) { error(e.getMessage()); } - }else if( resultCode == Activity.RESULT_CANCELED){ + } else if (resultCode == Activity.RESULT_CANCELED) { canceled(); } } @@ -106,6 +104,4 @@ abstract public class HandlePurchaseTask { abstract protected void success(String sku, String signature, String ticket); abstract protected void error(String message); abstract protected void canceled(); - - } diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java index 69ac02e902..f9828ef77d 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java +++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java @@ -34,41 +34,38 @@ import android.content.SharedPreferences; import android.util.Log; public class PaymentsCache { - + public Context context; - public PaymentsCache(Context context){ + public PaymentsCache(Context context) { this.context = context; } - - - public void setConsumableFlag(String set, String sku, Boolean flag){ - SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putBoolean(sku, flag); - editor.commit(); -} - public boolean getConsumableFlag(String set, String sku){ - SharedPreferences sharedPref = context.getSharedPreferences( - "consumables_" + set, Context.MODE_PRIVATE); - return sharedPref.getBoolean(sku, false); + public void setConsumableFlag(String set, String sku, Boolean flag) { + SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putBoolean(sku, flag); + editor.commit(); } + public boolean getConsumableFlag(String set, String sku) { + SharedPreferences sharedPref = context.getSharedPreferences( + "consumables_" + set, Context.MODE_PRIVATE); + return sharedPref.getBoolean(sku, false); + } - public void setConsumableValue(String set, String sku, String value){ - SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(sku, value); + public void setConsumableValue(String set, String sku, String value) { + SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString(sku, value); //Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku); - editor.commit(); + editor.commit(); } - public String getConsumableValue(String set, String sku){ - SharedPreferences sharedPref = context.getSharedPreferences( - "consumables_" + set, Context.MODE_PRIVATE); + public String getConsumableValue(String set, String sku) { + SharedPreferences sharedPref = context.getSharedPreferences( + "consumables_" + set, Context.MODE_PRIVATE); //Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku); - return sharedPref.getString(sku, null); + return sharedPref.getString(sku, null); } - } diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java index b327265abb..71407566e2 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java +++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java @@ -106,7 +106,6 @@ public class PaymentsManager { @Override protected void error(String message) { godotPaymentV3.callbackFail(); - } @Override @@ -119,8 +118,8 @@ public class PaymentsManager { godotPaymentV3.callbackAlreadyOwned(sku); } - }.purchase(sku, transactionId); - + } + .purchase(sku, transactionId); } public void consumeUnconsumedPurchases() { @@ -135,16 +134,15 @@ public class PaymentsManager { protected void error(String message) { Log.d("godot", "consumeUnconsumedPurchases :" + message); godotPaymentV3.callbackFailConsume(); - } @Override protected void notRequired() { Log.d("godot", "callbackSuccessNoUnconsumedPurchases :"); godotPaymentV3.callbackSuccessNoUnconsumedPurchases(); - } - }.consumeItAll(); + } + .consumeItAll(); } public void requestPurchased() { @@ -210,9 +208,9 @@ public class PaymentsManager { @Override protected void error(String message) { godotPaymentV3.callbackFail(); - } - }.consume(sku); + } + .consume(sku); } } @@ -225,7 +223,8 @@ public class PaymentsManager { protected void canceled() { godotPaymentV3.callbackCancel(); } - }.handlePurchaseRequest(resultCode, data); + } + .handlePurchaseRequest(resultCode, data); } public void validatePurchase(String purchaseToken, final String sku) { @@ -246,8 +245,8 @@ public class PaymentsManager { protected void error(String message) { godotPaymentV3.callbackFail(); } - }.consume(sku); - + } + .consume(sku); } @Override @@ -259,7 +258,8 @@ public class PaymentsManager { protected void canceled() { godotPaymentV3.callbackCancel(); } - }.validatePurchase(sku); + } + .validatePurchase(sku); } public void setAutoConsume(boolean autoConsume) { @@ -278,7 +278,8 @@ public class PaymentsManager { protected void error(String message) { godotPaymentV3.callbackFailConsume(); } - }.consume(sku); + } + .consume(sku); } // Workaround to bug where sometimes response codes come as Long instead of Integer @@ -287,8 +288,10 @@ public class PaymentsManager { if (o == null) { //logDebug("Bundle with null response code, assuming OK (known issue)"); return BILLING_RESPONSE_RESULT_OK; - } else if (o instanceof Integer) return ((Integer) o).intValue(); - else if (o instanceof Long) return (int) ((Long) o).longValue(); + } else if (o instanceof Integer) + return ((Integer)o).intValue(); + else if (o instanceof Long) + return (int)((Long)o).longValue(); else { //logError("Unexpected type for bundle response code."); //logError(o.getClass().getName()); @@ -304,25 +307,41 @@ public class PaymentsManager { * It also includes the result code numerically. */ public static String getResponseDesc(int code) { - String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" + - "3:Billing Unavailable/4:Item unavailable/" + - "5:Developer Error/6:Error/7:Item Already Owned/" + - "8:Item not owned").split("/"); - String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" + - "-1002:Bad response received/" + - "-1003:Purchase signature verification failed/" + - "-1004:Send intent failed/" + - "-1005:User cancelled/" + - "-1006:Unknown purchase response/" + - "-1007:Missing token/" + - "-1008:Unknown error/" + - "-1009:Subscriptions not available/" + - "-1010:Invalid consumption attempt").split("/"); + String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" + + + "3:Billing Unavailable/4:Item unavailable/" + + + "5:Developer Error/6:Error/7:Item Already Owned/" + + + "8:Item not owned") + .split("/"); + String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" + + + "-1002:Bad response received/" + + + "-1003:Purchase signature verification failed/" + + + "-1004:Send intent failed/" + + + "-1005:User cancelled/" + + + "-1006:Unknown purchase response/" + + + "-1007:Missing token/" + + + "-1008:Unknown error/" + + + "-1009:Subscriptions not available/" + + + "-1010:Invalid consumption attempt") + .split("/"); if (code <= -1000) { int index = -1000 - code; - if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index]; - else return String.valueOf(code) + ":Unknown IAB Helper Error"; + if (index >= 0 && index < iabhelper_msgs.length) + return iabhelper_msgs[index]; + else + return String.valueOf(code) + ":Unknown IAB Helper Error"; } else if (code < 0 || code >= iab_msgs.length) return String.valueOf(code) + ":Unknown"; else @@ -375,7 +394,7 @@ public class PaymentsManager { ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST"); for (String thisResponse : responseList) { - Log.d("godot", "response = "+thisResponse); + Log.d("godot", "response = " + thisResponse); godotPaymentV3.addSkuDetail(thisResponse); } } catch (RemoteException e) { @@ -385,7 +404,8 @@ public class PaymentsManager { } godotPaymentV3.completeSkuDetail(); } - })).start(); + })) + .start(); } private GodotPaymentV3 godotPaymentV3; @@ -393,5 +413,4 @@ public class PaymentsManager { public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) { this.godotPaymentV3 = godotPaymentV3; } - } diff --git a/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java b/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java index 6ecea0106c..e2f08345ad 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java @@ -50,17 +50,16 @@ import android.util.Log; abstract public class PurchaseTask { private Activity context; - + private IInAppBillingService mService; - public PurchaseTask(IInAppBillingService mService, Activity context ){ + public PurchaseTask(IInAppBillingService mService, Activity context) { this.context = context; this.mService = mService; } - private boolean isLooping = false; - - public void purchase(final String sku, final String transactionId){ + + public void purchase(final String sku, final String transactionId) { Log.d("XXX", "Starting purchase for: " + sku); PaymentsCache pc = new PaymentsCache(context); Boolean isBlocked = pc.getConsumableFlag("block", sku); @@ -75,7 +74,7 @@ abstract public class PurchaseTask { Bundle buyIntentBundle; try { - buyIntentBundle = mService.getBuyIntent(3, context.getApplicationContext().getPackageName(), sku, "inapp", hash ); + buyIntentBundle = mService.getBuyIntent(3, context.getApplicationContext().getPackageName(), sku, "inapp", hash); } catch (RemoteException e) { //Log.d("XXX", "Error: " + e.getMessage()); error(e.getMessage()); @@ -83,50 +82,45 @@ abstract public class PurchaseTask { } Object rc = buyIntentBundle.get("RESPONSE_CODE"); int responseCode = 0; - if(rc == null){ + if (rc == null) { responseCode = PaymentsManager.BILLING_RESPONSE_RESULT_OK; - }else if( rc instanceof Integer){ + } else if (rc instanceof Integer) { responseCode = ((Integer)rc).intValue(); - }else if( rc instanceof Long){ + } else if (rc instanceof Long) { responseCode = (int)((Long)rc).longValue(); } //Log.d("XXX", "Buy intent response code: " + responseCode); - if(responseCode == 1 || responseCode == 3 || responseCode == 4){ + if (responseCode == 1 || responseCode == 3 || responseCode == 4) { canceled(); return; } - if(responseCode == 7){ + if (responseCode == 7) { alreadyOwned(); return; } - - + PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT"); pc.setConsumableValue("validation_hash", sku, hash); try { - if(context == null){ + if (context == null) { //Log.d("XXX", "No context!"); } - if(pendingIntent == null){ + if (pendingIntent == null) { //Log.d("XXX", "No pending intent"); } //Log.d("XXX", "Starting activity for purchase!"); context.startIntentSenderForResult( pendingIntent.getIntentSender(), - PaymentsManager.REQUEST_CODE_FOR_PURCHASE, - new Intent(), + PaymentsManager.REQUEST_CODE_FOR_PURCHASE, + new Intent(), Integer.valueOf(0), Integer.valueOf(0), - Integer.valueOf(0)); + Integer.valueOf(0)); } catch (SendIntentException e) { error(e.getMessage()); } - - - } abstract protected void error(String message); abstract protected void canceled(); abstract protected void alreadyOwned(); - } diff --git a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java index d831e45694..765906d0bb 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java @@ -48,69 +48,63 @@ abstract public class ReleaseAllConsumablesTask { private Context context; private IInAppBillingService mService; - - public ReleaseAllConsumablesTask(IInAppBillingService mService, Context context ){ + + public ReleaseAllConsumablesTask(IInAppBillingService mService, Context context) { this.context = context; this.mService = mService; } - - public void consumeItAll(){ - try{ + public void consumeItAll() { + try { //Log.d("godot", "consumeItall for " + context.getPackageName()); - Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp",null); - + Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp", null); + for (String key : bundle.keySet()) { Object value = bundle.get(key); //Log.d("godot", String.format("%s %s (%s)", key, //value.toString(), value.getClass().getName())); } - - - if (bundle.getInt("RESPONSE_CODE") == 0){ + + if (bundle.getInt("RESPONSE_CODE") == 0) { final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); - - if (myPurchases == null || myPurchases.size() == 0){ + if (myPurchases == null || myPurchases.size() == 0) { //Log.d("godot", "No purchases!"); notRequired(); return; } - - + //Log.d("godot", "# products to be consumed:" + myPurchases.size()); - for (int i=0;i<myPurchases.size();i++) - { - - try{ + for (int i = 0; i < myPurchases.size(); i++) { + + try { String receipt = myPurchases.get(i); JSONObject inappPurchaseData = new JSONObject(receipt); String sku = inappPurchaseData.getString("productId"); String token = inappPurchaseData.getString("purchaseToken"); String signature = mySignatures.get(i); //Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt); - new GenericConsumeTask(context, mService, sku, receipt,signature, token) { - + new GenericConsumeTask(context, mService, sku, receipt, signature, token) { + @Override public void onSuccess(String sku, String receipt, String signature, String token) { ReleaseAllConsumablesTask.this.success(sku, receipt, signature, token); } - }.execute(); - + } + .execute(); + } catch (JSONException e) { } } - } - }catch(Exception e){ + } catch (Exception e) { Log.d("godot", "Error releasing products:" + e.getClass().getName() + ":" + e.getMessage()); } } - + abstract protected void success(String sku, String receipt, String signature, String token); abstract protected void error(String message); abstract protected void notRequired(); - } diff --git a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java index 6e058c140c..3e62ef282a 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java @@ -55,22 +55,21 @@ abstract public class ValidateTask { private Activity context; private GodotPaymentV3 godotPaymentsV3; - public ValidateTask(Activity context, GodotPaymentV3 godotPaymentsV3){ + public ValidateTask(Activity context, GodotPaymentV3 godotPaymentsV3) { this.context = context; this.godotPaymentsV3 = godotPaymentsV3; } - - public void validatePurchase(final String sku){ - new AsyncTask<String, String, String>(){ - + public void validatePurchase(final String sku) { + new AsyncTask<String, String, String>() { + private ProgressDialog dialog; @Override - protected void onPreExecute(){ + protected void onPreExecute() { dialog = ProgressDialog.show(context, null, "Please wait..."); } - + @Override protected String doInBackground(String... params) { PaymentsCache pc = new PaymentsCache(context); @@ -90,37 +89,34 @@ abstract public class ValidateTask { //Log.d("XXX", "Validation response:\n"+jsonResponse); return jsonResponse; } - + @Override - protected void onPostExecute(String response){ - if(dialog != null){ + protected void onPostExecute(String response) { + if (dialog != null) { dialog.dismiss(); } JSONObject j; try { j = new JSONObject(response); - if(j.getString("status").equals("OK")){ + if (j.getString("status").equals("OK")) { success(); return; - }else if(j.getString("status") != null){ + } else if (j.getString("status") != null) { error(j.getString("message")); - }else{ + } else { error("Connection error"); } } catch (JSONException e) { error(e.getMessage()); - }catch (Exception e){ + } catch (Exception e) { error(e.getMessage()); } - - } - - }.execute(); + + } + .execute(); } abstract protected void success(); abstract protected void error(String message); abstract protected void canceled(); - - } diff --git a/platform/android/java/src/org/godotengine/godot/utils/Crypt.java b/platform/android/java/src/org/godotengine/godot/utils/Crypt.java index 2fd66553f6..35e4e430a4 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/Crypt.java +++ b/platform/android/java/src/org/godotengine/godot/utils/Crypt.java @@ -34,34 +34,34 @@ import java.util.Random; public class Crypt { - public static String md5(String input){ - try { - // Create MD5 Hash - MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); - digest.update(input.getBytes()); - byte messageDigest[] = digest.digest(); - - // Create Hex String - StringBuffer hexString = new StringBuffer(); - for (int i=0; i<messageDigest.length; i++) - hexString.append(Integer.toHexString(0xFF & messageDigest[i])); - return hexString.toString(); - - } catch (Exception e) { - e.printStackTrace(); - } - return ""; + public static String md5(String input) { + try { + // Create MD5 Hash + MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); + digest.update(input.getBytes()); + byte messageDigest[] = digest.digest(); + + // Create Hex String + StringBuffer hexString = new StringBuffer(); + for (int i = 0; i < messageDigest.length; i++) + hexString.append(Integer.toHexString(0xFF & messageDigest[i])); + return hexString.toString(); + + } catch (Exception e) { + e.printStackTrace(); + } + return ""; } - - public static String createRandomHash(){ + + public static String createRandomHash() { return md5(Long.toString(createRandomLong())); } - - public static long createAbsRandomLong(){ + + public static long createAbsRandomLong() { return Math.abs(createRandomLong()); } - - public static long createRandomLong(){ + + public static long createRandomLong() { Random r = new Random(); return r.nextLong(); } diff --git a/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java index 3fc8c48397..bfcf7e3b2a 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java +++ b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java @@ -42,30 +42,29 @@ import javax.net.ssl.TrustManagerFactory; import org.apache.http.conn.ssl.SSLSocketFactory; - /** * * @author Luis Linietsky <luis.linietsky@gmail.com> */ public class CustomSSLSocketFactory extends SSLSocketFactory { - SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLContext sslContext = SSLContext.getInstance("TLS"); - public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - super(truststore); + public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { + super(truststore); - TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); - tmf.init(truststore); + TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); + tmf.init(truststore); - sslContext.init(null, tmf.getTrustManagers(), null); - } + sslContext.init(null, tmf.getTrustManagers(), null); + } - @Override - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { - return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); - } + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { + return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); + } - @Override - public Socket createSocket() throws IOException { - return sslContext.getSocketFactory().createSocket(); - } + @Override + public Socket createSocket() throws IOException { + return sslContext.getSocketFactory().createSocket(); + } } diff --git a/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java b/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java index 0711f30b8b..81a642af9f 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java +++ b/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java @@ -63,7 +63,6 @@ import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; - import android.content.Context; import android.content.SharedPreferences; import android.util.Log; @@ -73,155 +72,154 @@ import android.util.Log; * @author Luis Linietsky <luis.linietsky@gmail.com> */ public class HttpRequester { - + private Context context; - private static final int TTL = 600000; // 10 minutos - private long cttl=0; - - public HttpRequester(){ + private static final int TTL = 600000; // 10 minutos + private long cttl = 0; + + public HttpRequester() { //Log.d("XXX", "Creando http request sin contexto"); } - - public HttpRequester(Context context){ - this.context=context; + + public HttpRequester(Context context) { + this.context = context; //Log.d("XXX", "Creando http request con contexto"); } - - public String post(RequestParams params){ - HttpPost httppost = new HttpPost(params.getUrl()); - try { + + public String post(RequestParams params) { + HttpPost httppost = new HttpPost(params.getUrl()); + try { httppost.setEntity(new UrlEncodedFormEntity(params.toPairsList())); return request(httppost); } catch (UnsupportedEncodingException e) { return null; } } - - public String get(RequestParams params){ + + public String get(RequestParams params) { String response = getResponseFromCache(params.getUrl()); - if(response == null){ + if (response == null) { //Log.d("XXX", "Cache miss!"); - HttpGet httpget = new HttpGet(params.getUrl()); - long timeInit = new Date().getTime(); - response = request(httpget); - long delay = new Date().getTime() - timeInit; - Log.d("com.app11tt.android.utils.HttpRequest::get(url)", "Url: " + params.getUrl() + " downloaded in " + String.format("%.03f", delay/1000.0f) + " seconds"); - if(response == null || response.length() == 0){ - response = ""; - }else{ - saveResponseIntoCache(params.getUrl(), response); - } + HttpGet httpget = new HttpGet(params.getUrl()); + long timeInit = new Date().getTime(); + response = request(httpget); + long delay = new Date().getTime() - timeInit; + Log.d("com.app11tt.android.utils.HttpRequest::get(url)", "Url: " + params.getUrl() + " downloaded in " + String.format("%.03f", delay / 1000.0f) + " seconds"); + if (response == null || response.length() == 0) { + response = ""; + } else { + saveResponseIntoCache(params.getUrl(), response); + } } Log.d("XXX", "Req: " + params.getUrl()); Log.d("XXX", "Resp: " + response); - return response; + return response; } - - private String request(HttpUriRequest request){ + + private String request(HttpUriRequest request) { //Log.d("XXX", "Haciendo request a: " + request.getURI() ); - Log.d("PPP", "Haciendo request a: " + request.getURI() ); + Log.d("PPP", "Haciendo request a: " + request.getURI()); long init = new Date().getTime(); HttpClient httpclient = getNewHttpClient(); HttpParams httpParameters = httpclient.getParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, 0); HttpConnectionParams.setSoTimeout(httpParameters, 0); HttpConnectionParams.setTcpNoDelay(httpParameters, true); - try { - HttpResponse response = httpclient.execute(request); - Log.d("PPP", "Fin de request (" + (new Date().getTime() - init) + ") a: " + request.getURI() ); + try { + HttpResponse response = httpclient.execute(request); + Log.d("PPP", "Fin de request (" + (new Date().getTime() - init) + ") a: " + request.getURI()); //Log.d("XXX1", "Status:" + response.getStatusLine().toString()); - if(response.getStatusLine().getStatusCode() == 200){ - String strResponse = EntityUtils.toString(response.getEntity()); + if (response.getStatusLine().getStatusCode() == 200) { + String strResponse = EntityUtils.toString(response.getEntity()); //Log.d("XXX2", strResponse); - return strResponse; - }else{ - Log.d("XXX3", "Response status code:" + response.getStatusLine().getStatusCode() + "\n" + EntityUtils.toString(response.getEntity())); - return null; - } - - } catch (ClientProtocolException e) { - Log.d("XXX3", e.getMessage()); - } catch (IOException e) { - Log.d("XXX4", e.getMessage()); - } + return strResponse; + } else { + Log.d("XXX3", "Response status code:" + response.getStatusLine().getStatusCode() + "\n" + EntityUtils.toString(response.getEntity())); + return null; + } + + } catch (ClientProtocolException e) { + Log.d("XXX3", e.getMessage()); + } catch (IOException e) { + Log.d("XXX4", e.getMessage()); + } return null; } - + private HttpClient getNewHttpClient() { - try { - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - trustStore.load(null, null); + try { + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, null); - SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore); - sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore); + sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - HttpParams params = new BasicHttpParams(); - HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); - HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); + HttpParams params = new BasicHttpParams(); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); - SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - registry.register(new Scheme("https", sf, 443)); + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + registry.register(new Scheme("https", sf, 443)); - ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); + ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); - return new DefaultHttpClient(ccm, params); - } catch (Exception e) { - return new DefaultHttpClient(); - } + return new DefaultHttpClient(ccm, params); + } catch (Exception e) { + return new DefaultHttpClient(); + } } - + private static String convertStreamToString(InputStream is) { - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - StringBuilder sb = new StringBuilder(); - String line = null; - try { - while ((line = reader.readLine()) != null) { - sb.append((line + "\n")); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - is.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return sb.toString(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line = null; + try { + while ((line = reader.readLine()) != null) { + sb.append((line + "\n")); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return sb.toString(); } - public void saveResponseIntoCache(String request, String response){ - if(context == null){ + public void saveResponseIntoCache(String request, String response) { + if (context == null) { //Log.d("XXX", "No context, cache failed!"); return; } - SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString("request_" + Crypt.md5(request), response); - editor.putLong("request_" + Crypt.md5(request) + "_ttl", new Date().getTime() + getTtl()); - editor.commit(); + SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString("request_" + Crypt.md5(request), response); + editor.putLong("request_" + Crypt.md5(request) + "_ttl", new Date().getTime() + getTtl()); + editor.commit(); } - - - public String getResponseFromCache(String request){ - if(context == null){ + + public String getResponseFromCache(String request) { + if (context == null) { Log.d("XXX", "No context, cache miss"); return null; } - SharedPreferences sharedPref = context.getSharedPreferences( "http_get_cache", Context.MODE_PRIVATE); - long ttl = getResponseTtl(request); - if(ttl == 0l || (new Date().getTime() - ttl) > 0l){ - Log.d("XXX", "Cache invalid ttl:" + ttl + " vs now:" + new Date().getTime()); - return null; - } - return sharedPref.getString("request_" + Crypt.md5(request), null); + SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE); + long ttl = getResponseTtl(request); + if (ttl == 0l || (new Date().getTime() - ttl) > 0l) { + Log.d("XXX", "Cache invalid ttl:" + ttl + " vs now:" + new Date().getTime()); + return null; + } + return sharedPref.getString("request_" + Crypt.md5(request), null); } - public long getResponseTtl(String request){ - SharedPreferences sharedPref = context.getSharedPreferences( - "http_get_cache", Context.MODE_PRIVATE); - return sharedPref.getLong("request_" + Crypt.md5(request) + "_ttl", 0l); + public long getResponseTtl(String request) { + SharedPreferences sharedPref = context.getSharedPreferences( + "http_get_cache", Context.MODE_PRIVATE); + return sharedPref.getLong("request_" + Crypt.md5(request) + "_ttl", 0l); } public long getTtl() { @@ -229,7 +227,6 @@ public class HttpRequester { } public void setTtl(long ttl) { - this.cttl = (ttl*1000) + new Date().getTime(); + this.cttl = (ttl * 1000) + new Date().getTime(); } - } diff --git a/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java b/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java index ded11550bb..051fed5500 100644 --- a/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java +++ b/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java @@ -43,33 +43,33 @@ import org.apache.http.message.BasicNameValuePair; */ public class RequestParams { - private HashMap<String,String> params; + private HashMap<String, String> params; private String url; - - public RequestParams(){ - params = new HashMap<String,String>(); + + public RequestParams() { + params = new HashMap<String, String>(); } - - public void put(String key, String value){ + + public void put(String key, String value) { params.put(key, value); } - - public String get(String key){ + + public String get(String key) { return params.get(key); } - - public void remove(Object key){ + + public void remove(Object key) { params.remove(key); } - - public boolean has(String key){ + + public boolean has(String key) { return params.containsKey(key); } - - public List<NameValuePair> toPairsList(){ - List<NameValuePair> fields = new ArrayList<NameValuePair>(); - for(String key : params.keySet()){ + public List<NameValuePair> toPairsList() { + List<NameValuePair> fields = new ArrayList<NameValuePair>(); + + for (String key : params.keySet()) { fields.add(new BasicNameValuePair(key, this.get(key))); } return fields; @@ -82,6 +82,4 @@ public class RequestParams { public void setUrl(String url) { this.url = url; } - - } diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index ef5a065107..f7196755af 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -105,6 +105,7 @@ void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_ context_gl = memnew(ContextGL_Haiku(window)); context_gl->initialize(); context_gl->make_current(); + context_gl->set_use_vsync(current_video_mode.use_vsync); /* Port to GLES 3 rasterizer */ //rasterizer = memnew(RasterizerGLES2); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 6cc8be250d..75d0bd1648 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1089,6 +1089,8 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au [context makeCurrentContext]; + set_use_vsync(p_desired.use_vsync); + [NSApp activateIgnoringOtherApps:YES]; _update_window(); diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 1655caf04b..659f162724 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -241,6 +241,7 @@ void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_aud RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); + gl_context->set_use_vsync(vm.use_vsync); visual_server = memnew(VisualServerRaster); // FIXME: Reimplement threaded rendering? Or remove? diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index 5301aa9e95..1b6a8f4a60 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -28,11 +28,135 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "editor/editor_export.h" +#include "editor/editor_settings.h" +#include "os/file_access.h" +#include "os/os.h" #include "platform/windows/logo.gen.h" +class EditorExportPlatformWindows : public EditorExportPlatformPC { + +public: + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); + virtual void get_export_options(List<ExportOption> *r_options); +}; + +Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags); + + if (err != OK) { + return err; + } + + String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit"); + + if (rcedit_path == String()) { + return OK; + } + + if (!FileAccess::exists(rcedit_path)) { + ERR_PRINTS("Could not find rcedit executable at " + rcedit_path + ", aborting."); + return ERR_FILE_NOT_FOUND; + } + +#ifndef WINDOWS_ENABLED + // On non-Windows we need WINE to run rcedit + String wine_path = EditorSettings::get_singleton()->get("export/windows/wine"); + + if (wine_path != String() && !FileAccess::exists(wine_path)) { + ERR_PRINTS("Could not find wine executable at " + wine_path + ", aborting."); + return ERR_FILE_NOT_FOUND; + } + + if (wine_path == String()) { + wine_path = "wine"; // try to run wine from PATH + } +#endif + + String icon_path = p_preset->get("application/icon"); + String file_verion = p_preset->get("application/file_version"); + String product_version = p_preset->get("application/product_version"); + String company_name = p_preset->get("application/company_name"); + String product_name = p_preset->get("application/product_name"); + String file_description = p_preset->get("application/file_description"); + String copyright = p_preset->get("application/copyright"); + String trademarks = p_preset->get("application/trademarks"); + String comments = p_preset->get("application/comments"); + + List<String> args; + args.push_back(p_path); + if (icon_path != String()) { + args.push_back("--set-icon"); + args.push_back(icon_path); + } + if (file_verion != String()) { + args.push_back("--set-file-version"); + args.push_back(file_verion); + } + if (product_version != String()) { + args.push_back("--set-product-version"); + args.push_back(product_version); + } + if (company_name != String()) { + args.push_back("--set-version-string"); + args.push_back("CompanyName"); + args.push_back(company_name); + } + if (product_name != String()) { + args.push_back("--set-version-string"); + args.push_back("ProductName"); + args.push_back(product_name); + } + if (file_description != String()) { + args.push_back("--set-version-string"); + args.push_back("FileDescription"); + args.push_back(file_description); + } + if (copyright != String()) { + args.push_back("--set-version-string"); + args.push_back("LegalCopyright"); + args.push_back(copyright); + } + if (trademarks != String()) { + args.push_back("--set-version-string"); + args.push_back("LegalTrademarks"); + args.push_back(trademarks); + } + +#ifdef WINDOWS_ENABLED + OS::get_singleton()->execute(rcedit_path, args, true); +#else + // On non-Windows we need WINE to run rcedit + args.push_front(rcedit_path); + OS::get_singleton()->execute(wine_path, args, true); +#endif + + return OK; +} + +void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) { + EditorExportPlatformPC::get_export_options(r_options); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_GLOBAL_FILE, "*.ico"), String())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version"), String())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version"), String())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name"), String())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_name"), String())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), String())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), String())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), String())); +} + void register_windows_exporter() { - Ref<EditorExportPlatformPC> platform; + EDITOR_DEF("export/windows/rcedit", ""); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe")); +#ifndef WINDOWS_ENABLED + // On non-Windows we need WINE to run rcedit + EDITOR_DEF("export/windows/wine", ""); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/wine", PROPERTY_HINT_GLOBAL_FILE)); +#endif + + Ref<EditorExportPlatformWindows> platform; platform.instance(); Ref<Image> img = memnew(Image(_windows_logo)); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 79a760f055..41730d33af 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1074,6 +1074,8 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); + + gl_context->set_use_vsync(video_mode.use_vsync); #endif visual_server = memnew(VisualServerRaster); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index c210a03688..b59fab7088 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -195,14 +195,13 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au XIDeviceInfo *dev = &info[i]; if (!dev->enabled) continue; - /*if (dev->use != XIMasterPointer) - continue;*/ + if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave)) + continue; bool direct_touch = false; for (int j = 0; j < dev->num_classes; j++) { if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) { direct_touch = true; - printf("%d) %d %s\n", i, dev->attachment, dev->name); break; } } @@ -215,7 +214,7 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au XIFreeDeviceInfo(info); if (!touch.devices.size()) { - fprintf(stderr, "No suitable touch device found\n"); + fprintf(stderr, "No touch devices found\n"); } } } @@ -286,6 +285,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au RasterizerGLES3::make_current(); + context_gl->set_use_vsync(current_videomode.use_vsync); + #endif visual_server = memnew(VisualServerRaster); @@ -357,7 +358,7 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au // Must be alive after this block static unsigned char mask_data[XIMaskLen(XI_LASTEVENT)] = {}; - touch.event_mask.deviceid = XIAllMasterDevices; + touch.event_mask.deviceid = XIAllDevices; touch.event_mask.mask_len = sizeof(mask_data); touch.event_mask.mask = mask_data; @@ -368,12 +369,14 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au XISelectEvents(x11_display, x11_window, &touch.event_mask, 1); - XIClearMask(touch.event_mask.mask, XI_TouchOwnership); + // Disabled by now since grabbing also blocks mouse events + // (they are received as extended events instead of standard events) + /*XIClearMask(touch.event_mask.mask, XI_TouchOwnership); // Grab touch devices to avoid OS gesture interference for (int i = 0; i < touch.devices.size(); ++i) { XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask); - } + }*/ } #endif @@ -510,15 +513,14 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au power_manager = memnew(PowerX11); XEvent xevent; - while (XCheckIfEvent(x11_display, &xevent, _check_window_events, NULL)) { - _window_changed(&xevent); + while (XPending(x11_display) > 0) { + XNextEvent(x11_display, &xevent); + if (xevent.type == ConfigureNotify) { + _window_changed(&xevent); + } } } -int OS_X11::_check_window_events(Display *display, XEvent *event, char *arg) { - if (event->type == ConfigureNotify) return 1; - return 0; -} void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data, ::XPointer call_data) { @@ -1511,7 +1513,7 @@ void OS_X11::process_xevents() { #ifdef TOUCH_ENABLED if (XGetEventData(x11_display, &event.xcookie)) { - if (event.xcookie.extension == touch.opcode) { + if (event.xcookie.type == GenericEvent && event.xcookie.extension == touch.opcode) { XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data; int index = event_data->detail; @@ -1520,7 +1522,8 @@ void OS_X11::process_xevents() { switch (event_data->evtype) { case XI_TouchBegin: // Fall-through - XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch); + // Disabled hand-in-hand with the grabbing + //XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch); case XI_TouchEnd: { @@ -1566,9 +1569,8 @@ void OS_X11::process_xevents() { } break; } } - - XFreeEventData(x11_display, &event.xcookie); } + XFreeEventData(x11_display, &event.xcookie); #endif switch (event.type) { @@ -1614,10 +1616,10 @@ void OS_X11::process_xevents() { GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime); } #ifdef TOUCH_ENABLED - // Grab touch devices to avoid OS gesture interference - for (int i = 0; i < touch.devices.size(); ++i) { + // Grab touch devices to avoid OS gesture interference + /*for (int i = 0; i < touch.devices.size(); ++i) { XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask); - } + }*/ #endif if (xic) { XSetICFocus(xic); @@ -1637,9 +1639,9 @@ void OS_X11::process_xevents() { } #ifdef TOUCH_ENABLED // Ungrab touch devices so input works as usual while we are unfocused - for (int i = 0; i < touch.devices.size(); ++i) { + /*for (int i = 0; i < touch.devices.size(); ++i) { XIUngrabDevice(x11_display, touch.devices[i], CurrentTime); - } + }*/ // Release every pointer to avoid sticky points for (Map<int, Vector2>::Element *E = touch.state.front(); E; E = E->next()) { diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 84dff2e089..244c69ee2b 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -199,7 +199,6 @@ protected: virtual void set_main_loop(MainLoop *p_main_loop); void _window_changed(XEvent *xevent); - static int _check_window_events(Display *display, XEvent *xevent, char *arg); public: virtual String get_name(); diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 768d5185d7..82123d12ac 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -623,6 +623,29 @@ void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vect VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased); } + +void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + Vector<Color> colors; + colors.push_back(p_color); + VisualServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width, p_antialiased); +} + +void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + VisualServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width, p_antialiased); +} + void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled) { if (!drawing) { @@ -979,6 +1002,8 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width", "antialiased"), &CanvasItem::draw_multiline, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled"), &CanvasItem::draw_rect, DEFVAL(true)); ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle); ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant())); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index ccbb528d6f..2384c0f370 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -268,6 +268,8 @@ public: void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); + void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); + void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true); void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color); void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>()); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index e1c7331393..4029ef137b 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -107,34 +107,56 @@ void PathFollow2D::_update_transform() { if (!c.is_valid()) return; - if (delta_offset == 0) { - return; - } - - float o = offset; + float path_length = c->get_baked_length(); + float bounded_offset = offset; if (loop) - o = Math::fposmod(o, c->get_baked_length()); - - Vector2 pos = c->interpolate_baked(o, cubic); + bounded_offset = Math::fposmod(bounded_offset, path_length); + else + bounded_offset = CLAMP(bounded_offset, 0, path_length); - Vector2 displacement_offset = Vector2(h_offset, v_offset); + Vector2 pos = c->interpolate_baked(bounded_offset, cubic); if (rotate) { + float ahead = bounded_offset + lookahead; + + if (loop && ahead >= path_length) { + // If our lookahead will loop, we need to check if the path is closed. + int point_count = c->get_point_count(); + if (point_count > 0) { + Vector2 start_point = c->get_point_position(0); + Vector2 end_point = c->get_point_position(point_count - 1); + if (start_point == end_point) { + // Since the path is closed we want to 'smooth off' + // the corner at the start/end. + // So we wrap the lookahead back round. + ahead = Math::fmod(ahead, path_length); + } + } + } + + Vector2 ahead_pos = c->interpolate_baked(ahead, cubic); - Vector2 t_prev = (pos - c->interpolate_baked(o - delta_offset, cubic)).normalized(); - Vector2 t_next = (c->interpolate_baked(o + delta_offset, cubic) - pos).normalized(); + Vector2 tangent_to_curve; + if (ahead_pos == pos) { + // This will happen at the end of non-looping or non-closed paths. + // We'll try a look behind instead, in order to get a meaningful angle. + tangent_to_curve = + (pos - c->interpolate_baked(bounded_offset - lookahead, cubic)).normalized(); + } else { + tangent_to_curve = (ahead_pos - pos).normalized(); + } - float angle = t_prev.angle_to(t_next); + Vector2 normal_of_curve = -tangent_to_curve.tangent(); - set_rotation(get_rotation() + angle); + pos += tangent_to_curve * h_offset; + pos += normal_of_curve * v_offset; - Vector2 n = t_next; - Vector2 t = -n.tangent(); - pos += n * h_offset + t * v_offset; + set_rotation(tangent_to_curve.angle()); } else { - pos += displacement_offset; + pos.x += h_offset; + pos.y += v_offset; } set_position(pos); @@ -185,6 +207,8 @@ bool PathFollow2D::_set(const StringName &p_name, const Variant &p_value) { set_cubic_interpolation(p_value); } else if (String(p_name) == "loop") { set_loop(p_value); + } else if (String(p_name) == "lookahead") { + set_lookahead(p_value); } else return false; @@ -207,6 +231,8 @@ bool PathFollow2D::_get(const StringName &p_name, Variant &r_ret) const { r_ret = cubic; } else if (String(p_name) == "loop") { r_ret = loop; + } else if (String(p_name) == "lookahead") { + r_ret = lookahead; } else return false; @@ -224,6 +250,7 @@ void PathFollow2D::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::BOOL, "rotate")); p_list->push_back(PropertyInfo(Variant::BOOL, "cubic_interp")); p_list->push_back(PropertyInfo(Variant::BOOL, "loop")); + p_list->push_back(PropertyInfo(Variant::REAL, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001")); } String PathFollow2D::get_configuration_warning() const { @@ -263,7 +290,7 @@ void PathFollow2D::_bind_methods() { } void PathFollow2D::set_offset(float p_offset) { - delta_offset = p_offset - offset; + offset = p_offset; if (path) _update_transform(); @@ -314,6 +341,16 @@ float PathFollow2D::get_unit_offset() const { return 0; } +void PathFollow2D::set_lookahead(float p_lookahead) { + + lookahead = p_lookahead; +} + +float PathFollow2D::get_lookahead() const { + + return lookahead; +} + void PathFollow2D::set_rotate(bool p_rotate) { rotate = p_rotate; @@ -338,11 +375,11 @@ bool PathFollow2D::has_loop() const { PathFollow2D::PathFollow2D() { offset = 0; - delta_offset = 0; h_offset = 0; v_offset = 0; path = NULL; rotate = true; cubic = true; loop = true; + lookahead = 4; } diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index f5ba3a3d32..88a0abdea9 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -60,9 +60,9 @@ public: private: Path2D *path; real_t offset; - real_t delta_offset; // change in offset since last _update_transform real_t h_offset; real_t v_offset; + real_t lookahead; bool cubic; bool loop; bool rotate; @@ -90,6 +90,9 @@ public: void set_unit_offset(float p_unit_offset); float get_unit_offset() const; + void set_lookahead(float p_lookahead); + float get_lookahead() const; + void set_loop(bool p_loop); bool has_loop() const; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index c0d0a6e011..5a32a3d0f0 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -513,16 +513,13 @@ void TileMap::_update_dirty_quadrants() { } Ref<OccluderPolygon2D> occluder; - Vector2 occluder_ofs; if (tile_set->tile_get_is_autotile(c.id)) { occluder = tile_set->autotile_get_light_occluder(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); - occluder_ofs = tile_set->tile_get_occluder_offset(c.id); } else { occluder = tile_set->tile_get_light_occluder(c.id); - occluder_ofs = Vector2(); } if (occluder.is_valid()) { - + Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id); Transform2D xform; xform.set_origin(offset.floor() + q.pos); _fix_cell_transform(xform, c, occluder_ofs + center_ofs, s); @@ -968,14 +965,14 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) { int c = p_data.size(); PoolVector<int>::Read r = p_data.read(); - int offset = (format == FORMAT_2_1_5) ? 3 : 2; + int offset = (format == FORMAT_2) ? 3 : 2; clear(); for (int i = 0; i < c; i += offset) { const uint8_t *ptr = (const uint8_t *)&r[i]; uint8_t local[12]; - for (int j = 0; j < ((format == FORMAT_2_1_5) ? 12 : 8); j++) + for (int j = 0; j < ((format == FORMAT_2) ? 12 : 8); j++) local[j] = ptr[j]; #ifdef BIG_ENDIAN_ENABLED @@ -985,7 +982,7 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) { SWAP(local[4], local[7]); SWAP(local[5], local[6]); //TODO: ask someone to check this... - if (FORMAT == FORMAT_2_1_5) { + if (FORMAT == FORMAT_2) { SWAP(local[8], local[11]); SWAP(local[9], local[10]); } @@ -1000,7 +997,7 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) { v &= (1 << 29) - 1; int16_t coord_x; int16_t coord_y; - if (format == FORMAT_2_1_5) { + if (format == FORMAT_2) { coord_x = decode_uint16(&local[8]); coord_y = decode_uint16(&local[10]); } @@ -1018,6 +1015,8 @@ PoolVector<int> TileMap::_get_tile_data() const { data.resize(tile_map.size() * 3); PoolVector<int>::Write w = data.write(); + format = FORMAT_2; + int idx = 0; for (const Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) { uint8_t *ptr = (uint8_t *)&w[idx]; @@ -1298,7 +1297,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "format") { - r_ret = FORMAT_2_1_5; + r_ret = FORMAT_2; return true; } else if (p_name == "tile_data") { r_ret = _get_tile_data(); @@ -1594,7 +1593,7 @@ TileMap::TileMap() { y_sort_mode = false; occluder_light_mask = 1; clip_uv = false; - format = FORMAT_2_1_4; //Always initialize with the lowest format + format = FORMAT_1; //Always initialize with the lowest format fp_adjust = 0.00001; tile_origin = TILE_ORIGIN_TOP_LEFT; diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index edc9de0543..11d9915cb6 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -61,8 +61,8 @@ public: private: enum DataFormat { - FORMAT_2_1_4 = 0, - FORMAT_2_1_5 + FORMAT_1 = 0, + FORMAT_2 }; Ref<TileSet> tile_set; @@ -178,7 +178,7 @@ private: float bounce; uint32_t collision_layer; uint32_t collision_mask; - DataFormat format; + mutable DataFormat format; TileOrigin tile_origin; diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 8e2f87738a..1f2b43165e 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -1284,8 +1284,11 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { _create_debug_mesh(&baker); } else { - Ref<GIProbeData> probe_data; - probe_data.instance(); + Ref<GIProbeData> probe_data = get_probe_data(); + + if (probe_data.is_null()) + probe_data.instance(); + probe_data->set_bounds(AABB(-extents, extents * 2.0)); probe_data->set_cell_size(baker.po2_bounds.size[longest_axis] / baker.axis_cell_size[longest_axis]); probe_data->set_dynamic_data(data); diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index c137b7e8ff..821f1a5a78 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -1189,7 +1189,7 @@ void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags[p_flag] = p_enable; _queue_shader_change(); - if (p_flag==FLAG_DISABLE_Z) { + if (p_flag == FLAG_DISABLE_Z) { _change_notify(); } } @@ -1379,7 +1379,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { } if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { - property.usage=0; + property.usage = 0; } } diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index f2f00bb617..8c9f59e267 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -734,15 +734,31 @@ bool RigidBody::is_contact_monitor_enabled() const { return contact_monitor != NULL; } -void RigidBody::set_axis_lock(AxisLock p_lock) { +void RigidBody::set_axis_lock_x(bool p_lock) { + RigidBody::locked_axis[0] = p_lock; + PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), 0, locked_axis[0]); +} + +void RigidBody::set_axis_lock_y(bool p_lock) { + RigidBody::locked_axis[1] = p_lock; + PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), 1, locked_axis[1]); +} + +void RigidBody::set_axis_lock_z(bool p_lock) { + RigidBody::locked_axis[2] = p_lock; + PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), 2, locked_axis[2]); +} - axis_lock = p_lock; - PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), PhysicsServer::BodyAxisLock(axis_lock)); +bool RigidBody::get_axis_lock_x() const { + return RigidBody::locked_axis[0]; } -RigidBody::AxisLock RigidBody::get_axis_lock() const { +bool RigidBody::get_axis_lock_y() const { + return RigidBody::locked_axis[1]; +} - return axis_lock; +bool RigidBody::get_axis_lock_z() const { + return RigidBody::locked_axis[2]; } Array RigidBody::get_colliding_bodies() const { @@ -837,8 +853,12 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("_body_enter_tree"), &RigidBody::_body_enter_tree); ClassDB::bind_method(D_METHOD("_body_exit_tree"), &RigidBody::_body_exit_tree); - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis_lock"), &RigidBody::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock"), &RigidBody::get_axis_lock); + ClassDB::bind_method(D_METHOD("set_axis_lock_x", "axis_lock_x"), &RigidBody::set_axis_lock_x); + ClassDB::bind_method(D_METHOD("set_axis_lock_y", "axis_lock_y"), &RigidBody::set_axis_lock_y); + ClassDB::bind_method(D_METHOD("set_axis_lock_z", "axis_lock_z"), &RigidBody::set_axis_lock_z); + ClassDB::bind_method(D_METHOD("get_axis_lock_x"), &RigidBody::get_axis_lock_x); + ClassDB::bind_method(D_METHOD("get_axis_lock_y"), &RigidBody::get_axis_lock_y); + ClassDB::bind_method(D_METHOD("get_axis_lock_z"), &RigidBody::get_axis_lock_z); ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody::get_colliding_bodies); @@ -856,7 +876,10 @@ void RigidBody::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_lock", PROPERTY_HINT_ENUM, "Disabled,Lock X,Lock Y,Lock Z"), "set_axis_lock", "get_axis_lock"); + ADD_GROUP("Axis Lock", "axis_lock_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "axis_lock_x"), "set_axis_lock_x", "get_axis_lock_x"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "axis_lock_y"), "set_axis_lock_y", "get_axis_lock_y"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "axis_lock_z"), "set_axis_lock_z", "get_axis_lock_z"); ADD_GROUP("Linear", "linear_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "-1,128,0.01"), "set_linear_damp", "get_linear_damp"); @@ -874,11 +897,6 @@ void RigidBody::_bind_methods() { BIND_ENUM_CONSTANT(MODE_STATIC); BIND_ENUM_CONSTANT(MODE_CHARACTER); BIND_ENUM_CONSTANT(MODE_KINEMATIC); - - BIND_ENUM_CONSTANT(AXIS_LOCK_DISABLED); - BIND_ENUM_CONSTANT(AXIS_LOCK_X); - BIND_ENUM_CONSTANT(AXIS_LOCK_Y); - BIND_ENUM_CONSTANT(AXIS_LOCK_Z); } RigidBody::RigidBody() : @@ -904,8 +922,6 @@ RigidBody::RigidBody() : contact_monitor = NULL; can_sleep = true; - axis_lock = AXIS_LOCK_DISABLED; - PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); } @@ -952,6 +968,12 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_colli r_collision.local_shape = result.collision_local_shape; } + for (int i = 0; i < 3; i++) { + if (locked_axis[i]) { + result.motion[i] = 0; + } + } + gt.origin += result.motion; set_global_transform(gt); @@ -960,9 +982,16 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_colli Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) { - Vector3 motion = (floor_velocity + p_linear_velocity) * get_physics_process_delta_time(); Vector3 lv = p_linear_velocity; + for (int i = 0; i < 3; i++) { + if (locked_axis[i]) { + lv[i] = 0; + } + } + + Vector3 motion = (floor_velocity + lv) * get_physics_process_delta_time(); + on_floor = false; on_ceiling = false; on_wall = false; @@ -1008,6 +1037,12 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve motion = motion.slide(n); lv = lv.slide(n); + for (int i = 0; i < 3; i++) { + if (locked_axis[i]) { + lv[i] = 0; + } + } + colliders.push_back(collision); } else { @@ -1047,6 +1082,33 @@ bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion) return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion); } +void KinematicBody::set_axis_lock_x(bool p_lock) { + KinematicBody::locked_axis[0] = p_lock; + PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), 0, locked_axis[0]); +} + +void KinematicBody::set_axis_lock_y(bool p_lock) { + KinematicBody::locked_axis[1] = p_lock; + PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), 1, locked_axis[1]); +} + +void KinematicBody::set_axis_lock_z(bool p_lock) { + KinematicBody::locked_axis[2] = p_lock; + PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), 2, locked_axis[2]); +} + +bool KinematicBody::get_axis_lock_x() const { + return KinematicBody::locked_axis[0]; +} + +bool KinematicBody::get_axis_lock_y() const { + return KinematicBody::locked_axis[1]; +} + +bool KinematicBody::get_axis_lock_z() const { + return KinematicBody::locked_axis[2]; +} + void KinematicBody::set_safe_margin(float p_margin) { margin = p_margin; @@ -1095,12 +1157,24 @@ void KinematicBody::_bind_methods() { ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody::is_on_wall); ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody::get_floor_velocity); + ClassDB::bind_method(D_METHOD("set_axis_lock_x", "axis_lock_x"), &KinematicBody::set_axis_lock_x); + ClassDB::bind_method(D_METHOD("set_axis_lock_y", "axis_lock_y"), &KinematicBody::set_axis_lock_y); + ClassDB::bind_method(D_METHOD("set_axis_lock_z", "axis_lock_z"), &KinematicBody::set_axis_lock_z); + ClassDB::bind_method(D_METHOD("get_axis_lock_x"), &KinematicBody::get_axis_lock_x); + ClassDB::bind_method(D_METHOD("get_axis_lock_y"), &KinematicBody::get_axis_lock_y); + ClassDB::bind_method(D_METHOD("get_axis_lock_z"), &KinematicBody::get_axis_lock_z); + ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody::get_safe_margin); ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count); ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision); + ADD_GROUP("Axis Lock", "axis_lock_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "axis_lock_x"), "set_axis_lock_x", "get_axis_lock_x"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "axis_lock_y"), "set_axis_lock_y", "get_axis_lock_y"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "axis_lock_z"), "set_axis_lock_z", "get_axis_lock_z"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); } diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index f88b3860dc..57b120ef63 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -114,13 +114,6 @@ public: MODE_KINEMATIC, }; - enum AxisLock { - AXIS_LOCK_DISABLED, - AXIS_LOCK_X, - AXIS_LOCK_Y, - AXIS_LOCK_Z, - }; - private: bool can_sleep; PhysicsDirectBodyState *state; @@ -139,7 +132,7 @@ private: bool sleeping; bool ccd; - AxisLock axis_lock; + bool locked_axis[3] = { false, false, false }; int max_contacts_reported; @@ -245,8 +238,12 @@ public: void set_use_continuous_collision_detection(bool p_enable); bool is_using_continuous_collision_detection() const; - void set_axis_lock(AxisLock p_lock); - AxisLock get_axis_lock() const; + void set_axis_lock_x(bool p_lock); + void set_axis_lock_y(bool p_lock); + void set_axis_lock_z(bool p_lock); + bool get_axis_lock_x() const; + bool get_axis_lock_y() const; + bool get_axis_lock_z() const; Array get_colliding_bodies() const; @@ -259,7 +256,6 @@ public: }; VARIANT_ENUM_CAST(RigidBody::Mode); -VARIANT_ENUM_CAST(RigidBody::AxisLock); class KinematicCollision; @@ -281,6 +277,8 @@ public: }; private: + bool locked_axis[3] = { false, false, false }; + float margin; Vector3 floor_velocity; @@ -303,6 +301,13 @@ public: bool move_and_collide(const Vector3 &p_motion, Collision &r_collision); bool test_move(const Transform &p_from, const Vector3 &p_motion); + void set_axis_lock_x(bool p_lock); + void set_axis_lock_y(bool p_lock); + void set_axis_lock_z(bool p_lock); + bool get_axis_lock_x() const; + bool get_axis_lock_y() const; + bool get_axis_lock_z() const; + void set_safe_margin(float p_margin); float get_safe_margin() const; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index f3e750d0da..e866e665d8 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -364,6 +364,9 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float if (!nc) // no node cache for this track, skip it continue; + if (!a->track_is_enabled(i)) + continue; // do nothing if the track is disabled + if (a->track_get_key_count(i) == 0) continue; // do nothing if track is empty @@ -1325,8 +1328,6 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false)); ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance); - ClassDB::bind_method(D_METHOD("get_anim_position"), &AnimationPlayer::get_current_animation_position); - ClassDB::bind_method(D_METHOD("get_anim_length"), &AnimationPlayer::get_current_animation_length); ClassDB::bind_method(D_METHOD("find_animation", "animation"), &AnimationPlayer::find_animation); @@ -1335,6 +1336,9 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation_process_mode", "mode"), &AnimationPlayer::set_animation_process_mode); ClassDB::bind_method(D_METHOD("get_animation_process_mode"), &AnimationPlayer::get_animation_process_mode); + ClassDB::bind_method(D_METHOD("get_current_animation_position"), &AnimationPlayer::get_current_animation_position); + ClassDB::bind_method(D_METHOD("get_current_animation_length"), &AnimationPlayer::get_current_animation_length); + ADD_GROUP("Playback Options", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); @@ -1343,7 +1347,7 @@ void AnimationPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "autoplay"), "set_autoplay", "get_autoplay"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_anim"), "set_current_anim", "get_current_anim"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_animation"), "set_current_animation", "get_current_animation"); ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 23eccec82f..32f82fe6b8 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -831,7 +831,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) { for (List<AnimationNode::TrackRef>::Element *E = anim_list->tref.front(); E; E = E->next()) { AnimationNode::TrackRef &tr = E->get(); - if (tr.track == NULL || tr.local_track < 0 || tr.weight < CMP_EPSILON) + if (tr.track == NULL || tr.local_track < 0 || tr.weight < CMP_EPSILON || !a->track_is_enabled(tr.local_track)) continue; switch (a->track_get_type(tr.local_track)) { @@ -1796,6 +1796,10 @@ void AnimationTreePlayer::_bind_methods() { ADD_GROUP("Playback", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "master_player"), "set_master_player", "get_master_player"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "base_path"), "set_base_path", "get_base_path"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); + BIND_ENUM_CONSTANT(NODE_OUTPUT); BIND_ENUM_CONSTANT(NODE_ANIMATION); BIND_ENUM_CONSTANT(NODE_ONESHOT); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index adca78d1d4..81d2b6731f 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2470,6 +2470,16 @@ Control::MouseFilter Control::get_mouse_filter() const { return data.mouse_filter; } +void Control::set_pass_on_modal_close_click(bool p_pass_on) { + + data.pass_on_modal_close_click = p_pass_on; +} + +bool Control::pass_on_modal_close_click() const { + + return data.pass_on_modal_close_click; +} + Control *Control::get_focus_owner() const { ERR_FAIL_COND_V(!is_inside_tree(), NULL); @@ -2934,6 +2944,7 @@ Control::Control() { data.parent = NULL; data.mouse_filter = MOUSE_FILTER_STOP; + data.pass_on_modal_close_click = true; data.SI = NULL; data.MI = NULL; diff --git a/scene/gui/control.h b/scene/gui/control.h index 92d1c969fc..9ac0eb0be3 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -165,6 +165,8 @@ private: bool pending_min_size_update; Point2 custom_minimum_size; + bool pass_on_modal_close_click; + MouseFilter mouse_filter; bool clip_contents; @@ -401,6 +403,9 @@ public: void set_mouse_filter(MouseFilter p_filter); MouseFilter get_mouse_filter() const; + void set_pass_on_modal_close_click(bool p_pass_on); + bool pass_on_modal_close_click() const; + /* SKINNING */ void add_icon_override(const StringName &p_name, const Ref<Texture> &p_icon); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 8af499fd96..6af869c503 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -603,6 +603,14 @@ void FileDialog::set_current_path(const String &p_path) { } } +void FileDialog::set_mode_overrides_title(bool p_override) { + mode_overrides_title = p_override; +} + +bool FileDialog::is_mode_overriding_title() const { + return mode_overrides_title; +} + void FileDialog::set_mode(Mode p_mode) { mode = p_mode; @@ -610,27 +618,32 @@ void FileDialog::set_mode(Mode p_mode) { case MODE_OPEN_FILE: get_ok()->set_text(RTR("Open")); - set_title(RTR("Open a File")); + if (mode_overrides_title) + set_title(RTR("Open a File")); makedir->hide(); break; case MODE_OPEN_FILES: get_ok()->set_text(RTR("Open")); - set_title(RTR("Open File(s)")); + if (mode_overrides_title) + set_title(RTR("Open File(s)")); makedir->hide(); break; case MODE_OPEN_DIR: get_ok()->set_text(RTR("Select Current Folder")); - set_title(RTR("Open a Directory")); + if (mode_overrides_title) + set_title(RTR("Open a Directory")); makedir->show(); break; case MODE_OPEN_ANY: get_ok()->set_text(RTR("Open")); - set_title(RTR("Open a File or Directory")); + if (mode_overrides_title) + set_title(RTR("Open a File or Directory")); makedir->show(); break; case MODE_SAVE_FILE: get_ok()->set_text(RTR("Save")); - set_title(RTR("Save a File")); + if (mode_overrides_title) + set_title(RTR("Save a File")); makedir->show(); break; } @@ -760,6 +773,8 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("set_current_dir", "dir"), &FileDialog::set_current_dir); ClassDB::bind_method(D_METHOD("set_current_file", "file"), &FileDialog::set_current_file); ClassDB::bind_method(D_METHOD("set_current_path", "path"), &FileDialog::set_current_path); + ClassDB::bind_method(D_METHOD("set_mode_overrides_title", "override"), &FileDialog::set_mode_overrides_title); + ClassDB::bind_method(D_METHOD("is_mode_overriding_title"), &FileDialog::is_mode_overriding_title); ClassDB::bind_method(D_METHOD("set_mode", "mode"), &FileDialog::set_mode); ClassDB::bind_method(D_METHOD("get_mode"), &FileDialog::get_mode); ClassDB::bind_method(D_METHOD("get_vbox"), &FileDialog::get_vbox); @@ -791,6 +806,7 @@ void FileDialog::_bind_methods() { BIND_ENUM_CONSTANT(ACCESS_USERDATA); BIND_ENUM_CONSTANT(ACCESS_FILESYSTEM); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access"); ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "filters"), "set_filters", "get_filters"); @@ -814,6 +830,8 @@ FileDialog::FileDialog() { show_hidden_files = default_show_hidden_files; + mode_overrides_title = true; + VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index ca3d9f54b2..c8c1f23105 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -92,6 +92,8 @@ private: Vector<String> filters; + bool mode_overrides_title; + static bool default_show_hidden_files; bool show_hidden_files; @@ -143,6 +145,9 @@ public: void set_current_file(const String &p_file); void set_current_path(const String &p_path); + void set_mode_overrides_title(bool p_override); + bool is_mode_overriding_title() const; + void set_mode(Mode p_mode); Mode get_mode() const; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index ac450616d6..d850553957 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -111,6 +111,7 @@ MenuButton::MenuButton() { popup->hide(); add_child(popup); popup->set_as_toplevel(true); + popup->set_pass_on_modal_close_click(false); connect("button_up", popup, "call_deferred", make_binds("grab_click_focus")); set_process_unhandled_key_input(true); set_action_mode(ACTION_MODE_BUTTON_PRESS); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index b4d0799945..70f3d9ca83 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -323,6 +323,7 @@ OptionButton::OptionButton() { popup = memnew(PopupMenu); popup->hide(); popup->set_as_toplevel(true); + popup->set_pass_on_modal_close_click(false); add_child(popup); popup->connect("id_pressed", this, "_selected"); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 4ee6f93c9a..e37cdd5cc9 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -624,6 +624,20 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo update(); } +void PopupMenu::add_statable_item(const String &p_label, int p_max_states, int p_default_state, int p_ID, uint32_t p_accel) { + + Item item; + item.text = p_label; + item.xl_text = tr(p_label); + item.accel = p_accel; + item.ID = p_ID; + item.checkable = false; + item.max_states = p_max_states; + item.state = p_default_state; + items.push_back(item); + update(); +} + void PopupMenu::set_item_text(int p_idx, const String &p_text) { ERR_FAIL_INDEX(p_idx, items.size()); @@ -772,6 +786,11 @@ Ref<ShortCut> PopupMenu::get_item_shortcut(int p_idx) const { return items[p_idx].shortcut; } +int PopupMenu::get_item_state(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, items.size(), -1); + return items[p_idx].state; +} + void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { ERR_FAIL_INDEX(p_idx, items.size()); @@ -820,6 +839,27 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { update(); } +void PopupMenu::set_item_statable(int p_idx, int p_state) { + + ERR_FAIL_INDEX(p_idx, items.size()); + items[p_idx].state = p_state; + update(); +} + +void PopupMenu::toggle_item_statable(int p_idx) { + + ERR_FAIL_INDEX(p_idx, items.size()); + if (0 >= items[p_idx].max_states) { + return; + } + + ++items[p_idx].state; + if (items[p_idx].max_states <= items[p_idx].state) + items[p_idx].state = 0; + + update(); +} + bool PopupMenu::is_item_checkable(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, items.size(), false); return items[p_idx].checkable; @@ -895,21 +935,34 @@ void PopupMenu::activate_item(int p_item) { while (pop) { // We close all parents that are chained together, // with hide_on_item_selection enabled - if ((items[p_item].checkable && hide_on_checkable_item_selection && pop->is_hide_on_checkable_item_selection()) || (!items[p_item].checkable && hide_on_item_selection && pop->is_hide_on_item_selection())) { - pop->hide(); - next = next->get_parent(); - pop = Object::cast_to<PopupMenu>(next); - } else { - // Break out of loop when the next parent has - // hide_on_item_selection disabled + + if (items[p_item].checkable) { + if (!hide_on_checkable_item_selection || !pop->is_hide_on_checkable_item_selection()) + break; + } else if (0 < items[p_item].max_states) { + if (!hide_on_statable_item_selection || !pop->is_hide_on_statable_item_selection()) + break; + } else if (!hide_on_item_selection || !pop->is_hide_on_item_selection()) break; - } + + pop->hide(); + next = next->get_parent(); + pop = Object::cast_to<PopupMenu>(next); } + // Hides popup by default; unless otherwise specified // by using set_hide_on_item_selection and set_hide_on_checkable_item_selection - if ((items[p_item].checkable && hide_on_checkable_item_selection) || (!items[p_item].checkable && hide_on_item_selection)) { - hide(); - } + + if (items[p_item].checkable) { + if (!hide_on_checkable_item_selection) + return; + } else if (0 < items[p_item].max_states) { + if (!hide_on_statable_item_selection) + return; + } else if (!hide_on_item_selection) + return; + + hide(); } void PopupMenu::remove_item(int p_idx) { @@ -1025,7 +1078,7 @@ void PopupMenu::set_hide_on_item_selection(bool p_enabled) { hide_on_item_selection = p_enabled; } -bool PopupMenu::is_hide_on_item_selection() { +bool PopupMenu::is_hide_on_item_selection() const { return hide_on_item_selection; } @@ -1035,11 +1088,21 @@ void PopupMenu::set_hide_on_checkable_item_selection(bool p_enabled) { hide_on_checkable_item_selection = p_enabled; } -bool PopupMenu::is_hide_on_checkable_item_selection() { +bool PopupMenu::is_hide_on_checkable_item_selection() const { return hide_on_checkable_item_selection; } +void PopupMenu::set_hide_on_statable_item_selection(bool p_enabled) { + + hide_on_statable_item_selection = p_enabled; +} + +bool PopupMenu::is_hide_on_statable_item_selection() const { + + return hide_on_statable_item_selection; +} + String PopupMenu::get_tooltip(const Point2 &p_pos) const { int over = _get_mouse_over(p_pos); @@ -1098,8 +1161,10 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_as_checkable", "idx", "enable"), &PopupMenu::set_item_as_checkable); ClassDB::bind_method(D_METHOD("set_item_tooltip", "idx", "tooltip"), &PopupMenu::set_item_tooltip); ClassDB::bind_method(D_METHOD("set_item_shortcut", "idx", "shortcut", "global"), &PopupMenu::set_item_shortcut, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_item_statable", "idx", "state"), &PopupMenu::set_item_statable); ClassDB::bind_method(D_METHOD("toggle_item_checked", "idx"), &PopupMenu::toggle_item_checked); + ClassDB::bind_method(D_METHOD("toggle_item_statable", "idx"), &PopupMenu::toggle_item_statable); ClassDB::bind_method(D_METHOD("get_item_text", "idx"), &PopupMenu::get_item_text); ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &PopupMenu::get_item_icon); @@ -1131,6 +1196,9 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hide_on_checkable_item_selection", "enable"), &PopupMenu::set_hide_on_checkable_item_selection); ClassDB::bind_method(D_METHOD("is_hide_on_checkable_item_selection"), &PopupMenu::is_hide_on_checkable_item_selection); + ClassDB::bind_method(D_METHOD("set_hide_on_state_item_selection", "enable"), &PopupMenu::set_hide_on_statable_item_selection); + ClassDB::bind_method(D_METHOD("is_hide_on_state_item_selection"), &PopupMenu::is_hide_on_statable_item_selection); + ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items"); @@ -1154,6 +1222,7 @@ PopupMenu::PopupMenu() { set_as_toplevel(true); set_hide_on_item_selection(true); set_hide_on_checkable_item_selection(true); + set_hide_on_statable_item_selection(false); submenu_timer = memnew(Timer); submenu_timer->set_wait_time(0.3); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index c9e9c8e311..5a10bf0765 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -46,6 +46,8 @@ class PopupMenu : public Popup { String xl_text; bool checked; bool checkable; + int max_states; + int state; bool separator; bool disabled; int ID; @@ -62,6 +64,8 @@ class PopupMenu : public Popup { checked = false; checkable = false; separator = false; + max_states = 0; + state = 0; accel = 0; disabled = false; _ofs_cache = 0; @@ -86,6 +90,7 @@ class PopupMenu : public Popup { bool invalidated_click; bool hide_on_item_selection; bool hide_on_checkable_item_selection; + bool hide_on_statable_item_selection; Vector2 moved; Array _get_items() const; @@ -115,6 +120,8 @@ public: void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false); + void add_statable_item(const String &p_label, int p_max_states, int p_default_state, int p_ID = -1, uint32_t p_accel = 0); + void set_item_text(int p_idx, const String &p_text); void set_item_icon(int p_idx, const Ref<Texture> &p_icon); void set_item_checked(int p_idx, bool p_checked); @@ -128,6 +135,8 @@ public: void set_item_tooltip(int p_idx, const String &p_tooltip); void set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global = false); void set_item_h_offset(int p_idx, int p_offset); + void set_item_statable(int p_idx, int p_state); + void toggle_item_statable(int p_idx); void toggle_item_checked(int p_idx); @@ -145,6 +154,7 @@ public: bool is_item_checkable(int p_idx) const; String get_item_tooltip(int p_idx) const; Ref<ShortCut> get_item_shortcut(int p_idx) const; + int get_item_state(int p_idx) const; int get_item_count() const; @@ -168,10 +178,13 @@ public: void set_invalidate_click_until_motion(); void set_hide_on_item_selection(bool p_enabled); - bool is_hide_on_item_selection(); + bool is_hide_on_item_selection() const; void set_hide_on_checkable_item_selection(bool p_enabled); - bool is_hide_on_checkable_item_selection(); + bool is_hide_on_checkable_item_selection() const; + + void set_hide_on_statable_item_selection(bool p_enabled); + bool is_hide_on_statable_item_selection() const; PopupMenu(); ~PopupMenu(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 7ff85716a5..e5169089f2 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -4646,6 +4646,16 @@ void TextEdit::unfold_line(int p_line) { update(); } +void TextEdit::toggle_fold_line(int p_line) { + + ERR_FAIL_INDEX(p_line, text.size()); + + if (!is_folded(p_line)) + fold_line(p_line); + else + unfold_line(p_line); +} + int TextEdit::get_line_count() const { return text.size(); @@ -5461,6 +5471,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines); ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line); ClassDB::bind_method(D_METHOD("unfold_line", "line"), &TextEdit::unfold_line); + ClassDB::bind_method(D_METHOD("toggle_fold_line", "line"), &TextEdit::toggle_fold_line); ClassDB::bind_method(D_METHOD("can_fold", "line"), &TextEdit::can_fold); ClassDB::bind_method(D_METHOD("is_folded", "line"), &TextEdit::is_folded); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index e5dc2da7c7..dd305d5822 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -436,6 +436,7 @@ public: bool is_folded(int p_line) const; void fold_line(int p_line); void unfold_line(int p_line); + void toggle_fold_line(int p_line); String get_text(); String get_line(int line) const; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index a785abbc65..4635de81e8 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1269,12 +1269,9 @@ Transform2D Viewport::_get_input_pre_xform() const { Vector2 Viewport::_get_window_offset() const { - /* - if (parent_control) { - return (parent_control->get_viewport()->get_final_transform() * parent_control->get_global_transform_with_canvas()).get_origin(); + if (get_parent() && get_parent()->has_method("get_global_position")) { + return get_parent()->call("get_global_position"); } - */ - return Vector2(); } @@ -1649,6 +1646,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } else { + bool is_handled = false; + _gui_sort_modal_stack(); while (!gui.modal_stack.empty()) { @@ -1666,11 +1665,20 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { top->notification(Control::NOTIFICATION_MODAL_CLOSE); top->_modal_stack_remove(); top->hide(); + + if (!top->pass_on_modal_close_click()) { + is_handled = true; + } } else { break; } } + if (is_handled) { + get_tree()->set_input_as_handled(); + return; + } + //Matrix32 parent_xform; /* diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index ebbd2d35c3..4544549f94 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -77,6 +77,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { track_set_interpolation_loop_wrap(track, p_value); else if (what == "imported") track_set_imported(track, p_value); + else if (what == "enabled") + track_set_enabled(track, p_value); else if (what == "keys" || what == "key_values") { if (track_get_type(track) == TYPE_TRANSFORM) { @@ -247,6 +249,8 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { r_ret = track_get_interpolation_loop_wrap(track); else if (what == "imported") r_ret = track_is_imported(track); + else if (what == "enabled") + r_ret = track_is_enabled(track); else if (what == "keys") { if (track_get_type(track) == TYPE_TRANSFORM) { @@ -391,6 +395,7 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "tracks/" + itos(i) + "/interp", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/loop_wrap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/imported", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::ARRAY, "tracks/" + itos(i) + "/keys", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); } } @@ -1575,6 +1580,19 @@ bool Animation::track_is_imported(int p_track) const { return tracks[p_track]->imported; } +void Animation::track_set_enabled(int p_track, bool p_enabled) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + tracks[p_track]->enabled = p_enabled; + emit_changed(); +} + +bool Animation::track_is_enabled(int p_track) const { + + ERR_FAIL_INDEX_V(p_track, tracks.size(), false); + return tracks[p_track]->enabled; +} + void Animation::track_move_down(int p_track) { if (p_track > 0 && p_track < tracks.size()) { @@ -1603,6 +1621,7 @@ void Animation::copy_track(int src_track, Ref<Animation> p_to_animation) { p_to_animation->track_set_path(dst_track, track_get_path(src_track)); p_to_animation->track_set_imported(dst_track, track_is_imported(src_track)); + p_to_animation->track_set_enabled(dst_track, track_is_enabled(src_track)); p_to_animation->track_set_interpolation_type(dst_track, track_get_interpolation_type(src_track)); p_to_animation->track_set_interpolation_loop_wrap(dst_track, track_get_interpolation_loop_wrap(src_track)); for (int i = 0; i < track_get_key_count(src_track); i++) { @@ -1626,6 +1645,9 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_set_imported", "idx", "imported"), &Animation::track_set_imported); ClassDB::bind_method(D_METHOD("track_is_imported", "idx"), &Animation::track_is_imported); + ClassDB::bind_method(D_METHOD("track_set_enabled", "idx", "enabled"), &Animation::track_set_enabled); + ClassDB::bind_method(D_METHOD("track_is_enabled", "idx"), &Animation::track_is_enabled); + ClassDB::bind_method(D_METHOD("transform_track_insert_key", "idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key); ClassDB::bind_method(D_METHOD("track_insert_key", "idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1)); ClassDB::bind_method(D_METHOD("track_remove_key", "idx", "key_idx"), &Animation::track_remove_key); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index c96beeb01f..1f468b29b5 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -67,10 +67,12 @@ private: bool loop_wrap; NodePath path; // path to something bool imported; + bool enabled; Track() { interpolation = INTERPOLATION_LINEAR; imported = false; loop_wrap = true; + enabled = true; } virtual ~Track() {} }; @@ -239,6 +241,9 @@ public: void track_set_imported(int p_track, bool p_imported); bool track_is_imported(int p_track) const; + void track_set_enabled(int p_track, bool p_enabled); + bool track_is_enabled(int p_track) const; + int transform_track_insert_key(int p_track, float p_time, const Vector3 p_loc, const Quat &p_rot = Quat(), const Vector3 &p_scale = Vector3()); void track_insert_key(int p_track, float p_time, const Variant &p_key, float p_transition = 1); void track_set_key_transition(int p_track, int p_key_idx, float p_transition); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 0a886c25b1..0b352efca2 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -28,10 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "mesh.h" + +#include "pair.h" #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/convex_polygon_shape.h" #include "surface_tool.h" +#include <stdlib.h> + void Mesh::_clear_triangle_mesh() const { triangle_mesh.unref(); @@ -413,8 +417,21 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const { return newmesh; } +void Mesh::set_lightmap_size_hint(const Vector2 &p_size) { + lightmap_size_hint = p_size; +} + +Size2 Mesh::get_lightmap_size_hint() const { + return lightmap_size_hint; +} + void Mesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &Mesh::set_lightmap_size_hint); + ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &Mesh::get_lightmap_size_hint); + + ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint"); + BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); @@ -1035,6 +1052,200 @@ void ArrayMesh::regen_normalmaps() { } } +//dirty hack +bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = NULL; + +struct ArrayMeshLightmapSurface { + + Ref<Material> material; + Vector<SurfaceTool::Vertex> vertices; + Mesh::PrimitiveType primitive; + uint32_t format; +}; + +Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) { + + ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED); + ERR_EXPLAIN("Can't unwrap mesh with blend shapes"); + ERR_FAIL_COND_V(blend_shapes.size() != 0, ERR_UNAVAILABLE); + + Vector<float> vertices; + Vector<float> normals; + Vector<int> indices; + Vector<int> face_materials; + Vector<float> uv; + Vector<Pair<int, int> > uv_index; + + Vector<ArrayMeshLightmapSurface> surfaces; + for (int i = 0; i < get_surface_count(); i++) { + ArrayMeshLightmapSurface s; + s.primitive = surface_get_primitive_type(i); + + if (s.primitive != Mesh::PRIMITIVE_TRIANGLES) { + ERR_EXPLAIN("Only triangles are supported for lightmap unwrap"); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + s.format = surface_get_format(i); + if (!(s.format & ARRAY_FORMAT_NORMAL)) { + ERR_EXPLAIN("Normals are required for lightmap unwrap"); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + + Array arrays = surface_get_arrays(i); + s.material = surface_get_material(i); + s.vertices = SurfaceTool::create_vertex_array_from_triangle_arrays(arrays); + + PoolVector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX]; + int vc = rvertices.size(); + PoolVector<Vector3>::Read r = rvertices.read(); + + PoolVector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL]; + PoolVector<Vector3>::Read rn = rnormals.read(); + + int vertex_ofs = vertices.size() / 3; + + vertices.resize((vertex_ofs + vc) * 3); + normals.resize((vertex_ofs + vc) * 3); + uv_index.resize(vertex_ofs + vc); + + for (int j = 0; j < vc; j++) { + + Vector3 v = p_base_transform.xform(r[j]); + + vertices[(j + vertex_ofs) * 3 + 0] = v.x; + vertices[(j + vertex_ofs) * 3 + 1] = v.y; + vertices[(j + vertex_ofs) * 3 + 2] = v.z; + normals[(j + vertex_ofs) * 3 + 0] = rn[j].x; + normals[(j + vertex_ofs) * 3 + 1] = rn[j].y; + normals[(j + vertex_ofs) * 3 + 2] = rn[j].z; + uv_index[j + vertex_ofs] = Pair<int, int>(i, j); + } + + PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX]; + int ic = rindices.size(); + int index_ofs = indices.size(); + + if (ic == 0) { + indices.resize(index_ofs + vc); + face_materials.resize((index_ofs + vc) / 3); + for (int j = 0; j < vc; j++) { + indices[index_ofs + j] = vertex_ofs + j; + } + for (int j = 0; j < vc / 3; j++) { + face_materials[(index_ofs / 3) + j] = i; + } + + } else { + PoolVector<int>::Read ri = rindices.read(); + indices.resize(index_ofs + ic); + face_materials.resize((index_ofs + ic) / 3); + for (int j = 0; j < ic; j++) { + indices[index_ofs + j] = vertex_ofs + ri[j]; + } + for (int j = 0; j < ic / 3; j++) { + face_materials[(index_ofs / 3) + j] = i; + } + } + + surfaces.push_back(s); + } + + //unwrap + + float *gen_uvs; + int *gen_vertices; + int *gen_indices; + int gen_vertex_count; + int gen_index_count; + int size_x; + int size_y; + + bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), face_materials.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y); + + if (!ok) { + return ERR_CANT_CREATE; + } + + //remove surfaces + while (get_surface_count()) { + surface_remove(0); + } + + //create surfacetools for each surface.. + Vector<Ref<SurfaceTool> > surfaces_tools; + + for (int i = 0; i < surfaces.size(); i++) { + Ref<SurfaceTool> st; + st.instance(); + st->begin(Mesh::PRIMITIVE_TRIANGLES); + st->set_material(surfaces[i].material); + surfaces_tools.push_back(st); //stay there + } + + print_line("gen indices: " + itos(gen_index_count)); + //go through all indices + for (int i = 0; i < gen_index_count; i += 3) { + + ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_index.size(), ERR_BUG); + ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_index.size(), ERR_BUG); + ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_index.size(), ERR_BUG); + + ERR_FAIL_COND_V(uv_index[gen_vertices[gen_indices[i + 0]]].first != uv_index[gen_vertices[gen_indices[i + 1]]].first || uv_index[gen_vertices[gen_indices[i + 0]]].first != uv_index[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG); + + int surface = uv_index[gen_vertices[gen_indices[i + 0]]].first; + + for (int j = 0; j < 3; j++) { + + int vertex_idx = gen_vertices[gen_indices[i + j]]; + + SurfaceTool::Vertex v = surfaces[surface].vertices[uv_index[gen_vertices[gen_indices[i + j]]].second]; + + if (surfaces[surface].format & ARRAY_FORMAT_COLOR) { + surfaces_tools[surface]->add_color(v.color); + } + if (surfaces[surface].format & ARRAY_FORMAT_TEX_UV) { + surfaces_tools[surface]->add_uv(v.uv); + } + if (surfaces[surface].format & ARRAY_FORMAT_NORMAL) { + surfaces_tools[surface]->add_normal(v.normal); + } + if (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[surface]->add_tangent(t); + } + if (surfaces[surface].format & ARRAY_FORMAT_BONES) { + surfaces_tools[surface]->add_bones(v.bones); + } + if (surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) { + surfaces_tools[surface]->add_weights(v.weights); + } + + Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]); + surfaces_tools[surface]->add_uv2(uv2); + + surfaces_tools[surface]->add_vertex(v.vertex); + } + } + + //free stuff + ::free(gen_vertices); + ::free(gen_indices); + ::free(gen_uvs); + + //generate surfaces + + for (int i = 0; i < surfaces_tools.size(); i++) { + surfaces_tools[i]->index(); + surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), surfaces[i].format); + } + + set_lightmap_size_hint(Size2(size_x, size_y)); + + return OK; +} + void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index b85a6a84af..ea38ebf2ff 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -43,6 +43,8 @@ class Mesh : public Resource { GDCLASS(Mesh, Resource); mutable Ref<TriangleMesh> triangle_mesh; //cached + Size2 lightmap_size_hint; + protected: void _clear_triangle_mesh() const; @@ -138,6 +140,9 @@ public: virtual AABB get_aabb() const = 0; + void set_lightmap_size_hint(const Vector2 &p_size); + Size2 get_lightmap_size_hint() const; + Mesh(); }; @@ -216,6 +221,8 @@ public: void center_geometry(); void regen_normalmaps(); + Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); + virtual void reload_from_file(); ArrayMesh(); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index bf89e704bc..d8600e041d 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -101,6 +101,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) { vtx.color = last_color; vtx.normal = last_normal; vtx.uv = last_uv; + vtx.uv2 = last_uv2; vtx.weights = last_weights; vtx.bones = last_bones; vtx.tangent = last_tangent.normal; @@ -401,7 +402,7 @@ Array SurfaceTool::commit_to_arrays() { return a; } -Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) { +Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_flags) { Ref<ArrayMesh> mesh; if (p_existing.is_valid()) @@ -418,7 +419,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) { Array a = commit_to_arrays(); - mesh->add_surface_from_arrays(primitive, a); + mesh->add_surface_from_arrays(primitive, a, Array(), p_flags); if (material.is_valid()) mesh->surface_set_material(surface, material); @@ -482,6 +483,113 @@ void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List< _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; + + PoolVector<Vector3> varr = p_arrays[VS::ARRAY_VERTEX]; + PoolVector<Vector3> narr = p_arrays[VS::ARRAY_NORMAL]; + PoolVector<float> tarr = p_arrays[VS::ARRAY_TANGENT]; + PoolVector<Color> carr = p_arrays[VS::ARRAY_COLOR]; + PoolVector<Vector2> uvarr = p_arrays[VS::ARRAY_TEX_UV]; + PoolVector<Vector2> uv2arr = p_arrays[VS::ARRAY_TEX_UV2]; + PoolVector<int> barr = p_arrays[VS::ARRAY_BONES]; + PoolVector<float> warr = p_arrays[VS::ARRAY_WEIGHTS]; + + int vc = varr.size(); + + if (vc == 0) + return ret; + int lformat = 0; + + PoolVector<Vector3>::Read rv; + if (varr.size()) { + lformat |= VS::ARRAY_FORMAT_VERTEX; + rv = varr.read(); + } + PoolVector<Vector3>::Read rn; + if (narr.size()) { + lformat |= VS::ARRAY_FORMAT_NORMAL; + rn = narr.read(); + } + PoolVector<float>::Read rt; + if (tarr.size()) { + lformat |= VS::ARRAY_FORMAT_TANGENT; + rt = tarr.read(); + } + PoolVector<Color>::Read rc; + if (carr.size()) { + lformat |= VS::ARRAY_FORMAT_COLOR; + rc = carr.read(); + } + + PoolVector<Vector2>::Read ruv; + if (uvarr.size()) { + lformat |= VS::ARRAY_FORMAT_TEX_UV; + ruv = uvarr.read(); + } + + PoolVector<Vector2>::Read ruv2; + if (uv2arr.size()) { + lformat |= VS::ARRAY_FORMAT_TEX_UV2; + ruv2 = uv2arr.read(); + } + + PoolVector<int>::Read rb; + if (barr.size()) { + lformat |= VS::ARRAY_FORMAT_BONES; + rb = barr.read(); + } + + PoolVector<float>::Read rw; + if (warr.size()) { + lformat |= VS::ARRAY_FORMAT_WEIGHTS; + rw = warr.read(); + } + + for (int i = 0; i < vc; i++) { + + Vertex v; + if (lformat & VS::ARRAY_FORMAT_VERTEX) + v.vertex = varr[i]; + if (lformat & VS::ARRAY_FORMAT_NORMAL) + v.normal = narr[i]; + if (lformat & VS::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; + } + if (lformat & VS::ARRAY_FORMAT_COLOR) + v.color = carr[i]; + if (lformat & VS::ARRAY_FORMAT_TEX_UV) + v.uv = uvarr[i]; + if (lformat & VS::ARRAY_FORMAT_TEX_UV2) + v.uv2 = uv2arr[i]; + if (lformat & VS::ARRAY_FORMAT_BONES) { + Vector<int> b; + b.resize(4); + b[0] = barr[i * 4 + 0]; + b[1] = barr[i * 4 + 1]; + b[2] = barr[i * 4 + 2]; + b[3] = barr[i * 4 + 3]; + v.bones = b; + } + if (lformat & VS::ARRAY_FORMAT_WEIGHTS) { + Vector<float> w; + w.resize(4); + w[0] = warr[i * 4 + 0]; + w[1] = warr[i * 4 + 1]; + w[2] = warr[i * 4 + 2]; + w[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) { PoolVector<Vector3> varr = arr[VS::ARRAY_VERTEX]; @@ -882,7 +990,7 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from); ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from); - ClassDB::bind_method(D_METHOD("commit", "existing"), &SurfaceTool::commit, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT)); } SurfaceTool::SurfaceTool() { diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index cdaac643de..b180ffe260 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -127,10 +127,11 @@ public: List<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); Array commit_to_arrays(); void create_from(const Ref<Mesh> &p_existing, int p_surface); 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>()); + Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT); SurfaceTool(); }; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 6fab597d2b..1a46353fe3 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -83,7 +83,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { } } } else if (what == "occluder_map") { - tile_map[id].autotile_data.ocludder_map.clear(); + tile_map[id].autotile_data.occluder_map.clear(); Array p = p_value; Vector2 last_coord; while (p.size() > 0) { @@ -194,7 +194,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = p; } else if (what == "occluder_map") { Array p; - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = tile_map[id].autotile_data.ocludder_map.front(); E; E = E->next()) { + for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = tile_map[id].autotile_data.occluder_map.front(); E; E = E->next()) { p.push_back(E->key()); p.push_back(E->value()); } @@ -643,20 +643,20 @@ Ref<OccluderPolygon2D> TileSet::tile_get_light_occluder(int p_id) const { void TileSet::autotile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> &p_light_occluder, const Vector2 &p_coord) { ERR_FAIL_COND(!tile_map.has(p_id)); if (p_light_occluder.is_null()) { - if (tile_map[p_id].autotile_data.ocludder_map.has(p_coord)) { - tile_map[p_id].autotile_data.ocludder_map.erase(p_coord); + if (tile_map[p_id].autotile_data.occluder_map.has(p_coord)) { + tile_map[p_id].autotile_data.occluder_map.erase(p_coord); } } else { - tile_map[p_id].autotile_data.ocludder_map[p_coord] = p_light_occluder; + tile_map[p_id].autotile_data.occluder_map[p_coord] = p_light_occluder; } } Ref<OccluderPolygon2D> TileSet::autotile_get_light_occluder(int p_id, const Vector2 &p_coord) const { ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<OccluderPolygon2D>()); - if (!tile_map[p_id].autotile_data.ocludder_map.has(p_coord)) { + if (!tile_map[p_id].autotile_data.occluder_map.has(p_coord)) { return Ref<OccluderPolygon2D>(); } else { - return tile_map[p_id].autotile_data.ocludder_map[p_coord]; + return tile_map[p_id].autotile_data.occluder_map[p_coord]; } } @@ -688,7 +688,7 @@ const Map<Vector2, Ref<OccluderPolygon2D> > &TileSet::autotile_get_light_oclusio static Map<Vector2, Ref<OccluderPolygon2D> > dummy; ERR_FAIL_COND_V(!tile_map.has(p_id), dummy); - return tile_map[p_id].autotile_data.ocludder_map; + return tile_map[p_id].autotile_data.occluder_map; } void TileSet::autotile_set_navigation_polygon(int p_id, const Ref<NavigationPolygon> &p_navigation_polygon, const Vector2 &p_coord) { diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 4d2b02f54b..deac583f62 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -76,7 +76,7 @@ public: Size2 size; Vector2 icon_coord; Map<Vector2, uint16_t> flags; - Map<Vector2, Ref<OccluderPolygon2D> > ocludder_map; + Map<Vector2, Ref<OccluderPolygon2D> > occluder_map; Map<Vector2, Ref<NavigationPolygon> > navpoly_map; Map<Vector2, int> priority_map; diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index 5057c6ab9d..bba4d7a147 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -559,32 +559,30 @@ void BodySW::integrate_velocities(real_t p_step) { if (fi_callback) get_space()->body_add_to_state_query_list(&direct_state_query_list); - if (mode == PhysicsServer::BODY_MODE_KINEMATIC) { - - _set_transform(new_transform, false); - _set_inv_transform(new_transform.affine_inverse()); - if (contacts.size() == 0 && linear_velocity == Vector3() && angular_velocity == Vector3()) - set_active(false); //stopped moving, deactivate - - return; - } - //apply axis lock - if (axis_lock != PhysicsServer::BODY_AXIS_LOCK_DISABLED) { - - int axis = axis_lock - 1; + if (locked_axis[0] || locked_axis[1] || locked_axis[2]) { for (int i = 0; i < 3; i++) { - if (i == axis) { + if (locked_axis[i]) { linear_velocity[i] = 0; biased_linear_velocity[i] = 0; + new_transform.origin[i] = get_transform().origin[i]; } else { - angular_velocity[i] = 0; biased_angular_velocity[i] = 0; } } } + if (mode == PhysicsServer::BODY_MODE_KINEMATIC) { + + _set_transform(new_transform, false); + _set_inv_transform(new_transform.affine_inverse()); + if (contacts.size() == 0 && linear_velocity == Vector3() && angular_velocity == Vector3()) + set_active(false); //stopped moving, deactivate + + return; + } + Vector3 total_angular_velocity = angular_velocity + biased_angular_velocity; real_t ang_vel = total_angular_velocity.length(); @@ -775,7 +773,6 @@ BodySW::BodySW() : continuous_cd = false; can_sleep = false; fi_callback = NULL; - axis_lock = PhysicsServer::BODY_AXIS_LOCK_DISABLED; } BodySW::~BodySW() { diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h index 738d99c764..aab6def1a9 100644 --- a/servers/physics/body_sw.h +++ b/servers/physics/body_sw.h @@ -53,7 +53,7 @@ class BodySW : public CollisionObjectSW { real_t angular_damp; real_t gravity_scale; - PhysicsServer::BodyAxisLock axis_lock; + bool locked_axis[3] = { false, false, false }; real_t kinematic_safe_margin; real_t _inv_mass; @@ -288,8 +288,8 @@ public: _FORCE_INLINE_ Vector3 get_gravity() const { return gravity; } _FORCE_INLINE_ real_t get_bounce() const { return bounce; } - _FORCE_INLINE_ void set_axis_lock(PhysicsServer::BodyAxisLock p_lock) { axis_lock = p_lock; } - _FORCE_INLINE_ PhysicsServer::BodyAxisLock get_axis_lock() const { return axis_lock; } + _FORCE_INLINE_ void set_axis_lock(int axis, bool lock) { locked_axis[axis] = lock; } + _FORCE_INLINE_ bool get_axis_lock() const { return locked_axis; } void integrate_forces(real_t p_step); void integrate_velocities(real_t p_step); diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index ce63d84617..2909308366 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -794,19 +794,19 @@ void PhysicsServerSW::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_v body->wakeup(); }; -void PhysicsServerSW::body_set_axis_lock(RID p_body, BodyAxisLock p_lock) { +void PhysicsServerSW::body_set_axis_lock(RID p_body, int axis, bool lock) { BodySW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); - body->set_axis_lock(p_lock); + body->set_axis_lock(axis, lock); body->wakeup(); } -PhysicsServerSW::BodyAxisLock PhysicsServerSW::body_get_axis_lock(RID p_body) const { +bool PhysicsServerSW::body_get_axis_lock(RID p_body) const { const BodySW *body = body_owner.get(p_body); - ERR_FAIL_COND_V(!body, BODY_AXIS_LOCK_DISABLED); + ERR_FAIL_COND_V(!body, 0); return body->get_axis_lock(); } diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index fa754a1c8f..fea6e34ebd 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -203,8 +203,8 @@ public: virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity); - virtual void body_set_axis_lock(RID p_body, BodyAxisLock p_lock); - virtual BodyAxisLock body_get_axis_lock(RID p_body) const; + virtual void body_set_axis_lock(RID p_body, int axis, bool p_lock); + virtual bool body_get_axis_lock(RID p_body) const; virtual void body_add_collision_exception(RID p_body, RID p_body_b); virtual void body_remove_collision_exception(RID p_body, RID p_body_b); diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index f693622ede..9a9b20bf28 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -472,7 +472,7 @@ void PhysicsServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &PhysicsServer::body_apply_torque_impulse); ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &PhysicsServer::body_set_axis_velocity); - ClassDB::bind_method(D_METHOD("body_set_axis_lock", "body", "axis"), &PhysicsServer::body_set_axis_lock); + ClassDB::bind_method(D_METHOD("body_set_axis_lock", "body", "axis", "lock"), &PhysicsServer::body_set_axis_lock); ClassDB::bind_method(D_METHOD("body_get_axis_lock", "body"), &PhysicsServer::body_get_axis_lock); ClassDB::bind_method(D_METHOD("body_add_collision_exception", "body", "excepted_body"), &PhysicsServer::body_add_collision_exception); @@ -702,11 +702,6 @@ void PhysicsServer::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); - - BIND_ENUM_CONSTANT(BODY_AXIS_LOCK_DISABLED); - BIND_ENUM_CONSTANT(BODY_AXIS_LOCK_X); - BIND_ENUM_CONSTANT(BODY_AXIS_LOCK_Y); - BIND_ENUM_CONSTANT(BODY_AXIS_LOCK_Z); } PhysicsServer::PhysicsServer() { diff --git a/servers/physics_server.h b/servers/physics_server.h index 4886317224..66c3a0afc4 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -421,15 +421,8 @@ public: virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) = 0; virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) = 0; - enum BodyAxisLock { - BODY_AXIS_LOCK_DISABLED, - BODY_AXIS_LOCK_X, - BODY_AXIS_LOCK_Y, - BODY_AXIS_LOCK_Z, - }; - - virtual void body_set_axis_lock(RID p_body, BodyAxisLock p_lock) = 0; - virtual BodyAxisLock body_get_axis_lock(RID p_body) const = 0; + virtual void body_set_axis_lock(RID p_body, int axis, bool lock) = 0; + virtual bool body_get_axis_lock(RID p_body) const = 0; //fix virtual void body_add_collision_exception(RID p_body, RID p_body_b) = 0; @@ -692,7 +685,6 @@ VARIANT_ENUM_CAST(PhysicsServer::AreaSpaceOverrideMode); VARIANT_ENUM_CAST(PhysicsServer::BodyMode); VARIANT_ENUM_CAST(PhysicsServer::BodyParameter); VARIANT_ENUM_CAST(PhysicsServer::BodyState); -VARIANT_ENUM_CAST(PhysicsServer::BodyAxisLock); VARIANT_ENUM_CAST(PhysicsServer::PinJointParam); VARIANT_ENUM_CAST(PhysicsServer::JointType); VARIANT_ENUM_CAST(PhysicsServer::HingeJointParam); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 0ee70878dc..df41c3b5ce 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -636,6 +636,7 @@ public: struct CommandPolyLine : public Command { bool antialiased; + bool multiline; Vector<Point2> triangles; Vector<Color> triangle_colors; Vector<Point2> lines; @@ -643,6 +644,7 @@ public: CommandPolyLine() { type = TYPE_POLYLINE; antialiased = false; + multiline = false; } }; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 4de902af58..e10a57c571 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -254,6 +254,9 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_TYPE_ISAMPLER2D, "isampler2D" }, { TK_TYPE_USAMPLER2D, "usampler2D" }, { TK_TYPE_SAMPLERCUBE, "samplerCube" }, + { TK_INTERPOLATION_FLAT, "flat" }, + { TK_INTERPOLATION_NO_PERSPECTIVE, "noperspective" }, + { TK_INTERPOLATION_SMOOTH, "smooth" }, { TK_PRECISION_LOW, "lowp" }, { TK_PRECISION_MID, "mediump" }, { TK_PRECISION_HIGH, "highp" }, @@ -658,6 +661,24 @@ ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) { return DataType(p_type - TK_TYPE_VOID); } +bool ShaderLanguage::is_token_interpolation(TokenType p_type) { + + return ( + p_type == TK_INTERPOLATION_FLAT || + p_type == TK_INTERPOLATION_NO_PERSPECTIVE || + p_type == TK_INTERPOLATION_SMOOTH); +} + +ShaderLanguage::DataInterpolation ShaderLanguage::get_token_interpolation(TokenType p_type) { + + if (p_type == TK_INTERPOLATION_FLAT) + return INTERPOLATION_FLAT; + else if (p_type == TK_INTERPOLATION_NO_PERSPECTIVE) + return INTERPOLATION_NO_PERSPECTIVE; + else + return INTERPOLATION_SMOOTH; +} + bool ShaderLanguage::is_token_precision(TokenType p_type) { return ( @@ -3576,10 +3597,16 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct bool uniform = tk.type == TK_UNIFORM; DataPrecision precision = PRECISION_DEFAULT; + DataInterpolation interpolation = INTERPOLATION_SMOOTH; DataType type; StringName name; tk = _get_token(); + if (is_token_interpolation(tk.type)) { + interpolation = get_token_interpolation(tk.type); + tk = _get_token(); + } + if (is_token_precision(tk.type)) { precision = get_token_precision(tk.type); tk = _get_token(); @@ -3777,6 +3804,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct ShaderNode::Varying varying; varying.type = type; varying.precission = precision; + varying.interpolation = interpolation; shader->varyings[name] = varying; tk = _get_token(); diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 7a7f6dd71c..e092bf931f 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -72,6 +72,9 @@ public: TK_TYPE_ISAMPLER2D, TK_TYPE_USAMPLER2D, TK_TYPE_SAMPLERCUBE, + TK_INTERPOLATION_FLAT, + TK_INTERPOLATION_NO_PERSPECTIVE, + TK_INTERPOLATION_SMOOTH, TK_PRECISION_LOW, TK_PRECISION_MID, TK_PRECISION_HIGH, @@ -192,6 +195,12 @@ public: PRECISION_DEFAULT, }; + enum DataInterpolation { + INTERPOLATION_FLAT, + INTERPOLATION_NO_PERSPECTIVE, + INTERPOLATION_SMOOTH, + }; + enum Operator { OP_EQUAL, OP_NOT_EQUAL, @@ -431,6 +440,7 @@ public: struct Varying { DataType type; + DataInterpolation interpolation; DataPrecision precission; }; @@ -511,6 +521,8 @@ public: static bool is_token_datatype(TokenType p_type); static DataType get_token_datatype(TokenType p_type); + static bool is_token_interpolation(TokenType p_type); + static DataInterpolation get_token_interpolation(TokenType p_type); static bool is_token_precision(TokenType p_type); static DataPrecision get_token_precision(TokenType p_type); static String get_datatype_name(DataType p_type); diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 31c09dc23d..0fed9cc961 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -416,6 +416,7 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point ERR_FAIL_COND(!pline); pline->antialiased = p_antialiased; + pline->multiline = false; if (p_width <= 1) { pline->lines = p_points; @@ -486,6 +487,90 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point canvas_item->commands.push_back(pline); } +void VisualServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { + + ERR_FAIL_COND(p_points.size() < 2); + Item *canvas_item = canvas_item_owner.getornull(p_item); + ERR_FAIL_COND(!canvas_item); + + Item::CommandPolyLine *pline = memnew(Item::CommandPolyLine); + ERR_FAIL_COND(!pline); + + pline->antialiased = false; //todo + pline->multiline = true; + + // if (p_width <= 1) { + pline->lines = p_points; + pline->line_colors = p_colors; + if (pline->line_colors.size() == 0) { + pline->line_colors.push_back(Color(1, 1, 1, 1)); + } else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) { + pline->line_colors.resize(1); + } +#if 0 +//width not yet + } else { + //make a trianglestrip for drawing the line... + Vector2 prev_t; + pline->triangles.resize(p_points.size() * 2); + if (p_antialiased) { + pline->lines.resize(p_points.size() * 2); + } + + if (p_colors.size() == 0) { + pline->triangle_colors.push_back(Color(1, 1, 1, 1)); + if (p_antialiased) { + pline->line_colors.push_back(Color(1, 1, 1, 1)); + } + } + if (p_colors.size() == 1) { + pline->triangle_colors = p_colors; + pline->line_colors = p_colors; + } else { + pline->triangle_colors.resize(pline->triangles.size()); + pline->line_colors.resize(pline->lines.size()); + } + + for (int i = 0; i < p_points.size(); i++) { + + Vector2 t; + if (i == p_points.size() - 1) { + t = prev_t; + } else { + t = (p_points[i + 1] - p_points[i]).normalized().tangent(); + if (i == 0) { + prev_t = t; + } + } + + Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + + if (p_antialiased) { + pline->lines[i] = p_points[i] + tangent; + pline->lines[p_points.size() * 2 - i - 1] = p_points[i] - tangent; + if (pline->line_colors.size() > 1) { + pline->line_colors[i] = p_colors[i]; + pline->line_colors[p_points.size() * 2 - i - 1] = p_colors[i]; + } + } + + pline->triangles[i * 2 + 0] = p_points[i] + tangent; + pline->triangles[i * 2 + 1] = p_points[i] - tangent; + + if (pline->triangle_colors.size() > 1) { + + pline->triangle_colors[i * 2 + 0] = p_colors[i]; + pline->triangle_colors[i * 2 + 1] = p_colors[i]; + } + + prev_t = t; + } + } +#endif + canvas_item->rect_dirty = true; + canvas_item->commands.push_back(pline); +} + void VisualServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index a92370f1f0..3143ac847f 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -172,6 +172,7 @@ public: void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); + void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 9223d81e32..d843c443a2 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -551,6 +551,7 @@ public: BIND6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool) BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) + BIND5(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &) BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) BIND7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index eef4720d22..dde69eedd3 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -2283,7 +2283,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co if (angle > light_cache.spot_angle) continue; - float d = CLAMP(angle / light_cache.spot_angle, 1, 0); + float d = CLAMP(angle / light_cache.spot_angle, 0, 1); att *= powf(1.0 - d, light_cache.spot_attenuation); } diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index b58b1d917e..94f450c024 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -467,6 +467,7 @@ public: FUNC6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool) FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) + FUNC5(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &) FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) FUNC7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID) diff --git a/servers/visual_server.h b/servers/visual_server.h index 350097c1b5..de5ef7da0a 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -815,6 +815,7 @@ public: virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; + virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()) = 0; diff --git a/thirdparty/thekla_atlas/nvmesh/param/Atlas.cpp b/thirdparty/thekla_atlas/nvmesh/param/Atlas.cpp index 4e41e76695..98f92cef96 100644 --- a/thirdparty/thekla_atlas/nvmesh/param/Atlas.cpp +++ b/thirdparty/thekla_atlas/nvmesh/param/Atlas.cpp @@ -38,6 +38,7 @@ using namespace nv; /// Ctor. Atlas::Atlas() { + failed=false; } // Dtor. @@ -100,6 +101,7 @@ void Atlas::extractCharts(const HalfEdge::Mesh * mesh) void Atlas::computeCharts(const HalfEdge::Mesh * mesh, const SegmentationSettings & settings, const Array<uint> & unchartedMaterialArray) { + failed=false; MeshCharts * meshCharts = new MeshCharts(mesh); meshCharts->computeCharts(settings, unchartedMaterialArray); addMeshCharts(meshCharts); @@ -235,6 +237,8 @@ float Atlas::packCharts(int quality, float texelsPerUnit, bool blockAlign, bool { AtlasPacker packer(this); packer.packCharts(quality, texelsPerUnit, blockAlign, conservative); + if (hasFailed()) + return 0; return packer.computeAtlasUtilization(); } diff --git a/thirdparty/thekla_atlas/nvmesh/param/Atlas.h b/thirdparty/thekla_atlas/nvmesh/param/Atlas.h index 8b478207e3..41cfaea9cb 100644 --- a/thirdparty/thekla_atlas/nvmesh/param/Atlas.h +++ b/thirdparty/thekla_atlas/nvmesh/param/Atlas.h @@ -64,9 +64,12 @@ namespace nv // Pack charts in the smallest possible rectangle. float packCharts(int quality, float texelArea, bool blockAlign, bool conservative); + void setFailed() { failed = true; } + bool hasFailed() const { return failed; } private: + bool failed; Array<MeshCharts *> m_meshChartsArray; }; diff --git a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp index f2156899ae..5ce452cb9e 100644 --- a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp +++ b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp @@ -152,7 +152,7 @@ AtlasPacker::~AtlasPacker() } // This should compute convex hull and use rotating calipers to find the best box. Currently it uses a brute force method. -static void computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * minorAxis, Vector2 * minCorner, Vector2 * maxCorner) +static bool computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * minorAxis, Vector2 * minCorner, Vector2 * maxCorner) { // Compute list of boundary points. Array<Vector2> points(16); @@ -184,6 +184,9 @@ static void computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * min #if 1 Array<Vector2> hull; + if (points.size()==0) { + return false; + } convexHull(points, hull, 0.00001f); @@ -373,6 +376,8 @@ static void computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * min } }*/ #endif + + return true; } @@ -431,7 +436,10 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned // Compute bounding box of chart. Vector2 majorAxis, minorAxis, origin, end; - computeBoundingBox(chart, &majorAxis, &minorAxis, &origin, &end); + if (!computeBoundingBox(chart, &majorAxis, &minorAxis, &origin, &end)) { + m_atlas->setFailed(); + return; + } nvCheck(isFinite(majorAxis) && isFinite(minorAxis) && isFinite(origin)); diff --git a/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp b/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp new file mode 100644 index 0000000000..d6f0accf54 --- /dev/null +++ b/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp @@ -0,0 +1,271 @@ + +#include "thekla_atlas.h" + +#include <cfloat> + +#include "nvmesh/halfedge/Edge.h" +#include "nvmesh/halfedge/Mesh.h" +#include "nvmesh/halfedge/Face.h" +#include "nvmesh/halfedge/Vertex.h" +#include "nvmesh/param/Atlas.h" + +#include "nvmath/Vector.inl" +#include "nvmath/ftoi.h" + +#include "nvcore/Array.inl" + + +using namespace Thekla; +using namespace nv; + + +inline Atlas_Output_Mesh * set_error(Atlas_Error * error, Atlas_Error code) { + if (error) *error = code; + return NULL; +} + + + +static void input_to_mesh(const Atlas_Input_Mesh * input, HalfEdge::Mesh * mesh, Atlas_Error * error) { + + Array<uint> canonicalMap; + canonicalMap.reserve(input->vertex_count); + + for (int i = 0; i < input->vertex_count; i++) { + const Atlas_Input_Vertex & input_vertex = input->vertex_array[i]; + const float * pos = input_vertex.position; + const float * nor = input_vertex.normal; + const float * tex = input_vertex.uv; + + HalfEdge::Vertex * vertex = mesh->addVertex(Vector3(pos[0], pos[1], pos[2])); + vertex->nor.set(nor[0], nor[1], nor[2]); + vertex->tex.set(tex[0], tex[1]); + + canonicalMap.append(input_vertex.first_colocal); + } + + mesh->linkColocalsWithCanonicalMap(canonicalMap); + + + const int face_count = input->face_count; + + int non_manifold_faces = 0; + for (int i = 0; i < face_count; i++) { + const Atlas_Input_Face & input_face = input->face_array[i]; + + int v0 = input_face.vertex_index[0]; + int v1 = input_face.vertex_index[1]; + int v2 = input_face.vertex_index[2]; + + HalfEdge::Face * face = mesh->addFace(v0, v1, v2); + if (face != NULL) { + face->material = input_face.material_index; + } + else { + non_manifold_faces++; + } + } + + mesh->linkBoundary(); + + if (non_manifold_faces != 0 && error != NULL) { + *error = Atlas_Error_Invalid_Mesh_Non_Manifold; + } +} + +static Atlas_Output_Mesh * mesh_atlas_to_output(const HalfEdge::Mesh * mesh, const Atlas & atlas, Atlas_Error * error) { + + Atlas_Output_Mesh * output = new Atlas_Output_Mesh; + + const MeshCharts * charts = atlas.meshAt(0); + + // Allocate vertices. + const int vertex_count = charts->vertexCount(); + output->vertex_count = vertex_count; + output->vertex_array = new Atlas_Output_Vertex[vertex_count]; + + int w = 0; + int h = 0; + + // Output vertices. + const int chart_count = charts->chartCount(); + for (int i = 0; i < chart_count; i++) { + const Chart * chart = charts->chartAt(i); + uint vertexOffset = charts->vertexCountBeforeChartAt(i); + + const uint chart_vertex_count = chart->vertexCount(); + for (uint v = 0; v < chart_vertex_count; v++) { + Atlas_Output_Vertex & output_vertex = output->vertex_array[vertexOffset + v]; + + uint original_vertex = chart->mapChartVertexToOriginalVertex(v); + output_vertex.xref = original_vertex; + + Vector2 uv = chart->chartMesh()->vertexAt(v)->tex; + output_vertex.uv[0] = uv.x; + output_vertex.uv[1] = uv.y; + w = max(w, ftoi_ceil(uv.x)); + h = max(h, ftoi_ceil(uv.y)); + } + } + + const int face_count = mesh->faceCount(); + output->index_count = face_count * 3; + output->index_array = new int[face_count * 3]; + + // Set face indices. + for (int f = 0; f < face_count; f++) { + uint c = charts->faceChartAt(f); + uint i = charts->faceIndexWithinChartAt(f); + uint vertexOffset = charts->vertexCountBeforeChartAt(c); + + const Chart * chart = charts->chartAt(c); + nvDebugCheck(chart->faceAt(i) == f); + + const HalfEdge::Face * face = chart->chartMesh()->faceAt(i); + const HalfEdge::Edge * edge = face->edge; + + output->index_array[3*f+0] = vertexOffset + edge->vertex->id; + output->index_array[3*f+1] = vertexOffset + edge->next->vertex->id; + output->index_array[3*f+2] = vertexOffset + edge->next->next->vertex->id; + } + + *error = Atlas_Error_Success; + output->atlas_width = w; + output->atlas_height = h; + + return output; +} + + +void Thekla::atlas_set_default_options(Atlas_Options * options) { + if (options != NULL) { + // These are the default values we use on The Witness. + + options->charter = Atlas_Charter_Default; + options->charter_options.witness.proxy_fit_metric_weight = 2.0f; + options->charter_options.witness.roundness_metric_weight = 0.01f; + options->charter_options.witness.straightness_metric_weight = 6.0f; + options->charter_options.witness.normal_seam_metric_weight = 4.0f; + options->charter_options.witness.texture_seam_metric_weight = 0.5f; + options->charter_options.witness.max_chart_area = FLT_MAX; + options->charter_options.witness.max_boundary_length = FLT_MAX; + + options->mapper = Atlas_Mapper_Default; + + options->packer = Atlas_Packer_Default; + options->packer_options.witness.packing_quality = 0; + options->packer_options.witness.texel_area = 8; + options->packer_options.witness.block_align = true; + options->packer_options.witness.conservative = false; + } +} + + +Atlas_Output_Mesh * Thekla::atlas_generate(const Atlas_Input_Mesh * input, const Atlas_Options * options, Atlas_Error * error) { + // Validate args. + if (input == NULL || options == NULL || error == NULL) return set_error(error, Atlas_Error_Invalid_Args); + + // Validate options. + if (options->charter != Atlas_Charter_Witness) { + return set_error(error, Atlas_Error_Invalid_Options); + } + if (options->charter == Atlas_Charter_Witness) { + // @@ Validate input options! + } + + if (options->mapper != Atlas_Mapper_LSCM) { + return set_error(error, Atlas_Error_Invalid_Options); + } + if (options->mapper == Atlas_Mapper_LSCM) { + // No options. + } + + if (options->packer != Atlas_Packer_Witness) { + return set_error(error, Atlas_Error_Invalid_Options); + } + if (options->packer == Atlas_Packer_Witness) { + // @@ Validate input options! + } + + // Validate input mesh. + for (int i = 0; i < input->face_count; i++) { + int v0 = input->face_array[i].vertex_index[0]; + int v1 = input->face_array[i].vertex_index[1]; + int v2 = input->face_array[i].vertex_index[2]; + + if (v0 < 0 || v0 >= input->vertex_count || + v1 < 0 || v1 >= input->vertex_count || + v2 < 0 || v2 >= input->vertex_count) + { + return set_error(error, Atlas_Error_Invalid_Mesh); + } + } + + + // Build half edge mesh. + AutoPtr<HalfEdge::Mesh> mesh(new HalfEdge::Mesh); + + input_to_mesh(input, mesh.ptr(), error); + + if (*error == Atlas_Error_Invalid_Mesh) { + return NULL; + } + + Atlas atlas; + + // Charter. + if (options->charter == Atlas_Charter_Extract) { + return set_error(error, Atlas_Error_Not_Implemented); + } + else if (options->charter == Atlas_Charter_Witness) { + SegmentationSettings segmentation_settings; + segmentation_settings.proxyFitMetricWeight = options->charter_options.witness.proxy_fit_metric_weight; + segmentation_settings.roundnessMetricWeight = options->charter_options.witness.roundness_metric_weight; + segmentation_settings.straightnessMetricWeight = options->charter_options.witness.straightness_metric_weight; + segmentation_settings.normalSeamMetricWeight = options->charter_options.witness.normal_seam_metric_weight; + segmentation_settings.textureSeamMetricWeight = options->charter_options.witness.texture_seam_metric_weight; + segmentation_settings.maxChartArea = options->charter_options.witness.max_chart_area; + segmentation_settings.maxBoundaryLength = options->charter_options.witness.max_boundary_length; + + Array<uint> uncharted_materials; + atlas.computeCharts(mesh.ptr(), segmentation_settings, uncharted_materials); + } + + if (atlas.hasFailed()) + return NULL; + + // Mapper. + if (options->mapper == Atlas_Mapper_LSCM) { + atlas.parameterizeCharts(); + } + + if (atlas.hasFailed()) + return NULL; + + // Packer. + if (options->packer == Atlas_Packer_Witness) { + int packing_quality = options->packer_options.witness.packing_quality; + float texel_area = options->packer_options.witness.texel_area; + int block_align = options->packer_options.witness.block_align; + int conservative = options->packer_options.witness.conservative; + + /*float utilization =*/ atlas.packCharts(packing_quality, texel_area, block_align, conservative); + } + + if (atlas.hasFailed()) + return NULL; + + + // Build output mesh. + return mesh_atlas_to_output(mesh.ptr(), atlas, error); +} + + +void Thekla::atlas_free(Atlas_Output_Mesh * output) { + if (output != NULL) { + delete [] output->vertex_array; + delete [] output->index_array; + delete output; + } +} + diff --git a/thirdparty/thekla_atlas/thekla/thekla_atlas.h b/thirdparty/thekla_atlas/thekla/thekla_atlas.h new file mode 100644 index 0000000000..1d0716e781 --- /dev/null +++ b/thirdparty/thekla_atlas/thekla/thekla_atlas.h @@ -0,0 +1,116 @@ + +// Thekla Atlas Generator + +namespace Thekla { + +enum Atlas_Charter { + Atlas_Charter_Witness, // Options: threshold + Atlas_Charter_Extract, // Options: --- + Atlas_Charter_Default = Atlas_Charter_Witness +}; + +enum Atlas_Mapper { + Atlas_Mapper_LSCM, // Options: --- + Atlas_Mapper_Default = Atlas_Mapper_LSCM +}; + +enum Atlas_Packer { + Atlas_Packer_Witness, // Options: texel_area + Atlas_Packer_Default = Atlas_Packer_Witness +}; + +struct Atlas_Options { + Atlas_Charter charter; + union { + struct { + float proxy_fit_metric_weight; + float roundness_metric_weight; + float straightness_metric_weight; + float normal_seam_metric_weight; + float texture_seam_metric_weight; + float max_chart_area; + float max_boundary_length; + } witness; + struct { + } extract; + } charter_options; + + Atlas_Mapper mapper; + union { + } mapper_options; + + Atlas_Packer packer; + union { + struct { + int packing_quality; + float texel_area; // This is not really texel area, but 1 / texel width? + bool block_align; // Align charts to 4x4 blocks. + bool conservative; // Pack charts with extra padding. + } witness; + } packer_options; +}; + +struct Atlas_Input_Vertex { + float position[3]; + float normal[3]; + float uv[2]; + int first_colocal; +}; + +struct Atlas_Input_Face { + int vertex_index[3]; + int material_index; +}; + +struct Atlas_Input_Mesh { + int vertex_count; + int face_count; + Atlas_Input_Vertex * vertex_array; + Atlas_Input_Face * face_array; +}; + +struct Atlas_Output_Vertex { + float uv[2]; + int xref; // Index of input vertex from which this output vertex originated. +}; + +struct Atlas_Output_Mesh { + int atlas_width; + int atlas_height; + int vertex_count; + int index_count; + Atlas_Output_Vertex * vertex_array; + int * index_array; +}; + +enum Atlas_Error { + Atlas_Error_Success, + Atlas_Error_Invalid_Args, + Atlas_Error_Invalid_Options, + Atlas_Error_Invalid_Mesh, + Atlas_Error_Invalid_Mesh_Non_Manifold, + Atlas_Error_Not_Implemented, +}; + +void atlas_set_default_options(Atlas_Options * options); + +Atlas_Output_Mesh * atlas_generate(const Atlas_Input_Mesh * input, const Atlas_Options * options, Atlas_Error * error); + +void atlas_free(Atlas_Output_Mesh * output); + + +/* + +Should we represent the input mesh with an opaque structure that simply holds pointers to the user data? That would allow us to avoid having to copy attributes to an intermediate representation. + +struct Atlas_Input_Mesh; + +void mesh_set_vertex_position(Atlas_Input_Mesh * mesh, float * ptr, int stride); +void mesh_set_vertex_normal(Atlas_Input_Mesh * mesh, float * ptr, int stride); +void mesh_set_vertex_uv(Mesh * mesh, float * ptr, int stride); + +void mesh_set_index(Mesh * mesh, int * ptr); +*/ + +} // Thekla namespace + |