diff options
111 files changed, 1746 insertions, 738 deletions
diff --git a/.gitignore b/.gitignore index b347b348a5..0de1e682a0 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,9 @@ bld/ [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* +# Hints for improving IntelliSense, created together with VS project +cpp.hint + #NUNIT *.VisualState.xml TestResult.xml diff --git a/SConstruct b/SConstruct index c3ecdafd45..856994ef15 100644 --- a/SConstruct +++ b/SConstruct @@ -452,6 +452,7 @@ if selected_platform in platform_list: if env['vsproj']: env['CPPPATH'] = [Dir(path) for path in env['CPPPATH']] methods.generate_vs_project(env, GetOption("num_jobs")) + methods.generate_cpp_hint_file("cpp.hint") # Check for the existence of headers conf = Configure(env) diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index e1adb250e7..999befaf67 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -888,9 +888,9 @@ void _OS::dump_resources_to_file(const String &p_file) { OS::get_singleton()->dump_resources_to_file(p_file.utf8().get_data()); } -String _OS::get_data_dir() const { +String _OS::get_user_data_dir() const { - return OS::get_singleton()->get_data_dir(); + return OS::get_singleton()->get_user_data_dir(); }; Error _OS::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) { @@ -1088,7 +1088,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &_OS::get_static_memory_peak_usage); ClassDB::bind_method(D_METHOD("get_dynamic_memory_usage"), &_OS::get_dynamic_memory_usage); - ClassDB::bind_method(D_METHOD("get_data_dir"), &_OS::get_data_dir); + ClassDB::bind_method(D_METHOD("get_user_data_dir"), &_OS::get_user_data_dir); ClassDB::bind_method(D_METHOD("get_system_dir", "dir"), &_OS::get_system_dir); ClassDB::bind_method(D_METHOD("get_unique_id"), &_OS::get_unique_id); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 9be8895443..8163b08d76 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -297,7 +297,7 @@ public: String get_system_dir(SystemDir p_dir) const; - String get_data_dir() const; + String get_user_data_dir() const; void alert(const String &p_alert, const String &p_title = "ALERT!"); diff --git a/core/engine.cpp b/core/engine.cpp index 31abcd62ef..53c7a73b43 100644 --- a/core/engine.cpp +++ b/core/engine.cpp @@ -84,17 +84,17 @@ Dictionary Engine::get_version_info() const { #else dict["patch"] = 0; #endif - dict["status"] = _MKSTR(VERSION_STATUS); - dict["revision"] = _MKSTR(VERSION_REVISION); + dict["status"] = VERSION_STATUS; + dict["build"] = VERSION_BUILD; dict["year"] = VERSION_YEAR; - String hash = String(VERSION_HASH); + String hash = VERSION_HASH; dict["hash"] = hash.length() == 0 ? String("unknown") : hash; String stringver = String(dict["major"]) + "." + String(dict["minor"]); if ((int)dict["patch"] != 0) stringver += "." + String(dict["patch"]); - stringver += "-" + String(dict["status"]) + " (" + String(dict["revision"]) + ")"; + stringver += "-" + String(dict["status"]) + " (" + String(dict["build"]) + ")"; dict["string"] = stringver; return dict; diff --git a/core/image.cpp b/core/image.cpp index 42684e7ea7..422c0e407b 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -757,22 +757,24 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { _copy_internals_from(dst); } -void Image::crop(int p_width, int p_height) { +void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) { if (!_can_modify(format)) { ERR_EXPLAIN("Cannot crop in indexed, compressed or custom image formats."); ERR_FAIL(); } + ERR_FAIL_COND(p_x < 0); + ERR_FAIL_COND(p_y < 0); ERR_FAIL_COND(p_width <= 0); ERR_FAIL_COND(p_height <= 0); - ERR_FAIL_COND(p_width > MAX_WIDTH); - ERR_FAIL_COND(p_height > MAX_HEIGHT); + ERR_FAIL_COND(p_x + p_width > MAX_WIDTH); + ERR_FAIL_COND(p_y + p_height > MAX_HEIGHT); /* to save memory, cropping should be done in-place, however, since this function will most likely either not be used much, or in critical areas, for now it wont, because it's a waste of time. */ - if (p_width == width && p_height == height) + if (p_width == width && p_height == height && p_x == 0 && p_y == 0) return; uint8_t pdata[16]; //largest is 16 @@ -784,9 +786,11 @@ void Image::crop(int p_width, int p_height) { PoolVector<uint8_t>::Read r = data.read(); PoolVector<uint8_t>::Write w = dst.data.write(); - for (int y = 0; y < p_height; y++) { + int m_h = p_y + p_height; + int m_w = p_x + p_width; + for (int y = p_y; y < m_h; y++) { - for (int x = 0; x < p_width; x++) { + for (int x = p_x; x < m_w; x++) { if ((x >= width || y >= height)) { for (uint32_t i = 0; i < pixel_size; i++) @@ -795,7 +799,7 @@ void Image::crop(int p_width, int p_height) { _get_pixelb(x, y, pixel_size, r.ptr(), pdata); } - dst._put_pixelb(x, y, pixel_size, w.ptr(), pdata); + dst._put_pixelb(x - p_x, y - p_y, pixel_size, w.ptr(), pdata); } } } @@ -805,6 +809,11 @@ void Image::crop(int p_width, int p_height) { _copy_internals_from(dst); } +void Image::crop(int p_width, int p_height) { + + crop_from_point(0, 0, p_width, p_height); +} + void Image::flip_y() { if (!_can_modify(format)) { diff --git a/core/image.h b/core/image.h index 27df65a898..24693aa706 100644 --- a/core/image.h +++ b/core/image.h @@ -207,6 +207,7 @@ public: /** * Crop the image to a specific size, if larger, then the image is filled by black */ + void crop_from_point(int p_x, int p_y, int p_width, int p_height); void crop(int p_width, int p_height); void flip_x(); diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index 0875f78478..35e4443f2a 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -38,7 +38,7 @@ String DirAccess::_get_root_path() const { switch (_access_type) { case ACCESS_RESOURCES: return ProjectSettings::get_singleton()->get_resource_path(); - case ACCESS_USERDATA: return OS::get_singleton()->get_data_dir(); + case ACCESS_USERDATA: return OS::get_singleton()->get_user_data_dir(); default: return ""; } @@ -217,7 +217,7 @@ String DirAccess::fix_path(String p_path) const { if (p_path.begins_with("user://")) { - String data_dir = OS::get_singleton()->get_data_dir(); + String data_dir = OS::get_singleton()->get_user_data_dir(); if (data_dir != "") { return p_path.replace_first("user:/", data_dir); diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index fcb3b58fed..5fdd2b9135 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -152,7 +152,7 @@ String FileAccess::fix_path(const String &p_path) const { if (r_path.begins_with("user://")) { - String data_dir = OS::get_singleton()->get_data_dir(); + String data_dir = OS::get_singleton()->get_user_data_dir(); if (data_dir != "") { return r_path.replace("user:/", data_dir); diff --git a/core/os/os.cpp b/core/os/os.cpp index eb5d5be33d..65d0b2e05d 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -33,6 +33,7 @@ #include "input.h" #include "os/file_access.h" #include "project_settings.h" +#include "version_generated.gen.h" #include <stdarg.h> @@ -262,16 +263,7 @@ String OS::get_locale() const { return "en"; } -String OS::get_resource_dir() const { - - return ProjectSettings::get_singleton()->get_resource_path(); -} - -String OS::get_system_dir(SystemDir p_dir) const { - - return "."; -} - +// Helper function used by OS_Unix and OS_Windows String OS::get_safe_application_name() const { String an = ProjectSettings::get_singleton()->get("application/config/name"); Vector<String> invalid_char = String("\\ / : * ? \" < > |").split(" "); @@ -281,11 +273,51 @@ String OS::get_safe_application_name() const { return an; } -String OS::get_data_dir() const { +// Path to data, config, cache, etc. OS-specific folders + +// Get properly capitalized engine name for system paths +String OS::get_godot_dir_name() const { + + // Default to lowercase, so only override when different case is needed + return String(VERSION_SHORT_NAME).to_lower(); +} + +// OS equivalent of XDG_DATA_HOME +String OS::get_data_path() const { + + return "."; +} + +// OS equivalent of XDG_CONFIG_HOME +String OS::get_config_path() const { + + return "."; +} + +// OS equivalent of XDG_CACHE_HOME +String OS::get_cache_path() const { + + return "."; +} + +// OS specific path for user:// +String OS::get_user_data_dir() const { return "."; }; +// Absolute path to res:// +String OS::get_resource_dir() const { + + return ProjectSettings::get_singleton()->get_resource_path(); +} + +// Access system-specific dirs like Documents, Downloads, etc. +String OS::get_system_dir(SystemDir p_dir) const { + + return "."; +} + Error OS::shell_open(String p_uri) { return ERR_UNAVAILABLE; }; @@ -374,9 +406,9 @@ OS::ScreenOrientation OS::get_screen_orientation() const { return (OS::ScreenOrientation)_orientation; } -void OS::_ensure_data_dir() { +void OS::_ensure_user_data_dir() { - String dd = get_data_dir(); + String dd = get_user_data_dir(); DirAccess *da = DirAccess::open(dd); if (da) { memdelete(da); diff --git a/core/os/os.h b/core/os/os.h index faecdb0e07..474cb60627 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -124,7 +124,7 @@ protected: virtual void set_cmdline(const char *p_execpath, const List<String> &p_args); - void _ensure_data_dir(); + void _ensure_user_data_dir(); virtual bool _check_internal_feature_support(const String &p_feature) = 0; public: @@ -200,7 +200,6 @@ public: virtual void set_low_processor_usage_mode(bool p_enabled); virtual bool is_in_low_processor_usage_mode() const; - virtual String get_installed_templates_path() const { return ""; } virtual String get_executable_path() const; virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false) = 0; virtual Error kill(const ProcessID &p_pid) = 0; @@ -334,10 +333,14 @@ public: virtual String get_locale() const; String get_safe_application_name() const; - virtual String get_data_dir() const; - virtual String get_resource_dir() const; + virtual String get_godot_dir_name() const; - virtual Error move_to_trash(const String &p_path) { return FAILED; } + virtual String get_data_path() const; + virtual String get_config_path() const; + virtual String get_cache_path() const; + + virtual String get_user_data_dir() const; + virtual String get_resource_dir() const; enum SystemDir { SYSTEM_DIR_DESKTOP, @@ -352,6 +355,8 @@ public: virtual String get_system_dir(SystemDir p_dir) const; + virtual Error move_to_trash(const String &p_path) { return FAILED; } + virtual void set_no_window_mode(bool p_enable); virtual bool is_no_window_mode_enabled() const; diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 65a6f2b83c..361464ee1f 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -116,7 +116,7 @@ String ProjectSettings::globalize_path(const String &p_path) const { return p_path.replace("res://", ""); } else if (p_path.begins_with("user://")) { - String data_dir = OS::get_singleton()->get_data_dir(); + String data_dir = OS::get_singleton()->get_user_data_dir(); if (data_dir != "") { return p_path.replace("user:/", data_dir); diff --git a/core/version.h b/core/version.h index 7d2c47df6a..b217d82c5d 100644 --- a/core/version.h +++ b/core/version.h @@ -30,8 +30,8 @@ #include "version_generated.gen.h" #ifdef VERSION_PATCH -#define VERSION_MKSTRING "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." _MKSTR(VERSION_PATCH) "." _MKSTR(VERSION_STATUS) "." _MKSTR(VERSION_REVISION) VERSION_MODULE_CONFIG +#define VERSION_MKSTRING "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." _MKSTR(VERSION_PATCH) "." VERSION_STATUS "." VERSION_BUILD VERSION_MODULE_CONFIG #else -#define VERSION_MKSTRING "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." _MKSTR(VERSION_STATUS) "." _MKSTR(VERSION_REVISION) VERSION_MODULE_CONFIG +#define VERSION_MKSTRING "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." VERSION_STATUS "." VERSION_BUILD VERSION_MODULE_CONFIG #endif // VERSION_PATCH -#define VERSION_FULL_NAME "" _MKSTR(VERSION_NAME) " v" VERSION_MKSTRING +#define VERSION_FULL_NAME "" VERSION_NAME " v" VERSION_MKSTRING diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml index ee334e26a2..83a06bcd4d 100644 --- a/doc/classes/AudioServer.xml +++ b/doc/classes/AudioServer.xml @@ -287,7 +287,7 @@ <argument index="1" name="send" type="String"> </argument> <description> - Connects the output of the bus at [code]bus_idx[/code] to the bus named [code]send[/send]. + Connects the output of the bus at [code]bus_idx[/code] to the bus named [code]send[/code]. </description> </method> <method name="set_bus_solo"> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 03871802b7..57966fb74e 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -60,7 +60,7 @@ <argument index="1" name="constant" type="int"> </argument> <description> - Overrides an integer constant in the [theme] resource the node uses. If the [code]constant[code] is invalid, Godot clears the override. See [member Theme.INVALID_CONSTANT] for more information. + Overrides an integer constant in the [Theme] resource the node uses. If the [code]constant[/code] is invalid, Godot clears the override. See [member Theme.INVALID_CONSTANT] for more information. </description> </method> <method name="add_font_override"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index a0e4fdb8e0..e58516d461 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -55,7 +55,7 @@ Get the list of favorite directories for this project. </description> </method> - <method name="get_project_settings_path" qualifiers="const"> + <method name="get_project_settings_dir" qualifiers="const"> <return type="String"> </return> <description> @@ -77,7 +77,7 @@ <description> </description> </method> - <method name="get_settings_path" qualifiers="const"> + <method name="get_settings_dir" qualifiers="const"> <return type="String"> </return> <description> diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index f43bbc2e9d..090e0d7910 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -71,8 +71,8 @@ "minor" - Holds the minor version number as a String "patch" - Holds the patch version number as a String "status" - Holds the status (e.g. "beta", "rc1", "rc2", ... "stable") as a String - "revision" - Holds the revision (e.g. "custom-build") as a String - "string" - major + minor + patch + status + revision in a single String + "build" - Holds the build name (e.g. "custom-build") as a String + "string" - major + minor + patch + status + build in a single String </description> </method> <method name="has_singleton" qualifiers="const"> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 4f8da7af9e..b6eb26ce8c 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -377,13 +377,13 @@ </argument> <description> Sets the [Color] of the pixel at [code](x, y)[/code] if the image is unlocked. Example: - [code] + [codeblock] var img = Image.new() img.lock() img.set_pixel(x, y, color) # Does not have an effect img.unlock() img.set_pixel(x, y, color) # Works - [/code]. + [/codeblock] </description> </method> <method name="shrink_x2"> diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml index 1cebed7efc..e4404fc258 100644 --- a/doc/classes/InputEvent.xml +++ b/doc/classes/InputEvent.xml @@ -18,7 +18,7 @@ <argument index="0" name="event" type="InputEvent"> </argument> <description> - Returns [code]true[/code] if this event matches [code]event[event]. + Returns [code]true[/code] if this event matches [code]event[/code]. </description> </method> <method name="as_text" qualifiers="const"> diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml index 13d3a14511..383f8360fb 100644 --- a/doc/classes/InputEventAction.xml +++ b/doc/classes/InputEventAction.xml @@ -4,7 +4,7 @@ Input event type for actions. </brief_description> <description> - Contains a generic action which can be targeted from several type of inputs. Actions can be created from the project settings menu [code]Project > Project Settings > Input Map[/Code]. See [method Node._input]. + Contains a generic action which can be targeted from several type of inputs. Actions can be created from the project settings menu [code]Project > Project Settings > Input Map[/code]. See [method Node._input]. </description> <tutorials> http://docs.godotengine.org/en/stable/learning/features/inputs/inputevent.html#actions diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml index a04b9e78ae..d5a1d85def 100644 --- a/doc/classes/InputMap.xml +++ b/doc/classes/InputMap.xml @@ -4,7 +4,7 @@ Singleton that manages [InputEventAction]. </brief_description> <description> - Manages all [InputEventAction] which can be created/modified from the project settings menu [code]Project > Project Settings > Input Map[/Code] or in code with [method add_action] and [method action_add_event]. See [method Node._input]. + Manages all [InputEventAction] which can be created/modified from the project settings menu [code]Project > Project Settings > Input Map[/code] or in code with [method add_action] and [method action_add_event]. See [method Node._input]. </description> <tutorials> http://docs.godotengine.org/en/stable/learning/features/inputs/inputevent.html#inputmap diff --git a/doc/classes/KinematicBody.xml b/doc/classes/KinematicBody.xml index b827db474d..a423974753 100644 --- a/doc/classes/KinematicBody.xml +++ b/doc/classes/KinematicBody.xml @@ -32,7 +32,7 @@ <argument index="0" name="slide_idx" type="int"> </argument> <description> - Returns a [KinematicCollision], which contains information about a collision that occured during the last [method move_and_slide] call. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count]()-1). + Returns a [KinematicCollision], which contains information about a collision that occured during the last [method move_and_slide] call. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1). </description> </method> <method name="get_slide_count" qualifiers="const"> diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml index 264e414ad4..7285c780e5 100644 --- a/doc/classes/KinematicBody2D.xml +++ b/doc/classes/KinematicBody2D.xml @@ -32,7 +32,7 @@ <argument index="0" name="slide_idx" type="int"> </argument> <description> - Returns a [KinematicCollision2D], which contains information about a collision that occured during the last [method move_and_slide] call. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count]()-1). + Returns a [KinematicCollision2D], which contains information about a collision that occured during the last [method move_and_slide] call. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1). </description> </method> <method name="get_slide_count" qualifiers="const"> diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml index f49a806f0e..7b76d94c95 100644 --- a/doc/classes/Line2D.xml +++ b/doc/classes/Line2D.xml @@ -63,7 +63,7 @@ <argument index="0" name="i" type="int"> </argument> <description> - Returns point [code]i[code]'s position. + Returns point [code]i[/code]'s position. </description> </method> <method name="get_points" qualifiers="const"> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index db70b99de4..8f82040eca 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -127,11 +127,11 @@ Returns the current screen index (0 padded). </description> </method> - <method name="get_data_dir" qualifiers="const"> + <method name="get_user_data_dir" qualifiers="const"> <return type="String"> </return> <description> - Returns the absolute directory path of user data path([user://]). + Returns the absolute directory path where user data is written ([code]user://[/code]). </description> </method> <method name="get_date" qualifiers="const"> diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index d3ddbaddca..cd0108019b 100644 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -207,6 +207,7 @@ def rstize_text(text, cclass): elif cmd == '/code': tag_text = '``' inside_code = False + escape_post = True elif inside_code: tag_text = '[' + tag_text + ']' elif cmd.find('html') == 0: diff --git a/drivers/SCsub b/drivers/SCsub index 34d6254578..938927f3a9 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -34,7 +34,12 @@ if env['tools']: SConscript("convex_decomp/SCsub") if env['vsproj']: + import os + path = os.getcwd() + # Change directory so the path resolves correctly in the function call. + os.chdir("..") env.AddToVSProject(env.drivers_sources) + os.chdir(path) if env.split_drivers: env.split_lib("drivers") diff --git a/drivers/gl_context/context_gl.cpp b/drivers/gl_context/context_gl.cpp index a453eef227..1581512369 100644 --- a/drivers/gl_context/context_gl.cpp +++ b/drivers/gl_context/context_gl.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "context_gl.h" -#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED) +#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) ContextGL *ContextGL::singleton = NULL; diff --git a/drivers/gl_context/context_gl.h b/drivers/gl_context/context_gl.h index 399657eb52..3496f2948c 100644 --- a/drivers/gl_context/context_gl.h +++ b/drivers/gl_context/context_gl.h @@ -30,7 +30,7 @@ #ifndef CONTEXT_GL_H #define CONTEXT_GL_H -#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED) +#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) #include "typedefs.h" diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 42a253bc2d..308a18aa9d 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -149,13 +149,6 @@ void RasterizerCanvasGLES3::canvas_begin() { storage->frame.clear_request = false; } - /*canvas_shader.unbind(); - canvas_shader.set_custom_shader(0); - canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false); - canvas_shader.bind(); - canvas_shader.set_uniform(CanvasShaderGLES2::TEXTURE, 0); - canvas_use_modulate=false;*/ - reset_canvas(); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_TEXTURE_RECT, true); @@ -911,61 +904,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } } -#if 0 -void RasterizerGLES2::_canvas_item_setup_shader_params(ShaderMaterial *material,Shader* shader) { - - if (canvas_shader.bind()) - rebind_texpixel_size=true; - - if (material->shader_version!=shader->version) { - //todo optimize uniforms - material->shader_version=shader->version; - } - - if (shader->has_texscreen && framebuffer.active) { - - int x = viewport.x; - int y = window_size.height-(viewport.height+viewport.y); - - canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height)); - canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height)); - canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,max_texture_units-1); - glActiveTexture(GL_TEXTURE0+max_texture_units-1); - glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color); - if (framebuffer.scale==1 && !canvas_texscreen_used) { -#ifdef GLEW_ENABLED - if (current_rt) { - glReadBuffer(GL_COLOR_ATTACHMENT0); - } else { - glReadBuffer(GL_BACK); - } -#endif - if (current_rt) { - glCopyTexSubImage2D(GL_TEXTURE_2D,0,viewport.x,viewport.y,viewport.x,viewport.y,viewport.width,viewport.height); - canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(viewport.y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height)); - //window_size.height-(viewport.height+viewport.y) - } else { - glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height); - } - - canvas_texscreen_used=true; - } - - glActiveTexture(GL_TEXTURE0); - - } - - if (shader->has_screen_uv) { - canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height)); - } - - - uses_texpixel_size=shader->uses_texpixel_size; - -} - -#endif - void RasterizerCanvasGLES3::_copy_texscreen(const Rect2 &p_rect) { glDisable(GL_BLEND); diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 220a3533b7..ee61481a86 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -141,28 +141,22 @@ void RasterizerGLES3::initialize() { print_line("Using GLES3 video driver"); } -#ifdef GLEW_ENABLED - GLuint res = glewInit(); - ERR_FAIL_COND(res != GLEW_OK); - if (OS::get_singleton()->is_stdout_verbose()) { - print_line(String("GLES2: Using GLEW ") + (const char *)glewGetString(GLEW_VERSION)); +#ifdef GLAD_ENABLED + if (!gladLoadGL()) { + ERR_PRINT("Error initializing GLAD"); } - // Check for GL 2.1 compatibility, if not bail out - if (!glewIsSupported("GL_VERSION_3_0")) { - ERR_PRINT("Your system's graphic drivers seem not to support OpenGL 3.0+ / GLES 3.0, sorry :(\n" +// GLVersion seems to be used for both GL and GL ES, so we need different version checks for them +#ifdef OPENGL_ENABLED // OpenGL 3.3 Core Profile required + if (GLVersion.major < 3 && GLVersion.minor < 3) { +#else // OpenGL ES 3.0 + if (GLVersion.major < 3) { +#endif + ERR_PRINT("Your system's graphic drivers seem not to support OpenGL 3.3 / OpenGL ES 3.0, sorry :(\n" "Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault."); - OS::get_singleton()->alert("Your system's graphic drivers seem not to support OpenGL 3.0+ / GLES 3.0, sorry :(\n" + OS::get_singleton()->alert("Your system's graphic drivers seem not to support OpenGL 3.3 / OpenGL ES 3.0, sorry :(\n" "Godot Engine will self-destruct as soon as you acknowledge this error message.", - "Fatal error: Insufficient OpenGL / GLES drivers"); - // TODO: If it's even possible, we should stop the execution without segfault and memory leaks :) - } -#endif - -#ifdef GLAD_ENABLED - - if (!gladLoadGL()) { - ERR_PRINT("Error initializing GLAD"); + "Fatal error: Insufficient OpenGL / GLES driver support"); } #ifdef __APPLE__ @@ -175,21 +169,20 @@ void RasterizerGLES3::initialize() { } #endif -#endif +#endif // GLAD_ENABLED - /* glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_ERROR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); + /* // For debugging + glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_ERROR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_PORTABILITY_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_PERFORMANCE_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_OTHER_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); glDebugMessageInsertARB( - GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_OTHER_ARB, 1, GL_DEBUG_SEVERITY_HIGH_ARB,5, "hello"); - -*/ + */ const GLubyte *renderer = glGetString(GL_RENDERER); print_line("OpenGL ES 3.0 Renderer: " + String((const char *)renderer)); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 004c628252..a41d84a2aa 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -4466,6 +4466,7 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type) { light->type = p_type; light->param[VS::LIGHT_PARAM_ENERGY] = 1.0; + light->param[VS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0; light->param[VS::LIGHT_PARAM_SPECULAR] = 0.5; light->param[VS::LIGHT_PARAM_RANGE] = 1.0; light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45; diff --git a/drivers/unix/SCsub b/drivers/unix/SCsub index c560e1289f..ada8255580 100644 --- a/drivers/unix/SCsub +++ b/drivers/unix/SCsub @@ -2,16 +2,6 @@ Import('env') -g_set_p = '#ifdef UNIX_ENABLED\n' -g_set_p += '#include "os_unix.h"\n' -g_set_p += 'String OS_Unix::get_global_settings_path() const {\n' -g_set_p += '\treturn "' + env["unix_global_settings_path"] + '";\n' -g_set_p += '}\n' -g_set_p += '#endif' -f = open("os_unix_global_settings_path.gen.cpp", "w") -f.write(g_set_p) -f.close() - env.add_source_files(env.drivers_sources, "*.cpp") env["check_c_headers"] = [ [ "mntent.h", "HAVE_MNTENT" ] ] diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 729abd57ef..ce0967af2c 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -454,32 +454,21 @@ int OS_Unix::get_processor_count() const { return sysconf(_SC_NPROCESSORS_CONF); } -String OS_Unix::get_data_dir() const { +String OS_Unix::get_user_data_dir() const { - String an = get_safe_application_name(); - if (an != "") { - - if (has_environment("HOME")) { - - bool use_godot = ProjectSettings::get_singleton()->get("application/config/use_shared_user_dir"); - if (use_godot) - return get_environment("HOME") + "/.godot/app_userdata/" + an; - else - return get_environment("HOME") + "/." + an; + String appname = get_safe_application_name(); + if (appname != "") { + bool use_godot_dir = ProjectSettings::get_singleton()->get("application/config/use_shared_user_dir"); + if (use_godot_dir) { + return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname); + } else { + return get_data_path().plus_file(appname); } } return ProjectSettings::get_singleton()->get_resource_path(); } -String OS_Unix::get_installed_templates_path() const { - String p = get_global_settings_path(); - if (p != "") - return p + "/templates/"; - else - return ""; -} - String OS_Unix::get_executable_path() const { #ifdef __linux__ diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 82c7dee3b9..432f48408f 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -62,8 +62,6 @@ protected: String stdin_buf; - String get_global_settings_path() const; - public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual String get_stdin_string(bool p_block); @@ -108,11 +106,8 @@ public: virtual void debug_break(); - virtual String get_installed_templates_path() const; virtual String get_executable_path() const; - virtual String get_data_dir() const; - - //virtual void run( MainLoop * p_main_loop ); + virtual String get_user_data_dir() const; }; class UnixTerminalLogger : public StdLogger { diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 0100c221c4..c7012a0c14 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -56,6 +56,7 @@ void GotoLineDialog::ok_pressed() { if (get_line() < 1 || get_line() > text_editor->get_line_count()) return; + text_editor->unfold_line(get_line() - 1); text_editor->cursor_set_line(get_line() - 1); hide(); } @@ -139,6 +140,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) if (found) { if (!preserve_cursor) { + text_edit->unfold_line(line); text_edit->cursor_set_line(line, false); text_edit->cursor_set_column(col + text.length(), false); text_edit->center_viewport_to_cursor(); @@ -167,6 +169,7 @@ void FindReplaceBar::_replace() { if (result_line != -1 && result_col != -1) { text_edit->begin_complex_operation(); + text_edit->unfold_line(result_line); text_edit->select(result_line, result_col, result_line, result_col + get_search_text().length()); text_edit->insert_text_at_cursor(get_replace_text()); @@ -214,6 +217,7 @@ void FindReplaceBar::_replace_all() { prev_match = Point2i(result_line, result_col + replace_text.length()); + text_edit->unfold_line(result_line); text_edit->select(result_line, result_col, result_line, match_to.y); if (selection_enabled && is_selection_only()) { @@ -751,6 +755,7 @@ bool FindReplaceDialog::_search() { if (found) { // print_line("found"); + text_edit->unfold_line(line); text_edit->cursor_set_line(line); if (is_backwards()) text_edit->cursor_set_column(col); @@ -1093,6 +1098,8 @@ void CodeTextEditor::update_editor_settings() { text_editor->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink")); text_editor->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed")); text_editor->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_breakpoint_gutter")); + text_editor->set_hiding_enabled(EditorSettings::get_singleton()->get("text_editor/line_numbers/code_folding")); + text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/code_folding")); text_editor->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret")); text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/open_scripts/smooth_scrolling")); text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/open_scripts/v_scroll_speed")); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 02af304dc6..c058d290bf 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -41,7 +41,7 @@ void CreateDialog::popup_create(bool p_dontclear) { recent->clear(); - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("create_recent." + base_type), FileAccess::READ); + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::READ); if (f) { @@ -63,7 +63,7 @@ void CreateDialog::popup_create(bool p_dontclear) { favorites->clear(); - f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("favorites." + base_type), FileAccess::READ); + f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::READ); favorite_list.clear(); @@ -316,7 +316,7 @@ void CreateDialog::_confirmed() { if (!ti) return; - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("create_recent." + base_type), FileAccess::WRITE); + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE); if (f) { f->store_line(get_selected_type()); @@ -476,7 +476,7 @@ void CreateDialog::_favorite_toggled() { void CreateDialog::_save_favorite_list() { - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("favorites." + base_type), FileAccess::WRITE); + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE); if (f) { diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index f7f823c945..1f9884aa70 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -951,7 +951,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri if (c.category == "") category = "Core"; header += " category=\"" + category + "\""; - header += String(" version=\"") + _MKSTR(VERSION_MAJOR) + "." + _MKSTR(VERSION_MINOR) + "-" + _MKSTR(VERSION_STATUS) + "\""; + header += String(" version=\"") + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + "\""; header += ">"; _write_string(f, 0, header); _write_string(f, 1, "<brief_description>"); diff --git a/editor/doc/doc_dump.cpp b/editor/doc/doc_dump.cpp index 45b7613659..9dd05d9d0f 100644 --- a/editor/doc/doc_dump.cpp +++ b/editor/doc/doc_dump.cpp @@ -82,7 +82,7 @@ void DocDump::dump(const String &p_file) { FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE); _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); - _write_string(f, 0, String("<doc version=\"") + _MKSTR(VERSION_MAJOR) + "." + _MKSTR(VERSION_MINOR) + "-" + _MKSTR(VERSION_STATUS) + "\" name=\"Engine Types\">"); + _write_string(f, 0, String("<doc version=\"") + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + "\" name=\"Engine Types\">"); while (class_list.size()) { diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index a458a10cd2..519bc33d42 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -336,33 +336,18 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat String EditorExportPlatform::find_export_template(String template_file_name, String *err) const { - String base_name = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + _MKSTR(VERSION_STATUS) + "/" + template_file_name; - String user_file = EditorSettings::get_singleton()->get_settings_path() + "/templates/" + base_name; - String system_file = OS::get_singleton()->get_installed_templates_path(); - bool has_system_path = (system_file != ""); - system_file = system_file.plus_file(base_name); - - // Prefer user file - if (FileAccess::exists(user_file)) { - return user_file; - } + String current_version = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + VERSION_MODULE_CONFIG; + String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(current_version).plus_file(template_file_name); - // Now check system file - if (has_system_path) { - if (FileAccess::exists(system_file)) { - return system_file; - } + if (FileAccess::exists(template_path)) { + return template_path; } // Not found if (err) { - *err += "No export template found at \"" + user_file + "\""; - if (has_system_path) - *err += "\n or \"" + system_file + "\"."; - else - *err += "."; + *err += "No export template found at \"" + template_path + "\"."; } - return String(); // not found + return String(); } bool EditorExportPlatform::exists_export_template(String template_file_name, String *err) const { @@ -692,7 +677,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } String config_file = "project.binary"; - String engine_cfb = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmp" + config_file; + String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); @@ -705,7 +690,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c EditorProgress ep("savepack", TTR("Packing"), 102); - String tmppath = EditorSettings::get_singleton()->get_settings_path() + "/tmp/packtmp"; + String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp"); FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE); ERR_FAIL_COND_V(!ftmp, ERR_CANT_CREATE) diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 9db3bcba00..8d5bad3346 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -188,7 +188,7 @@ void EditorFileSystem::_scan_filesystem() { String project = ProjectSettings::get_singleton()->get_resource_path(); - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache3"); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache3"); FileAccess *f = FileAccess::open(fscache, FileAccess::READ); if (f) { @@ -238,7 +238,7 @@ void EditorFileSystem::_scan_filesystem() { memdelete(f); } - String update_cache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_update3"); + String update_cache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update3"); if (FileAccess::exists(update_cache)) { { @@ -282,7 +282,7 @@ void EditorFileSystem::_scan_filesystem() { } void EditorFileSystem::_save_filesystem_cache() { - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache3"); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache3"); FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE); _save_filesystem_cache(filesystem, f); @@ -1180,7 +1180,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p void EditorFileSystem::_save_late_updated_files() { //files that already existed, and were modified, need re-scanning for dependencies upon project restart. This is done via saving this special file - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_update3"); + String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update3"); FileAccessRef f = FileAccess::open(fscache, FileAccess::WRITE); for (Set<String>::Element *E = late_update_files.front(); E; E = E->next()) { f->store_line(E->get()); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index a209aca9d5..7627fecc43 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -147,7 +147,7 @@ void EditorNode::_update_scene_tabs() { void EditorNode::_update_title() { String appname = ProjectSettings::get_singleton()->get("application/config/name"); - String title = appname.empty() ? String(VERSION_FULL_NAME) : String(_MKSTR(VERSION_NAME) + String(" - ") + appname); + String title = appname.empty() ? String(VERSION_FULL_NAME) : String(VERSION_NAME + String(" - ") + appname); String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_filename() : String(); if (!edited.empty()) title += " - " + String(edited.get_file()); @@ -705,7 +705,7 @@ void EditorNode::_get_scene_metadata(const String &p_file) { if (!scene) return; - String path = EditorSettings::get_singleton()->get_project_settings_path().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); + String path = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); Ref<ConfigFile> cf; cf.instance(); @@ -739,7 +739,7 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) { scene->set_meta("__editor_run_settings__", Variant()); //clear it (no point in keeping it) scene->set_meta("__editor_plugin_states__", Variant()); - String path = EditorSettings::get_singleton()->get_project_settings_path().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); + String path = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); Ref<ConfigFile> cf; cf.instance(); @@ -906,27 +906,33 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { int preview_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); preview_size *= EDSCALE; - int width, height; - if (img->get_width() > preview_size && img->get_width() >= img->get_height()) { - width = preview_size; - height = img->get_height() * preview_size / img->get_width(); - } else if (img->get_height() > preview_size && img->get_height() >= img->get_width()) { + // consider a square region + int vp_size = MIN(img->get_width(), img->get_height()); + int x = (img->get_width() - vp_size) / 2; + int y = (img->get_height() - vp_size) / 2; - height = preview_size; - width = img->get_width() * preview_size / img->get_height(); + img->convert(Image::FORMAT_RGB8); + + if (vp_size < preview_size) { + // just square it. + img->crop_from_point(x, y, vp_size, vp_size); } else { + int ratio = vp_size / preview_size; + int size = preview_size * (ratio / 2); - width = img->get_width(); - height = img->get_height(); + x = (img->get_width() - size) / 2; + y = (img->get_height() - size) / 2; + + img->crop_from_point(x, y, size, size); + // We could get better pictures with better filters + img->resize(preview_size, preview_size, Image::INTERPOLATE_CUBIC); } - img->convert(Image::FORMAT_RGB8); - img->resize(width, height); img->flip_y(); //save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5 - String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); + String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); @@ -1109,7 +1115,7 @@ void EditorNode::_dialog_action(String p_file) { _save_default_environment(); _save_scene_with_preview(p_file); - _run(false); + _run(false, p_file); } } break; @@ -1198,7 +1204,7 @@ void EditorNode::_dialog_action(String p_file) { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err == ERR_CANT_OPEN) { config.instance(); // new config @@ -1209,7 +1215,7 @@ void EditorNode::_dialog_action(String p_file) { _save_docks_to_config(config, p_file); - config->save(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + config->save(EditorSettings::get_singleton()->get_editor_layouts_config()); layout_dialog->hide(); _update_layouts_menu(); @@ -1226,7 +1232,7 @@ void EditorNode::_dialog_action(String p_file) { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK || !config->has_section(p_file)) { show_warning(TTR("Layout name not found!")); @@ -1240,7 +1246,7 @@ void EditorNode::_dialog_action(String p_file) { config->set_value(p_file, E->get(), Variant()); } - config->save(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + config->save(EditorSettings::get_singleton()->get_editor_layouts_config()); layout_dialog->hide(); _update_layouts_menu(); @@ -3581,7 +3587,7 @@ void EditorNode::_save_docks() { _save_docks_to_config(config, "docks"); editor_data.get_plugin_window_layout(config); - config->save(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg")); + config->save(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); } void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) { @@ -3643,7 +3649,7 @@ void EditorNode::_load_docks() { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); if (err != OK) { //no config if (overridden_default_layout >= 0) { @@ -3812,7 +3818,7 @@ void EditorNode::_update_layouts_menu() { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK) { return; //no config } @@ -3860,7 +3866,7 @@ void EditorNode::_layout_menu_option(int p_id) { Ref<ConfigFile> config; config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts-3.cfg")); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK) { return; //no config } diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 5b4bdb59d3..467451cd2b 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -198,7 +198,7 @@ void EditorResourcePreview::_thread() { } else { - String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); + String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 165c0691fb..d228dd2581 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -334,6 +334,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/line_numbers/show_line_numbers", true); _initial_set("text_editor/line_numbers/line_numbers_zero_padded", false); _initial_set("text_editor/line_numbers/show_breakpoint_gutter", true); + _initial_set("text_editor/line_numbers/code_folding", true); _initial_set("text_editor/line_numbers/show_line_length_guideline", false); _initial_set("text_editor/line_numbers/line_length_guideline_column", 80); hints["text_editor/line_numbers/line_length_guideline_column"] = PropertyInfo(Variant::INT, "text_editor/line_numbers/line_length_guideline_column", PROPERTY_HINT_RANGE, "20, 160, 10"); @@ -639,10 +640,14 @@ void EditorSettings::create() { return; //pointless DirAccess *dir = NULL; - Variant meta; + String data_path; + String data_dir; String config_path; String config_dir; + String cache_path; + String cache_dir; + Ref<ConfigFile> extra_config = memnew(ConfigFile); String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); @@ -659,38 +664,50 @@ void EditorSettings::create() { memdelete(d); if (self_contained) { - // editor is self contained + + // editor is self contained, all in same folder + data_path = exe_path; + data_dir = data_path.plus_file("editor_data"); config_path = exe_path; - config_dir = "editor_data"; + config_dir = data_dir; + cache_path = exe_path; + cache_dir = data_dir.plus_file("cache"); } else { - if (OS::get_singleton()->has_environment("APPDATA")) { - // Most likely under windows, save here - config_path = OS::get_singleton()->get_environment("APPDATA"); - config_dir = String(_MKSTR(VERSION_SHORT_NAME)).capitalize(); - } else if (OS::get_singleton()->has_environment("HOME")) { - - config_path = OS::get_singleton()->get_environment("HOME"); - config_dir = "." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower(); + // Typically XDG_DATA_HOME or %APPDATA% + data_path = OS::get_singleton()->get_data_path(); + data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + // Can be different from data_path e.g. on Linux or macOS + config_path = OS::get_singleton()->get_config_path(); + config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + // Can be different from above paths, otherwise a subfolder of data_dir + cache_path = OS::get_singleton()->get_cache_path(); + if (cache_path == data_path) { + cache_dir = data_dir.plus_file("cache"); + } else { + cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name()); } - }; + } ClassDB::register_class<EditorSettings>(); //otherwise it can't be unserialized + String config_file_path; - if (config_path != "") { + if (data_path != "" && config_path != "" && cache_path != "") { + + // Validate/create data dir and subdirectories dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (dir->change_dir(config_path) != OK) { - ERR_PRINT("Cannot find path for config directory!"); + if (dir->change_dir(data_path) != OK) { + ERR_PRINT("Cannot find path for data directory!"); memdelete(dir); goto fail; } - if (dir->change_dir(config_dir) != OK) { - dir->make_dir(config_dir); - if (dir->change_dir(config_dir) != OK) { - ERR_PRINT("Cannot create config directory!"); + if (dir->change_dir(data_dir) != OK) { + dir->make_dir(data_dir); + if (dir->change_dir(data_dir) != OK) { + ERR_PRINT("Cannot create data directory!"); memdelete(dir); goto fail; } @@ -699,10 +716,43 @@ void EditorSettings::create() { if (dir->change_dir("templates") != OK) { dir->make_dir("templates"); } else { - dir->change_dir(".."); } + // Validate/create cache dir + + if (dir->change_dir(cache_path) != OK) { + ERR_PRINT("Cannot find path for cache directory!"); + memdelete(dir); + goto fail; + } + + if (dir->change_dir(cache_dir) != OK) { + dir->make_dir(cache_dir); + if (dir->change_dir(cache_dir) != OK) { + ERR_PRINT("Cannot create cache directory!"); + memdelete(dir); + goto fail; + } + } + + // Validate/create config dir and subdirectories + + if (dir->change_dir(config_path) != OK) { + ERR_PRINT("Cannot find path for config directory!"); + memdelete(dir); + goto fail; + } + + if (dir->change_dir(config_dir) != OK) { + dir->make_dir(config_dir); + if (dir->change_dir(config_dir) != OK) { + ERR_PRINT("Cannot create config directory!"); + memdelete(dir); + goto fail; + } + } + if (dir->change_dir("text_editor_themes") != OK) { dir->make_dir("text_editor_themes"); } else { @@ -714,52 +764,40 @@ void EditorSettings::create() { } else { dir->change_dir(".."); } - _create_script_templates(dir->get_current_dir() + "/script_templates"); - - if (dir->change_dir("tmp") != OK) { - dir->make_dir("tmp"); - } else { - - dir->change_dir(".."); - } + _create_script_templates(dir->get_current_dir().plus_file("script_templates")); - if (dir->change_dir("config") != OK) { - dir->make_dir("config"); + if (dir->change_dir("projects") != OK) { + dir->make_dir("projects"); } else { - dir->change_dir(".."); } - dir->change_dir("config"); + // Validate/create project-specific config dir - String pcp = ProjectSettings::get_singleton()->get_resource_path(); - if (pcp.ends_with("/")) - pcp = config_path.substr(0, pcp.size() - 1); - pcp = pcp.get_file() + "-" + pcp.md5_text(); + dir->change_dir("projects"); + String project_config_dir = ProjectSettings::get_singleton()->get_resource_path(); + if (project_config_dir.ends_with("/")) + project_config_dir = config_path.substr(0, project_config_dir.size() - 1); + project_config_dir = project_config_dir.get_file() + "-" + project_config_dir.md5_text(); - if (dir->change_dir(pcp)) { - dir->make_dir(pcp); + if (dir->change_dir(project_config_dir) != OK) { + dir->make_dir(project_config_dir); } else { dir->change_dir(".."); } - dir->change_dir(".."); - // path at least is validated, so validate config file - - String config_file_name = "editor_settings-" + String(_MKSTR(VERSION_MAJOR)) + ".tres"; - config_file_path = config_path + "/" + config_dir + "/" + config_file_name; - - String open_path = config_file_path; + // Validate editor config file + String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres"; + config_file_path = config_dir.plus_file(config_file_name); if (!dir->file_exists(config_file_name)) { - goto fail; } memdelete(dir); - singleton = ResourceLoader::load(open_path, "EditorSettings"); + singleton = ResourceLoader::load(config_file_path, "EditorSettings"); if (singleton.is_null()) { WARN_PRINT("Could not open config file."); @@ -768,8 +806,10 @@ void EditorSettings::create() { singleton->save_changed_setting = true; singleton->config_file_path = config_file_path; - singleton->project_config_path = pcp; - singleton->settings_path = config_path + "/" + config_dir; + singleton->project_config_dir = project_config_dir; + singleton->settings_dir = config_dir; + singleton->data_dir = data_dir; + singleton->cache_dir = cache_dir; if (OS::get_singleton()->is_stdout_verbose()) { @@ -799,7 +839,9 @@ fail: singleton = Ref<EditorSettings>(memnew(EditorSettings)); singleton->save_changed_setting = true; singleton->config_file_path = config_file_path; - singleton->settings_path = config_path + "/" + config_dir; + singleton->settings_dir = config_dir; + singleton->data_dir = data_dir; + singleton->cache_dir = cache_dir; singleton->_load_defaults(extra_config); singleton->setup_language(); singleton->setup_network(); @@ -970,21 +1012,52 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { hints[p_hint.name] = p_hint; } -// Settings paths and saved metadata +// Data directories + +String EditorSettings::get_data_dir() const { + + return data_dir; +} + +String EditorSettings::get_templates_dir() const { + + return get_data_dir().plus_file("templates"); +} + +// Config directories + +String EditorSettings::get_settings_dir() const { + + return settings_dir; +} + +String EditorSettings::get_project_settings_dir() const { + + return get_settings_dir().plus_file("projects").plus_file(project_config_dir); +} + +String EditorSettings::get_text_editor_themes_dir() const { -String EditorSettings::get_settings_path() const { + return get_settings_dir().plus_file("text_editor_themes"); +} - return settings_path; +String EditorSettings::get_script_templates_dir() const { + + return get_settings_dir().plus_file("script_templates"); } -String EditorSettings::get_project_settings_path() const { +// Cache directory + +String EditorSettings::get_cache_dir() const { - return get_settings_path().plus_file("config").plus_file(project_config_path); + return cache_dir; } +// Metadata + void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) { Ref<ConfigFile> cf = memnew(ConfigFile); - String path = get_project_settings_path().plus_file("project_metadata.cfg"); + String path = get_project_settings_dir().plus_file("project_metadata.cfg"); cf->load(path); cf->set_value(p_section, p_key, p_data); cf->save(path); @@ -992,7 +1065,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) { Ref<ConfigFile> cf = memnew(ConfigFile); - String path = get_project_settings_path().plus_file("project_metadata.cfg"); + String path = get_project_settings_dir().plus_file("project_metadata.cfg"); Error err = cf->load(path); if (err != OK) { return p_default; @@ -1003,7 +1076,7 @@ Variant EditorSettings::get_project_metadata(const String &p_section, const Stri void EditorSettings::set_favorite_dirs(const Vector<String> &p_favorites_dirs) { favorite_dirs = p_favorites_dirs; - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"), FileAccess::WRITE); + FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("favorite_dirs"), FileAccess::WRITE); if (f) { for (int i = 0; i < favorite_dirs.size(); i++) f->store_line(favorite_dirs[i]); @@ -1019,7 +1092,7 @@ Vector<String> EditorSettings::get_favorite_dirs() const { void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) { recent_dirs = p_recent_dirs; - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"), FileAccess::WRITE); + FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("recent_dirs"), FileAccess::WRITE); if (f) { for (int i = 0; i < recent_dirs.size(); i++) f->store_line(recent_dirs[i]); @@ -1034,7 +1107,7 @@ Vector<String> EditorSettings::get_recent_dirs() const { void EditorSettings::load_favorites() { - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"), FileAccess::READ); + FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("favorite_dirs"), FileAccess::READ); if (f) { String line = f->get_line().strip_edges(); while (line != "") { @@ -1044,7 +1117,7 @@ void EditorSettings::load_favorites() { memdelete(f); } - f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"), FileAccess::READ); + f = FileAccess::open(get_project_settings_dir().plus_file("recent_dirs"), FileAccess::READ); if (f) { String line = f->get_line().strip_edges(); while (line != "") { @@ -1057,7 +1130,7 @@ void EditorSettings::load_favorites() { void EditorSettings::list_text_editor_themes() { String themes = "Adaptive,Default"; - DirAccess *d = DirAccess::open(get_settings_path().plus_file("text_editor_themes")); + DirAccess *d = DirAccess::open(get_text_editor_themes_dir()); if (d) { d->list_dir_begin(); String file = d->get_next(); @@ -1079,7 +1152,7 @@ void EditorSettings::load_text_editor_theme() { return; } - String theme_path = get_settings_path().plus_file("text_editor_themes").plus_file((String)get("text_editor/theme/color_theme") + ".tet"); + String theme_path = get_text_editor_themes_dir().plus_file((String)get("text_editor/theme/color_theme") + ".tet"); Ref<ConfigFile> cf = memnew(ConfigFile); Error err = cf->load(theme_path); @@ -1117,9 +1190,9 @@ bool EditorSettings::import_text_editor_theme(String p_file) { return false; } - DirAccess *d = DirAccess::open(get_settings_path().plus_file("text_editor_themes")); + DirAccess *d = DirAccess::open(get_text_editor_themes_dir()); if (d) { - d->copy(p_file, get_settings_path().plus_file("text_editor_themes").plus_file(p_file.get_file())); + d->copy(p_file, get_text_editor_themes_dir().plus_file(p_file.get_file())); memdelete(d); return true; } @@ -1134,7 +1207,7 @@ bool EditorSettings::save_text_editor_theme() { if (p_file.get_file().to_lower() == "default" || p_file.get_file().to_lower() == "adaptive") { return false; } - String theme_path = get_settings_path().plus_file("text_editor_themes").plus_file(p_file + ".tet"); + String theme_path = get_text_editor_themes_dir().plus_file(p_file + ".tet"); return _save_text_editor_theme(theme_path); } @@ -1152,7 +1225,7 @@ bool EditorSettings::save_text_editor_theme_as(String p_file) { list_text_editor_themes(); String theme_name = p_file.substr(0, p_file.length() - 4).get_file(); - if (p_file.get_base_dir() == get_settings_path().plus_file("text_editor_themes")) { + if (p_file.get_base_dir() == get_text_editor_themes_dir()) { _initial_set("text_editor/theme/color_theme", theme_name); load_text_editor_theme(); } @@ -1164,7 +1237,7 @@ bool EditorSettings::save_text_editor_theme_as(String p_file) { Vector<String> EditorSettings::get_script_templates(const String &p_extension) { Vector<String> templates; - DirAccess *d = DirAccess::open(get_settings_path().plus_file("script_templates")); + DirAccess *d = DirAccess::open(get_script_templates_dir()); if (d) { d->list_dir_begin(); String file = d->get_next(); @@ -1180,6 +1253,11 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension) { return templates; } +String EditorSettings::get_editor_layouts_config() const { + + return get_settings_dir().plus_file("editor_layouts.cfg"); +} + // Shortcuts void EditorSettings::add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcut) { @@ -1286,8 +1364,8 @@ void EditorSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert); ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind); - ClassDB::bind_method(D_METHOD("get_settings_path"), &EditorSettings::get_settings_path); - ClassDB::bind_method(D_METHOD("get_project_settings_path"), &EditorSettings::get_project_settings_path); + ClassDB::bind_method(D_METHOD("get_settings_dir"), &EditorSettings::get_settings_dir); + ClassDB::bind_method(D_METHOD("get_project_settings_dir"), &EditorSettings::get_project_settings_dir); ClassDB::bind_method(D_METHOD("set_favorite_dirs", "dirs"), &EditorSettings::set_favorite_dirs); ClassDB::bind_method(D_METHOD("get_favorite_dirs"), &EditorSettings::get_favorite_dirs); diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 29665369c4..f11f4dfd43 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -93,9 +93,11 @@ private: Map<String, Ref<ShortCut> > shortcuts; String resource_path; + String settings_dir; + String data_dir; + String cache_dir; String config_file_path; - String settings_path; - String project_config_path; + String project_config_dir; Vector<String> favorite_dirs; Vector<String> recent_dirs; @@ -147,8 +149,13 @@ public: void set_resource_clipboard(const Ref<Resource> &p_resource) { clipboard = p_resource; } Ref<Resource> get_resource_clipboard() const { return clipboard; } - String get_settings_path() const; - String get_project_settings_path() const; + String get_data_dir() const; + String get_templates_dir() const; + String get_settings_dir() const; + String get_project_settings_dir() const; + String get_text_editor_themes_dir() const; + String get_script_templates_dir() const; + String get_cache_dir() const; void set_project_metadata(const String &p_section, const String &p_key, Variant p_data); Variant get_project_metadata(const String &p_section, const String &p_key, Variant p_default); @@ -166,6 +173,7 @@ public: bool save_text_editor_theme_as(String p_file); Vector<String> get_script_templates(const String &p_extension); + String get_editor_layouts_config() const; void add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcut); bool is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const; diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 8641fc7667..d208bbe662 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -35,6 +35,7 @@ #include "io/zip_io.h" #include "os/dir_access.h" #include "version.h" + void ExportTemplateManager::_update_template_list() { while (current_hb->get_child_count()) { @@ -46,7 +47,7 @@ void ExportTemplateManager::_update_template_list() { } DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error err = d->change_dir(EditorSettings::get_singleton()->get_settings_path().plus_file("templates")); + Error err = d->change_dir(EditorSettings::get_singleton()->get_templates_dir()); d->list_dir_begin(); Set<String> templates; @@ -66,7 +67,7 @@ void ExportTemplateManager::_update_template_list() { memdelete(d); - String current_version = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + _MKSTR(VERSION_STATUS) + VERSION_MODULE_CONFIG; + String current_version = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + VERSION_MODULE_CONFIG; Label *current = memnew(Label); current->set_h_size_flags(SIZE_EXPAND_FILL); @@ -142,7 +143,7 @@ void ExportTemplateManager::_uninstall_template(const String &p_version) { void ExportTemplateManager::_uninstall_template_confirm() { DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error err = d->change_dir(EditorSettings::get_singleton()->get_settings_path().plus_file("templates")); + Error err = d->change_dir(EditorSettings::get_singleton()->get_templates_dir()); ERR_FAIL_COND(err != OK); @@ -244,7 +245,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file) { return; } - String template_path = EditorSettings::get_singleton()->get_settings_path().plus_file("templates").plus_file(version); + String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version); DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error err = d->make_dir_recursive(template_path); @@ -393,7 +394,7 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int if (p_code != 200) { template_list_state->set_text(TTR("Failed:") + " " + itos(p_code)); } else { - String path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("tmp_templates.tpz"); + String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"); FileAccess *f = FileAccess::open(path, FileAccess::WRITE); if (!f) { template_list_state->set_text(TTR("Can't write file.")); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 4541c77085..bd24aac99b 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -413,6 +413,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in for (List<Ref<Mesh> >::Element *E = meshes.front(); E; E = E->next()) { MeshInstance *mi = memnew(MeshInstance); + mi->set_mesh(E->get()); mi->set_name(E->get()->get_name()); scene->add_child(mi); mi->set_owner(scene); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index d2e7feb6e1..87228dee6f 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -445,7 +445,7 @@ void EditorAssetLibraryItemDownload::_install() { void EditorAssetLibraryItemDownload::_make_request() { download->cancel_request(); - download->set_download_file(EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("tmp_asset_" + itos(asset_id)) + ".zip"); + download->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip"); Error err = download->request(host); if (err != OK) { @@ -680,7 +680,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt PoolByteArray image_data = p_data; if (use_cache) { - String cache_filename_base = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); + String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ); @@ -738,7 +738,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) { for (int i = 0; i < headers.size(); i++) { if (headers[i].findn("ETag:") == 0) { // Save etag - String cache_filename_base = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); + String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges(); FileAccess *file; @@ -786,7 +786,7 @@ void EditorAssetLibrary::_update_image_queue() { for (Map<int, ImageQueue>::Element *E = image_queue.front(); E; E = E->next()) { if (!E->get().active && current_images < max_images) { - String cache_filename_base = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("assetimage_" + E->get().image_url.md5_text()); + String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text()); Vector<String> headers; if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) { diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index dd49bae51d..ed04c90cc5 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -184,7 +184,7 @@ Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from) { Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path) { - String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); + String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 85416a5700..52989ffd3c 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -855,7 +855,7 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog_option = FILE_SAVE_THEME_AS; file_dialog->clear_filters(); file_dialog->add_filter("*.tet"); - file_dialog->set_current_path(EditorSettings::get_singleton()->get_settings_path() + "/text_editor_themes/" + EditorSettings::get_singleton()->get("text_editor/theme/color_theme")); + file_dialog->set_current_path(EditorSettings::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))); file_dialog->popup_centered_ratio(); file_dialog->set_title(TTR("Save Theme As..")); } break; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index f670724f47..214f24b386 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -518,7 +518,9 @@ void ScriptTextEditor::tag_saved_version() { } void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { - code_editor->get_text_edit()->call_deferred("cursor_set_line", p_line); + TextEdit *tx = code_editor->get_text_edit(); + tx->unfold_line(p_line); + tx->call_deferred("cursor_set_line", p_line); } void ScriptTextEditor::ensure_focus() { @@ -712,15 +714,6 @@ void ScriptTextEditor::_breakpoint_toggled(int p_row) { ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), p_row + 1, code_editor->get_text_edit()->is_line_set_as_breakpoint(p_row)); } -static void swap_lines(TextEdit *tx, int line1, int line2) { - String tmp = tx->get_line(line1); - String tmp2 = tx->get_line(line2); - tx->set_line(line2, tmp); - tx->set_line(line1, tmp2); - - tx->cursor_set_line(line2); -} - void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_column) { Node *base = get_tree()->get_edited_scene_root(); @@ -799,39 +792,41 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c void ScriptTextEditor::_edit_option(int p_op) { + TextEdit *tx = code_editor->get_text_edit(); + switch (p_op) { case EDIT_UNDO: { - code_editor->get_text_edit()->undo(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + + tx->undo(); + tx->call_deferred("grab_focus"); } break; case EDIT_REDO: { - code_editor->get_text_edit()->redo(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + + tx->redo(); + tx->call_deferred("grab_focus"); } break; case EDIT_CUT: { - code_editor->get_text_edit()->cut(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->cut(); + tx->call_deferred("grab_focus"); } break; case EDIT_COPY: { - code_editor->get_text_edit()->copy(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->copy(); + tx->call_deferred("grab_focus"); } break; case EDIT_PASTE: { - code_editor->get_text_edit()->paste(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->paste(); + tx->call_deferred("grab_focus"); } break; case EDIT_SELECT_ALL: { - code_editor->get_text_edit()->select_all(); - code_editor->get_text_edit()->call_deferred("grab_focus"); - + tx->select_all(); + tx->call_deferred("grab_focus"); } break; case EDIT_MOVE_LINE_UP: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = script; if (scr.is_null()) return; @@ -850,6 +845,9 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == 0 || next_id < 0) return; + tx->unfold_line(line_id); + tx->unfold_line(next_id); + tx->swap_lines(line_id, next_id); tx->cursor_set_line(next_id); } @@ -863,16 +861,17 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == 0 || next_id < 0) return; + tx->unfold_line(line_id); + tx->unfold_line(next_id); + tx->swap_lines(line_id, next_id); tx->cursor_set_line(next_id); } tx->end_complex_operation(); tx->update(); - } break; case EDIT_MOVE_LINE_DOWN: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -891,6 +890,9 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) return; + tx->unfold_line(line_id); + tx->unfold_line(next_id); + tx->swap_lines(line_id, next_id); tx->cursor_set_line(next_id); } @@ -904,6 +906,9 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) return; + tx->unfold_line(line_id); + tx->unfold_line(next_id); + tx->swap_lines(line_id, next_id); tx->cursor_set_line(next_id); } @@ -913,7 +918,6 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_INDENT_LEFT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -938,11 +942,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_INDENT_RIGHT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -959,11 +961,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_DELETE_LINE: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -972,13 +972,12 @@ void ScriptTextEditor::_edit_option(int p_op) { int line = tx->cursor_get_line(); tx->set_line(tx->cursor_get_line(), ""); tx->backspace_at_cursor(); + tx->unfold_line(line); tx->cursor_set_line(line); tx->end_complex_operation(); - } break; case EDIT_CLONE_DOWN: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -997,6 +996,7 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->begin_complex_operation(); for (int i = from_line; i <= to_line; i++) { + tx->unfold_line(i); if (i >= tx->get_line_count() - 1) { tx->set_line(i, tx->get_line(i) + "\n"); } @@ -1012,11 +1012,29 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); + } break; + case EDIT_FOLD_LINE: { + + tx->fold_line(tx->cursor_get_line()); + tx->update(); + } break; + case EDIT_UNFOLD_LINE: { + + tx->unfold_line(tx->cursor_get_line()); + tx->update(); + } break; + case EDIT_FOLD_ALL_LINES: { + + tx->fold_all_lines(); + tx->update(); + } break; + case EDIT_UNFOLD_ALL_LINES: { + tx->unhide_all_lines(); + tx->update(); } break; case EDIT_TOGGLE_COMMENT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -1065,62 +1083,65 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_COMPLETE: { - code_editor->get_text_edit()->query_code_comple(); - + tx->query_code_comple(); } break; case EDIT_AUTO_INDENT: { - TextEdit *te = code_editor->get_text_edit(); - String text = te->get_text(); + String text = tx->get_text(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; - te->begin_complex_operation(); + tx->begin_complex_operation(); int begin, end; - if (te->is_selection_active()) { - begin = te->get_selection_from_line(); - end = te->get_selection_to_line(); + if (tx->is_selection_active()) { + begin = tx->get_selection_from_line(); + end = tx->get_selection_to_line(); // ignore if the cursor is not past the first column - if (te->get_selection_to_column() == 0) { + if (tx->get_selection_to_column() == 0) { end--; } } else { begin = 0; - end = te->get_line_count() - 1; + end = tx->get_line_count() - 1; } scr->get_language()->auto_indent_code(text, begin, end); Vector<String> lines = text.split("\n"); for (int i = begin; i <= end; ++i) { - te->set_line(i, lines[i]); + tx->set_line(i, lines[i]); } - te->end_complex_operation(); - + tx->end_complex_operation(); } break; case EDIT_TRIM_TRAILING_WHITESAPCE: { + trim_trailing_whitespace(); } break; case EDIT_CONVERT_INDENT_TO_SPACES: { + convert_indent_to_spaces(); } break; case EDIT_CONVERT_INDENT_TO_TABS: { + convert_indent_to_tabs(); } break; case EDIT_PICK_COLOR: { + color_panel->popup(); } break; case EDIT_TO_UPPERCASE: { + _convert_case(UPPER); } break; case EDIT_TO_LOWERCASE: { + _convert_case(LOWER); } break; case EDIT_CAPITALIZE: { + _convert_case(CAPITALIZE); } break; case SEARCH_FIND: { @@ -1145,41 +1166,47 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case SEARCH_GOTO_LINE: { - goto_line_dialog->popup_find_line(code_editor->get_text_edit()); + goto_line_dialog->popup_find_line(tx); } break; case DEBUG_TOGGLE_BREAKPOINT: { - int line = code_editor->get_text_edit()->cursor_get_line(); - bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line); - code_editor->get_text_edit()->set_line_as_breakpoint(line, dobreak); + + int line = tx->cursor_get_line(); + bool dobreak = !tx->is_line_set_as_breakpoint(line); + tx->set_line_as_breakpoint(line, dobreak); ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); } break; case DEBUG_REMOVE_ALL_BREAKPOINTS: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { int line = E->get(); - bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line); - code_editor->get_text_edit()->set_line_as_breakpoint(line, dobreak); + bool dobreak = !tx->is_line_set_as_breakpoint(line); + tx->set_line_as_breakpoint(line, dobreak); ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); } } case DEBUG_GOTO_NEXT_BREAKPOINT: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); if (bpoints.size() <= 0) { return; } - int line = code_editor->get_text_edit()->cursor_get_line(); + int line = tx->cursor_get_line(); + // wrap around if (line >= bpoints[bpoints.size() - 1]) { - code_editor->get_text_edit()->cursor_set_line(bpoints[0]); + tx->unfold_line(bpoints[0]); + tx->cursor_set_line(bpoints[0]); } else { for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { int bline = E->get(); if (bline > line) { - code_editor->get_text_edit()->cursor_set_line(bline); + tx->unfold_line(bline); + tx->cursor_set_line(bline); return; } } @@ -1187,21 +1214,24 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case DEBUG_GOTO_PREV_BREAKPOINT: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); if (bpoints.size() <= 0) { return; } - int line = code_editor->get_text_edit()->cursor_get_line(); + int line = tx->cursor_get_line(); // wrap around if (line <= bpoints[0]) { - code_editor->get_text_edit()->cursor_set_line(bpoints[bpoints.size() - 1]); + tx->unfold_line(bpoints[bpoints.size() - 1]); + tx->cursor_set_line(bpoints[bpoints.size() - 1]); } else { for (List<int>::Element *E = bpoints.back(); E; E = E->prev()) { int bline = E->get(); if (bline < line) { - code_editor->get_text_edit()->cursor_set_line(bline); + tx->unfold_line(bline); + tx->cursor_set_line(bline); return; } } @@ -1210,9 +1240,10 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case HELP_CONTEXTUAL: { - String text = code_editor->get_text_edit()->get_selection_text(); + + String text = tx->get_selection_text(); if (text == "") - text = code_editor->get_text_edit()->get_word_under_cursor(); + text = tx->get_word_under_cursor(); if (text != "") { emit_signal("request_help_search", text); } @@ -1398,6 +1429,9 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { Vector2 mpos = mb->get_global_position() - tx->get_global_position(); bool have_selection = (tx->get_selection_text().length() > 0); bool have_color = (tx->get_word_at_pos(mpos) == "Color"); + int fold_state = 0; + bool can_fold = tx->can_fold(row); + bool is_folded = tx->is_folded(row); if (have_color) { String line = tx->get_line(row); @@ -1428,7 +1462,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { have_color = false; } } - _make_context_menu(have_selection, have_color); + _make_context_menu(have_selection, have_color, can_fold, is_folded); } } } @@ -1447,7 +1481,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) { code_editor->get_text_edit()->set_line(color_line, new_line); } -void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color) { +void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded) { context_menu->clear(); if (p_selection) { @@ -1467,6 +1501,13 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color) { 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_color) { context_menu->add_separator(); context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR); @@ -1530,6 +1571,10 @@ 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/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 edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE); @@ -1607,6 +1652,10 @@ 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/fold_all_lines", TTR("Fold All Lines"), 0); + ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0); #ifdef OSX_ENABLED ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL | KEY_SPACE); #else diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 83f3ea57c0..722015ef3e 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -91,6 +91,10 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_TO_UPPERCASE, EDIT_TO_LOWERCASE, EDIT_CAPITALIZE, + EDIT_FOLD_LINE, + EDIT_UNFOLD_LINE, + EDIT_FOLD_ALL_LINES, + EDIT_UNFOLD_ALL_LINES, SEARCH_FIND, SEARCH_FIND_NEXT, SEARCH_FIND_PREV, @@ -118,7 +122,7 @@ protected: static void _bind_methods(); void _edit_option(int p_op); - void _make_context_menu(bool p_selection, bool p_color); + void _make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded); void _text_edit_gui_input(const Ref<InputEvent> &ev); void _color_changed(const Color &p_color); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 2c16157b6a..b3d3d5e13a 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -758,17 +758,49 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig } } + bool is_plane_scale = false; + // plane select + if (col_axis == -1) { + col_d = 1e20; + + for (int i = 0; i < 3; i++) { + + Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized(); + Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized(); + + Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST); + + Vector3 r; + Plane plane(gt.origin, gt.basis.get_axis(i).normalized()); + + if (plane.intersects_ray(ray_pos, ray, &r)) { + + float dist = r.distance_to(grabber_pos); + if (dist < (gs * GIZMO_PLANE_SIZE)) { + + float d = ray_pos.distance_to(r); + if (d < col_d) { + col_d = d; + col_axis = i; + + is_plane_scale = true; + } + } + } + } + } + if (col_axis != -1) { if (p_highlight_only) { - spatial_editor->select_gizmo_highlight_axis(col_axis + 9); + spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_scale ? 12 : 9)); } else { //handle scale _edit.mode = TRANSFORM_SCALE; _compute_edit(Point2(p_screenpos.x, p_screenpos.y)); - _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis); + _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_scale ? 3 : 0)); } return true; } @@ -1255,6 +1287,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Vector3 motion_mask; Plane plane; + bool plane_mv = false; switch (_edit.plane) { case TRANSFORM_VIEW: @@ -1273,6 +1306,21 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2); plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized()); break; + case TRANSFORM_YZ: + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(1); + plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0)); + plane_mv = true; + break; + case TRANSFORM_XZ: + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(0); + plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1)); + plane_mv = true; + break; + case TRANSFORM_XY: + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0) + spatial_editor->get_gizmo_transform().basis.get_axis(1); + plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2)); + plane_mv = true; + break; } Vector3 intersection; @@ -1284,8 +1332,19 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { break; Vector3 motion = intersection - click; - if (motion_mask != Vector3()) { - motion = motion_mask.dot(motion) * motion_mask; + if (_edit.plane != TRANSFORM_VIEW) { + + if (!plane_mv) { + + motion = motion_mask.dot(motion) * motion_mask; + + } else { + + // Alternative planar scaling mode + if (_get_key_modifier(m) != KEY_SHIFT) { + motion = motion_mask.dot(motion) * motion_mask; + } + } } else { float center_click_dist = click.distance_to(_edit.center); @@ -1379,7 +1438,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { switch (_edit.plane) { case TRANSFORM_VIEW: - motion_mask = Vector3(0, 0, 0); plane = Plane(_edit.center, _get_camera_normal()); break; case TRANSFORM_X_AXIS: @@ -1417,7 +1475,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { break; Vector3 motion = intersection - click; - if (motion_mask != Vector3()) { + if (_edit.plane != TRANSFORM_VIEW) { if (!plane_mv) { motion = motion_mask.dot(motion) * motion_mask; } @@ -2099,6 +2157,29 @@ void SpatialEditorViewport::_notification(int p_what) { } } + // FPS Counter. + bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS)); + if (show_fps != fps->is_visible()) { + if (show_fps) + fps->show(); + else + fps->hide(); + } + + if (show_fps) { + String text; + const float temp_fps = Engine::get_singleton()->get_frames_per_second(); + text += TTR("FPS") + ": " + itos(temp_fps) + " (" + String::num(1000.0f / temp_fps, 2) + " ms)"; + + if (fps_label->get_text() != text || surface->get_size() != prev_size) { + fps_label->set_text(text); + Size2 ms = fps->get_size(); + Size2 size = surface->get_size(); + size.y = ms.y + 20; + fps->set_position(size - ms - Vector2(20, 0) * EDSCALE); + } + } + prev_size = surface->get_size(); } @@ -2109,6 +2190,7 @@ void SpatialEditorViewport::_notification(int p_what) { surface->connect("mouse_entered", this, "_smouseenter"); surface->connect("mouse_exited", this, "_smouseexit"); info->add_style_override("panel", get_stylebox("panel", "Panel")); + fps->add_style_override("panel", get_stylebox("panel", "Panel")); preview_camera->set_icon(get_icon("Camera", "EditorIcons")); _init_gizmo_instance(index); } @@ -2431,6 +2513,13 @@ void SpatialEditorViewport::_menu_option(int p_option) { view_menu->get_popup()->set_item_checked(idx, !current); } break; + case VIEW_FPS: { + + int idx = view_menu->get_popup()->get_item_index(VIEW_FPS); + bool current = view_menu->get_popup()->is_item_checked(idx); + view_menu->get_popup()->set_item_checked(idx, !current); + + } break; case VIEW_DISPLAY_NORMAL: { viewport->set_debug_draw(Viewport::DEBUG_DRAW_DISABLED); @@ -2516,6 +2605,14 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { //VS::get_singleton()->instance_geometry_set_flag(scale_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer); + + scale_plane_gizmo_instance[i] = VS::get_singleton()->instance_create(); + VS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid()); + VS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); + VS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); + //VS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); + VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); + VS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer); } } @@ -2526,6 +2623,7 @@ void SpatialEditorViewport::_finish_gizmo_instances() { VS::get_singleton()->free(move_plane_gizmo_instance[i]); VS::get_singleton()->free(rotate_gizmo_instance[i]); VS::get_singleton()->free(scale_gizmo_instance[i]); + VS::get_singleton()->free(scale_plane_gizmo_instance[i]); } } void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) { @@ -2622,6 +2720,8 @@ void SpatialEditorViewport::update_transform_gizmo_view() { VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE)); VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform); VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE)); + VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform); + VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE)); } } @@ -3149,6 +3249,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION); + view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true); view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION); @@ -3191,6 +3292,14 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed info->add_child(info_label); info->hide(); + // FPS Counter. + fps = memnew(PanelContainer); + fps->set_self_modulate(Color(1, 1, 1, 0.4)); + surface->add_child(fps); + fps_label = memnew(Label); + fps->add_child(fps_label); + fps->hide(); + accept = NULL; freelook_active = false; @@ -3528,6 +3637,7 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? gizmo_hl : plane_gizmo_color[i]); rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_hl : gizmo_color[i]); scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_hl : gizmo_color[i]); + scale_plane_gizmo[i]->surface_set_material(0, (i + 12) == p_axis ? gizmo_hl : plane_gizmo_color[i]); } } @@ -4101,6 +4211,7 @@ void SpatialEditor::_init_indicators() { move_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); + scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); Ref<SpatialMaterial> mat = memnew(SpatialMaterial); mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); @@ -4296,6 +4407,49 @@ void SpatialEditor::_init_indicators() { surftool->set_material(mat); surftool->commit(scale_gizmo[i]); } + + // Plane Scale + { + Ref<SurfaceTool> surftool = memnew(SurfaceTool); + surftool->begin(Mesh::PRIMITIVE_TRIANGLES); + + Vector3 vec = ivec2 - ivec3; + Vector3 plane[4] = { + vec * GIZMO_PLANE_DST, + vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE, + vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE), + vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE + }; + + Basis ma(ivec, Math_PI / 2); + + Vector3 points[4] = { + ma.xform(plane[0]), + ma.xform(plane[1]), + ma.xform(plane[2]), + ma.xform(plane[3]), + }; + surftool->add_vertex(points[0]); + surftool->add_vertex(points[1]); + surftool->add_vertex(points[2]); + + surftool->add_vertex(points[0]); + surftool->add_vertex(points[2]); + surftool->add_vertex(points[3]); + + Ref<SpatialMaterial> plane_mat = memnew(SpatialMaterial); + plane_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + plane_mat->set_on_top_of_alpha(); + plane_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + plane_mat->set_cull_mode(SpatialMaterial::CULL_DISABLED); + Color col; + col[i] = 1.0; + col.a = gizmo_alph; + plane_mat->set_albedo(col); + plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides + surftool->set_material(plane_mat); + surftool->commit(scale_plane_gizmo[i]); + } } } diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 0ef85b72d9..c986e45f43 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -88,6 +88,7 @@ class SpatialEditorViewport : public Control { VIEW_AUDIO_DOPPLER, VIEW_GIZMOS, VIEW_INFORMATION, + VIEW_FPS, VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_OVERDRAW, @@ -138,6 +139,9 @@ private: PanelContainer *info; Label *info_label; + PanelContainer *fps; + Label *fps_label; + struct _RayResult { Spatial *item; @@ -255,7 +259,7 @@ private: real_t zoom_indicator_delay; - RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3]; + RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3], scale_plane_gizmo_instance[3]; String last_message; String message; @@ -418,7 +422,7 @@ private: bool grid_enable[3]; //should be always visible if true bool grid_enabled; - Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3]; + Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3], scale_plane_gizmo[3]; Ref<SpatialMaterial> gizmo_color[3]; Ref<SpatialMaterial> plane_gizmo_color[3]; Ref<SpatialMaterial> gizmo_hl; @@ -571,6 +575,7 @@ public: Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; } Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; } 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]; } void update_transform_gizmo(); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index cc9de3e44d..16b85121ef 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -233,7 +233,7 @@ private: fdialog->set_mode(FileDialog::MODE_OPEN_FILE); fdialog->clear_filters(); - fdialog->add_filter("project.godot ; " _MKSTR(VERSION_NAME) " Project"); + fdialog->add_filter("project.godot ; " VERSION_NAME " Project"); } else { fdialog->set_mode(FileDialog::MODE_OPEN_DIR); } @@ -1483,13 +1483,13 @@ ProjectManager::ProjectManager() { String cp; cp.push_back(0xA9); cp.push_back(0); - OS::get_singleton()->set_window_title(_MKSTR(VERSION_NAME) + String(" - ") + TTR("Project Manager") + " - " + cp + " 2008-2017 Juan Linietsky, Ariel Manzur & Godot Contributors"); + OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2008-2017 Juan Linietsky, Ariel Manzur & Godot Contributors"); HBoxContainer *top_hb = memnew(HBoxContainer); vb->add_child(top_hb); CenterContainer *ccl = memnew(CenterContainer); Label *l = memnew(Label); - l->set_text(_MKSTR(VERSION_NAME) + String(" - ") + TTR("Project Manager")); + l->set_text(VERSION_NAME + String(" - ") + TTR("Project Manager")); ccl->add_child(l); top_hb->add_child(ccl); top_hb->add_spacer(); @@ -1498,11 +1498,8 @@ ProjectManager::ProjectManager() { if (hash.length() != 0) hash = "." + hash.left(7); l->set_text("v" VERSION_MKSTRING "" + hash); - //l->add_font_override("font",get_font("bold","Fonts")); l->set_align(Label::ALIGN_CENTER); top_hb->add_child(l); - //vb->add_child(memnew(HSeparator)); - //vb->add_margin_child("\n",memnew(Control)); Control *center_box = memnew(Control); center_box->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/pvrtc_compress.cpp b/editor/pvrtc_compress.cpp index 13d74a6593..575ff40287 100644 --- a/editor/pvrtc_compress.cpp +++ b/editor/pvrtc_compress.cpp @@ -62,12 +62,12 @@ static void _compress_image(Image::CompressMode p_mode, Image *p_image) { } return; } - String spath = EditorSettings::get_singleton()->get_settings_path(); + String tmppath = EditorSettings::get_singleton()->get_cache_dir(); List<String> args; - String src_img = spath + "/" + "_tmp_src_img.png"; - String dst_img = spath + "/" + "_tmp_dst_img.pvr"; + String src_img = tmppath.plus_file("_tmp_src_img.png"); + String dst_img = tmppath.plus_file("_tmp_dst_img.pvr"); args.push_back("-i"); args.push_back(src_img); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 816156ef00..21ac27dc4e 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1459,6 +1459,8 @@ void SceneTreeDock::_create() { for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) continue; + if (E->get().name == "__meta__") + continue; newnode->set(E->get().name, n->get(E->get().name)); } diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 0f1712c224..3cab14b0c4 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -128,7 +128,7 @@ void ScriptCreateDialog::_template_changed(int p_template) { } String ext = ScriptServer::get_language(language_menu->get_selected())->get_extension(); String name = template_list[p_template - 1] + "." + ext; - script_template = EditorSettings::get_singleton()->get_settings_path() + "/script_templates/" + name; + script_template = EditorSettings::get_singleton()->get_script_templates_dir().plus_file(name); } void ScriptCreateDialog::ok_pressed() { diff --git a/main/main.cpp b/main/main.cpp index 023520017b..c4bca94b44 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -177,7 +177,7 @@ static String get_full_version_string() { void Main::print_help(const char *p_binary) { - print_line(String(_MKSTR(VERSION_NAME)) + " v" + get_full_version_string() + " - https://godotengine.org"); + print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - https://godotengine.org"); OS::get_singleton()->print("(c) 2007-2017 Juan Linietsky, Ariel Manzur.\n"); OS::get_singleton()->print("(c) 2014-2017 Godot Engine contributors.\n"); OS::get_singleton()->print("\n"); @@ -1766,8 +1766,7 @@ bool Main::iteration() { return exit; if (OS::get_singleton()->is_in_low_processor_usage_mode() || !OS::get_singleton()->can_draw()) - //OS::get_singleton()->delay_usec(16600); //apply some delay to force idle time (results in about 60 FPS max) - OS::get_singleton()->delay_usec(1000); //apply some delay to force idle time (results in about 60 FPS max) + OS::get_singleton()->delay_usec(16600); //apply some delay to force idle time (results in about 60 FPS max) else { uint32_t frame_delay = Engine::get_singleton()->get_frame_delay(); if (frame_delay) diff --git a/methods.py b/methods.py index 8fc7f87a41..2be73f02d2 100644 --- a/methods.py +++ b/methods.py @@ -1150,26 +1150,26 @@ def build_gles3_headers(target, source, env): def add_module_version_string(self,s): - self.module_version_string+="."+s + self.module_version_string += "." + s def update_version(module_version_string=""): - rev = "custom_build" + build_name = "custom_build" + if (os.getenv("BUILD_NAME") != None): + build_name = os.getenv("BUILD_NAME") + print("Using custom build name: " + build_name) - if (os.getenv("BUILD_REVISION") != None): - rev = os.getenv("BUILD_REVISION") - print("Using custom revision: " + rev) import version f = open("core/version_generated.gen.h", "w") - f.write("#define VERSION_SHORT_NAME " + str(version.short_name) + "\n") - f.write("#define VERSION_NAME " + str(version.name) + "\n") + f.write("#define VERSION_SHORT_NAME \"" + str(version.short_name) + "\"\n") + f.write("#define VERSION_NAME \"" + str(version.name) + "\"\n") f.write("#define VERSION_MAJOR " + str(version.major) + "\n") f.write("#define VERSION_MINOR " + str(version.minor) + "\n") if (hasattr(version, 'patch')): f.write("#define VERSION_PATCH " + str(version.patch) + "\n") - f.write("#define VERSION_REVISION " + str(rev) + "\n") - f.write("#define VERSION_STATUS " + str(version.status) + "\n") + f.write("#define VERSION_STATUS \"" + str(version.status) + "\"\n") + f.write("#define VERSION_BUILD \"" + str(build_name) + "\"\n") f.write("#define VERSION_MODULE_CONFIG \"" + str(version.module_config) + module_version_string + "\"\n") import datetime f.write("#define VERSION_YEAR " + str(datetime.datetime.now().year) + "\n") @@ -1686,6 +1686,17 @@ def find_visual_c_batch_file(env): (host_platform, target_platform,req_target_platform) = get_host_target(env) return find_batch_file(env, version, host_platform, target_platform)[0] +def generate_cpp_hint_file(filename): + import os.path + if os.path.isfile(filename): + # Don't overwrite an existing hint file since the user may have customized it. + pass + else: + try: + fd = open(filename, "w") + fd.write("#define GDCLASS(m_class, m_inherits)\n") + except IOError: + print("Could not write cpp.hint file.") def generate_vs_project(env, num_jobs): batch_file = find_visual_c_batch_file(env) diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index bc60c9cb6b..cbf30c8a2e 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -77,7 +77,7 @@ btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalCo PhysicsDirectSpaceState::ShapeResult &result = m_results[count]; - result.shape = convexResult.m_localShapeInfo->m_shapePart; + result.shape = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID result.rid = gObj->get_self(); result.collider_id = gObj->get_instance_id(); result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id); @@ -122,7 +122,7 @@ bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) { btScalar res = btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); - m_shapePart = convexResult.m_localShapeInfo->m_shapePart; + m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID return res; } @@ -242,3 +242,21 @@ btScalar GodotRestInfoContactResultCallback::addSingleResult(btManifoldPoint &cp return cp.getDistance(); } + +void GodotDeepPenetrationContactResultCallback::addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth) { + + if (depth < 0) { + // Has penetration + if (m_most_penetrated_distance > depth) { + + bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); + + m_most_penetrated_distance = depth; + m_pointCollisionObject = (isSwapped ? m_body0Wrap : m_body1Wrap)->getCollisionObject(); + m_other_compound_shape_index = isSwapped ? m_index1 : m_index0; + m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld; + m_pointWorld = isSwapped ? (pointInWorldOnB + normalOnBInWorld * depth) : pointInWorldOnB; + m_penetration_distance = depth; + } + } +} diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h index 68dff5b12a..ba5142676b 100644 --- a/modules/bullet/godot_result_callbacks.h +++ b/modules/bullet/godot_result_callbacks.h @@ -88,7 +88,7 @@ public: struct GodotClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: const Set<RID> *m_exclude; - int m_shapePart; + int m_shapeId; GodotClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const Set<RID> *p_exclude) : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), m_exclude(p_exclude) {} @@ -149,4 +149,31 @@ public: virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); }; +struct GodotDeepPenetrationContactResultCallback : public btManifoldResult { + btVector3 m_pointNormalWorld; + btVector3 m_pointWorld; + btScalar m_penetration_distance; + int m_other_compound_shape_index; + const btCollisionObject *m_pointCollisionObject; + + btScalar m_most_penetrated_distance; + + GodotDeepPenetrationContactResultCallback(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) + : btManifoldResult(body0Wrap, body1Wrap), + m_pointCollisionObject(NULL), + m_penetration_distance(0), + m_other_compound_shape_index(0), + m_most_penetrated_distance(1e20) {} + + void reset() { + m_pointCollisionObject = NULL; + m_most_penetrated_distance = 1e20; + } + + bool hasHit() { + return m_pointCollisionObject; + } + + virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorld, btScalar depth); +}; #endif // GODOT_RESULT_CALLBACKS_H diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 9df01aee3e..e4d049b00d 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -115,12 +115,13 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); - btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape()); - if (!btConvex) { - bulletdelete(btConvex); + btCollisionShape *btShape = shape->create_bt_shape(); + if (!btShape->isConvex()) { + bulletdelete(btShape); ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); return 0; } + btConvexShape *btConvex = static_cast<btConvexShape *>(btShape); btVector3 scale_with_margin; G_TO_B(p_xform.basis.get_scale(), scale_with_margin); @@ -147,12 +148,13 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask, ShapeRestInfo *r_info) { ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); - btConvexShape *bt_convex_shape = dynamic_cast<btConvexShape *>(shape->create_bt_shape()); - if (!bt_convex_shape) { - bulletdelete(bt_convex_shape); + btCollisionShape *btShape = shape->create_bt_shape(); + if (!btShape->isConvex()) { + bulletdelete(btShape); ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); return 0; } + btConvexShape *bt_convex_shape = static_cast<btConvexShape *>(btShape); btVector3 bt_motion; G_TO_B(p_motion, bt_motion); @@ -173,17 +175,19 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf space->dynamicsWorld->convexSweepTest(bt_convex_shape, bt_xform_from, bt_xform_to, btResult, 0.002); - if (btResult.hasHit()) { - if (btCollisionObject::CO_RIGID_BODY == btResult.m_hitCollisionObject->getInternalType()) { - B_TO_G(static_cast<const btRigidBody *>(btResult.m_hitCollisionObject)->getVelocityInLocalPoint(btResult.m_hitPointWorld), r_info->linear_velocity); + if (r_info) { + if (btResult.hasHit()) { + if (btCollisionObject::CO_RIGID_BODY == btResult.m_hitCollisionObject->getInternalType()) { + B_TO_G(static_cast<const btRigidBody *>(btResult.m_hitCollisionObject)->getVelocityInLocalPoint(btResult.m_hitPointWorld), r_info->linear_velocity); + } + CollisionObjectBullet *collision_object = static_cast<CollisionObjectBullet *>(btResult.m_hitCollisionObject->getUserPointer()); + p_closest_safe = p_closest_unsafe = btResult.m_closestHitFraction; + B_TO_G(btResult.m_hitPointWorld, r_info->point); + B_TO_G(btResult.m_hitNormalWorld, r_info->normal); + r_info->rid = collision_object->get_self(); + r_info->collider_id = collision_object->get_instance_id(); + r_info->shape = btResult.m_shapeId; } - CollisionObjectBullet *collision_object = static_cast<CollisionObjectBullet *>(btResult.m_hitCollisionObject->getUserPointer()); - p_closest_safe = p_closest_unsafe = btResult.m_closestHitFraction; - B_TO_G(btResult.m_hitPointWorld, r_info->point); - B_TO_G(btResult.m_hitNormalWorld, r_info->normal); - r_info->rid = collision_object->get_self(); - r_info->collider_id = collision_object->get_instance_id(); - r_info->shape = btResult.m_shapePart; } bulletdelete(bt_convex_shape); @@ -197,12 +201,13 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); - btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape()); - if (!btConvex) { - bulletdelete(btConvex); + btCollisionShape *btShape = shape->create_bt_shape(); + if (!btShape->isConvex()) { + bulletdelete(btShape); ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); return 0; } + btConvexShape *btConvex = static_cast<btConvexShape *>(btShape); btVector3 scale_with_margin; G_TO_B(p_shape_xform.basis.get_scale(), scale_with_margin); @@ -231,12 +236,13 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); - btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape()); - if (!btConvex) { - bulletdelete(btConvex); + btCollisionShape *btShape = shape->create_bt_shape(); + if (!btShape->isConvex()) { + bulletdelete(btShape); ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); return 0; } + btConvexShape *btConvex = static_cast<btConvexShape *>(btShape); btVector3 scale_with_margin; G_TO_B(p_shape_xform.basis.get_scale() + Vector3(p_margin, p_margin, p_margin), scale_with_margin); @@ -777,7 +783,8 @@ void SpaceBullet::check_body_collision() { void SpaceBullet::update_gravity() { btVector3 btGravity; G_TO_B(gravityDirection * gravityMagnitude, btGravity); - dynamicsWorld->setGravity(btGravity); + //dynamicsWorld->setGravity(btGravity); + dynamicsWorld->setGravity(btVector3(0, 0, 0)); if (soft_body_world_info) { soft_body_world_info->m_gravity = btGravity; } @@ -877,11 +884,11 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f continue; } - btConvexShape *convex_shape_test(dynamic_cast<btConvexShape *>(p_body->get_bt_shape(shIndex))); - if (!convex_shape_test) { + if (!p_body->get_bt_shape(shIndex)->isConvex()) { // Skip no convex shape continue; } + btConvexShape *convex_shape_test(static_cast<btConvexShape *>(p_body->get_bt_shape(shIndex))); btTransform shape_world_from; G_TO_B(p_body->get_shape_transform(shIndex), shape_world_from); @@ -910,26 +917,26 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f { /// Phase three - Recover + contact test with margin - RecoverResult recover_result; + RecoverResult r_recover_result; - hasPenetration = recover_from_penetration(p_body, body_safe_position, recovered_motion, &recover_result); + hasPenetration = recover_from_penetration(p_body, body_safe_position, recovered_motion, &r_recover_result); if (r_result) { B_TO_G(recovered_motion + recover_initial_position, r_result->motion); if (hasPenetration) { - const btRigidBody *btRigid = static_cast<const btRigidBody *>(recover_result.other_collision_object); + const btRigidBody *btRigid = static_cast<const btRigidBody *>(r_recover_result.other_collision_object); CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(btRigid->getUserPointer()); r_result->remainder = p_motion - r_result->motion; // is the remaining movements - B_TO_G(recover_result.pointWorld, r_result->collision_point); - B_TO_G(recover_result.pointNormalWorld, r_result->collision_normal); - B_TO_G(btRigid->getVelocityInLocalPoint(recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); // It calculates velocity at point and assign it using special function Bullet_to_Godot + B_TO_G(r_recover_result.pointWorld, r_result->collision_point); + B_TO_G(r_recover_result.pointNormalWorld, r_result->collision_normal); + B_TO_G(btRigid->getVelocityInLocalPoint(r_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); // It calculates velocity at point and assign it using special function Bullet_to_Godot r_result->collider = collisionObject->get_self(); r_result->collider_id = collisionObject->get_instance_id(); - r_result->collider_shape = recover_result.other_compound_shape_index; - r_result->collision_local_shape = recover_result.local_shape_most_recovered; + r_result->collider_shape = r_recover_result.other_compound_shape_index; + r_result->collision_local_shape = r_recover_result.local_shape_most_recovered; //{ /// Add manifold point to manage collisions // btPersistentManifold* manifold = dynamicsWorld->getDispatcher()->getNewManifold(p_body->getBtBody(), btRigid); @@ -995,7 +1002,7 @@ public: } }; -bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btVector3 &out_recover_position, RecoverResult *recover_result) { +bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btVector3 &r_recover_position, RecoverResult *r_recover_result) { RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask()); @@ -1005,9 +1012,6 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran // Broad phase support btVector3 minAabb, maxAabb; - // GJK support - btGjkPairDetector::ClosestPointInput gjk_input; - bool penetration = false; // For each shape @@ -1022,7 +1026,7 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran body_shape_position = p_body_position * kin_shape.transform; body_shape_position_recovered = body_shape_position; - body_shape_position_recovered.getOrigin() += out_recover_position; + body_shape_position_recovered.getOrigin() += r_recover_position; kin_shape.shape->getAabb(body_shape_position_recovered, minAabb, maxAabb); dynamicsWorld->getBroadphase()->aabbTest(minAabb, maxAabb, recover_broad_result); @@ -1032,66 +1036,33 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object())) continue; - if (otherObject->getCollisionShape()->isCompound()) { /// Execute GJK test against all shapes + if (otherObject->getCollisionShape()->isCompound()) { // Each convex shape btCompoundShape *cs = static_cast<btCompoundShape *>(otherObject->getCollisionShape()); for (int x = cs->getNumChildShapes() - 1; 0 <= x; --x) { - if (!cs->getChildShape(x)->isConvex()) - continue; + if (cs->getChildShape(x)->isConvex()) { + if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(cs->getChildShape(x)), otherObject, x, body_shape_position, otherObject->getWorldTransform() * cs->getChildTransform(x), r_recover_position, r_recover_result)) { - // Initialize GJK input - gjk_input.m_transformA = body_shape_position; - gjk_input.m_transformA.getOrigin() += out_recover_position; - gjk_input.m_transformB = otherObject->getWorldTransform() * cs->getChildTransform(x); + penetration = true; + } + } else { + if (RFP_convex_world_test(kin_shape.shape, cs->getChildShape(x), p_body->get_bt_collision_object(), otherObject, kinIndex, x, body_shape_position, otherObject->getWorldTransform() * cs->getChildTransform(x), r_recover_position, r_recover_result)) { - // Perform GJK test - btPointCollector result; - btGjkPairDetector gjk_pair_detector(kin_shape.shape, static_cast<const btConvexShape *>(cs->getChildShape(x)), gjk_simplex_solver, gjk_epa_pen_solver); - gjk_pair_detector.getClosestPoints(gjk_input, result, 0); - if (0 > result.m_distance) { - // Has penetration - out_recover_position += result.m_normalOnBInWorld * (result.m_distance * -1); - penetration = true; - - if (recover_result) { - - recover_result->hasPenetration = true; - recover_result->other_collision_object = otherObject; - recover_result->other_compound_shape_index = x; - recover_result->penetration_distance = result.m_distance; - recover_result->pointNormalWorld = result.m_normalOnBInWorld; - recover_result->pointWorld = result.m_pointInWorld; + penetration = true; } } } - } else if (otherObject->getCollisionShape()->isConvex()) { /// Execute GJK test against object shape + if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(otherObject->getCollisionShape()), otherObject, 0, body_shape_position, otherObject->getWorldTransform(), r_recover_position, r_recover_result)) { - // Initialize GJK input - gjk_input.m_transformA = body_shape_position; - gjk_input.m_transformA.getOrigin() += out_recover_position; - gjk_input.m_transformB = otherObject->getWorldTransform(); - - // Perform GJK test - btPointCollector result; - btGjkPairDetector gjk_pair_detector(kin_shape.shape, static_cast<const btConvexShape *>(otherObject->getCollisionShape()), gjk_simplex_solver, gjk_epa_pen_solver); - gjk_pair_detector.getClosestPoints(gjk_input, result, 0); - if (0 > result.m_distance) { - // Has penetration - out_recover_position += result.m_normalOnBInWorld * (result.m_distance * -1); penetration = true; + } + } else { + if (RFP_convex_world_test(kin_shape.shape, otherObject->getCollisionShape(), p_body->get_bt_collision_object(), otherObject, kinIndex, 0, body_shape_position, otherObject->getWorldTransform(), r_recover_position, r_recover_result)) { - if (recover_result) { - - recover_result->hasPenetration = true; - recover_result->other_collision_object = otherObject; - recover_result->other_compound_shape_index = 0; - recover_result->penetration_distance = result.m_distance; - recover_result->pointNormalWorld = result.m_normalOnBInWorld; - recover_result->pointWorld = result.m_pointInWorld; - } + penetration = true; } } } @@ -1099,3 +1070,70 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran return penetration; } + +bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btVector3 &r_recover_position, RecoverResult *r_recover_result) { + + // Initialize GJK input + btGjkPairDetector::ClosestPointInput gjk_input; + gjk_input.m_transformA = p_transformA; + gjk_input.m_transformA.getOrigin() += r_recover_position; + gjk_input.m_transformB = p_transformB; + + // Perform GJK test + btPointCollector result; + btGjkPairDetector gjk_pair_detector(p_shapeA, p_shapeB, gjk_simplex_solver, gjk_epa_pen_solver); + gjk_pair_detector.getClosestPoints(gjk_input, result, 0); + if (0 > result.m_distance) { + // Has penetration + r_recover_position += result.m_normalOnBInWorld * (result.m_distance * -1); + + if (r_recover_result) { + + r_recover_result->hasPenetration = true; + r_recover_result->other_collision_object = p_objectB; + r_recover_result->other_compound_shape_index = p_shapeId_B; + r_recover_result->penetration_distance = result.m_distance; + r_recover_result->pointNormalWorld = result.m_normalOnBInWorld; + r_recover_result->pointWorld = result.m_pointInWorld; + } + return true; + } + return false; +} + +bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btVector3 &r_recover_position, RecoverResult *r_recover_result) { + + /// Contact test + + btTransform p_recovered_transformA(p_transformA); + p_recovered_transformA.getOrigin() += r_recover_position; + + btCollisionObjectWrapper obA(NULL, p_shapeA, p_objectA, p_recovered_transformA, -1, p_shapeId_A); + btCollisionObjectWrapper obB(NULL, p_shapeB, p_objectB, p_transformB, -1, p_shapeId_B); + + btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, NULL, BT_CLOSEST_POINT_ALGORITHMS); + if (algorithm) { + GodotDeepPenetrationContactResultCallback contactPointResult(&obA, &obB); + //discrete collision detection query + algorithm->processCollision(&obA, &obB, dynamicsWorld->getDispatchInfo(), &contactPointResult); + + algorithm->~btCollisionAlgorithm(); + dispatcher->freeCollisionAlgorithm(algorithm); + + if (contactPointResult.hasHit()) { + r_recover_position += contactPointResult.m_pointNormalWorld * (contactPointResult.m_penetration_distance * -1); + + if (r_recover_result) { + + r_recover_result->hasPenetration = true; + r_recover_result->other_collision_object = p_objectB; + r_recover_result->other_compound_shape_index = p_shapeId_B; + r_recover_result->penetration_distance = contactPointResult.m_penetration_distance; + r_recover_result->pointNormalWorld = contactPointResult.m_pointNormalWorld; + r_recover_result->pointWorld = contactPointResult.m_pointWorld; + } + return true; + } + } + return false; +} diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index d9206f8046..9acac9a7d6 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -189,6 +189,12 @@ private: : hasPenetration(false) {} }; - bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btVector3 &out_recover_position, RecoverResult *recover_result = NULL); + bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btVector3 &r_recover_position, RecoverResult *r_recover_result = NULL); + /// This is an API that recover a kinematic object from penetration + /// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions + bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btVector3 &r_recover_position, RecoverResult *r_recover_result); + /// This is an API that recover a kinematic object from penetration + /// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm + bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btVector3 &r_recover_position, RecoverResult *r_recover_result); }; #endif diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index c50886ad3c..1e18ec0d18 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -505,7 +505,7 @@ uint32_t NetworkedMultiplayerENet::_gen_unique_id() const { hash = hash_djb2_one_32( (uint32_t)OS::get_singleton()->get_unix_time(), hash); hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_data_dir().hash64(), hash); + (uint32_t)OS::get_singleton()->get_user_data_dir().hash64(), hash); /* hash = hash_djb2_one_32( (uint32_t)OS::get_singleton()->get_unique_id().hash64(), hash ); diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 7cc2168b70..a0c2508b0d 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -57,7 +57,7 @@ String _get_expected_build_config() { String _get_mono_user_dir() { #ifdef TOOLS_ENABLED if (EditorSettings::get_singleton()) { - return EditorSettings::get_singleton()->get_settings_path().plus_file("mono"); + return EditorSettings::get_singleton()->get_data_dir().plus_file("mono"); } else { String settings_path; @@ -68,19 +68,13 @@ String _get_mono_user_dir() { // contain yourself settings_path = exe_dir.plus_file("editor_data"); } else { - if (OS::get_singleton()->has_environment("APPDATA")) { - String app_data = OS::get_singleton()->get_environment("APPDATA").replace("\\", "/"); - settings_path = app_data.plus_file(String(_MKSTR(VERSION_SHORT_NAME)).capitalize()); - } else if (OS::get_singleton()->has_environment("HOME")) { - String home = OS::get_singleton()->get_environment("HOME"); - settings_path = home.plus_file("." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower()); - } + settings_path = OS::get_singleton()->get_data_path().plus_file(OS::get_singleton()->get_godot_dir_name()); } return settings_path.plus_file("mono"); } #else - return OS::get_singleton()->get_data_dir().plus_file("mono"); + return OS::get_singleton()->get_user_data_dir().plus_file("mono"); #endif } diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 7cb6cf860a..11c49fbb50 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -31,7 +31,7 @@ android { disable 'MissingTranslation' } - compileSdkVersion 23 + compileSdkVersion 24 buildToolsVersion "26.0.1" useLibrary 'org.apache.http.legacy' diff --git a/platform/android/detect.py b/platform/android/detect.py index a3ada5cf51..bc67f6e6dc 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -205,7 +205,7 @@ def configure(env): env.Append(CPPFLAGS=["-isystem", lib_sysroot + "/usr/include"]) env.Append(CPPFLAGS='-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'.split()) - env.Append(CPPFLAGS='-DNO_STATVFS -DGLES2_ENABLED'.split()) + env.Append(CPPFLAGS='-DNO_STATVFS -DGLES_ENABLED'.split()) env['neon_enabled'] = False if env['android_arch'] == 'x86': diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 79be1501a7..e1ff12c5ac 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -370,7 +370,7 @@ class EditorExportAndroid : public EditorExportPlatform { } if (aname == "") { - aname = _MKSTR(VERSION_NAME); + aname = VERSION_NAME; } return aname; @@ -945,16 +945,17 @@ public: public: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { - int api = p_preset->get("graphics/api"); + // Reenable when a GLES 2.0 backend is readded + /*int api = p_preset->get("graphics/api"); if (api == 0) r_features->push_back("etc"); - else - r_features->push_back("etc2"); + else*/ + r_features->push_back("etc2"); } virtual void get_export_options(List<ExportOption> *r_options) { - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/api", PROPERTY_HINT_ENUM, "OpenGL ES 2.0,OpenGL ES 3.0"), 1)); + /*r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/api", PROPERTY_HINT_ENUM, "OpenGL ES 2.0,OpenGL ES 3.0"), 1));*/ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "apk"), "")); @@ -1066,7 +1067,7 @@ public: if (use_reverse) p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST; - String export_to = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpexport.apk"; + String export_to = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport.apk"); Error err = export_project(p_preset, true, export_to, p_debug_flags); if (err) { device_lock->unlock(); @@ -1291,7 +1292,7 @@ public: zlib_filefunc_def io2 = io; FileAccess *dst_f = NULL; io2.opaque = &dst_f; - String unaligned_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpexport-unaligned.apk"; + String unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned.apk"); zipFile unaligned_apk = zipOpen2(unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); bool export_x86 = p_preset->get("architecture/x86"); diff --git a/platform/android/globals/global_defaults.cpp b/platform/android/globals/global_defaults.cpp index c73b578154..0e1c17e9c8 100644 --- a/platform/android/globals/global_defaults.cpp +++ b/platform/android/globals/global_defaults.cpp @@ -31,12 +31,4 @@ #include "project_settings.h" void register_android_global_defaults() { - - /* GLOBAL_DEF("rasterizer.Android/use_fragment_lighting",false); - GLOBAL_DEF("rasterizer.Android/fp16_framebuffer",false); - GLOBAL_DEF("display.Android/driver","GLES2"); - //GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false); - - ProjectSettings::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES2")); - */ } diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp index 9d056bca7c..f9bcbadc24 100644 --- a/platform/android/godot_android.cpp +++ b/platform/android/godot_android.cpp @@ -29,24 +29,23 @@ /*************************************************************************/ #ifdef ANDROID_NATIVE_ACTIVITY -#include <errno.h> -#include <jni.h> - -#include <EGL/egl.h> -#include <GLES2/gl2.h> - #include "engine.h" #include "file_access_android.h" #include "main/main.h" #include "os_android.h" #include "project_settings.h" + +#include <EGL/egl.h> #include <android/log.h> #include <android/sensor.h> #include <android/window.h> #include <android_native_app_glue.h> +#include <errno.h> +#include <jni.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "godot", __VA_ARGS__)) #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "godot", __VA_ARGS__)) diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 90144d9b4d..40dfe6d909 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -647,7 +647,7 @@ static int _open_uri(const String &p_uri) { return env->CallIntMethod(godot_io, _openURI, jStr); } -static String _get_data_dir() { +static String _get_user_data_dir() { JNIEnv *env = ThreadAndroid::get_env(); jstring s = (jstring)env->CallObjectMethod(godot_io, _getDataDir); @@ -825,7 +825,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en AudioDriverAndroid::setup(gob); } - os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion); + os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_user_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion); os_android->set_need_reload_hooks(p_need_reload_hook); char wd[500]; diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 2578bd6d96..d5ccf76631 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -612,13 +612,13 @@ void OS_Android::set_need_reload_hooks(bool p_needs_them) { use_reload_hooks = p_needs_them; } -String OS_Android::get_data_dir() const { +String OS_Android::get_user_data_dir() const { if (data_dir_cache != String()) return data_dir_cache; - if (get_data_dir_func) { - String data_dir = get_data_dir_func(); + if (get_user_data_dir_func) { + String data_dir = get_user_data_dir_func(); //store current dir char real_current_dir_name[2048]; @@ -641,7 +641,6 @@ String OS_Android::get_data_dir() const { } return "."; - //return Engine::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); } void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) { @@ -709,7 +708,7 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) { return p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2"; //TODO support etc2 only if GLES3 driver is selected } -OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { +OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { use_apk_expansion = p_use_apk_expansion; default_videomode.width = 800; @@ -725,7 +724,7 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI use_gl2 = false; open_uri_func = p_open_uri_func; - get_data_dir_func = p_get_data_dir_func; + get_user_data_dir_func = p_get_user_data_dir_func; get_locale_func = p_get_locale_func; get_model_func = p_get_model_func; get_screen_dpi_func = p_get_screen_dpi_func; diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 750afa7a14..d25f60d540 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -48,7 +48,7 @@ typedef void (*GFXInitFunc)(void *ud, bool gl2); typedef int (*OpenURIFunc)(const String &); -typedef String (*GetDataDirFunc)(); +typedef String (*GetUserDataDirFunc)(); typedef String (*GetLocaleFunc)(); typedef String (*GetModelFunc)(); typedef int (*GetScreenDPIFunc)(); @@ -116,7 +116,7 @@ private: MainLoop *main_loop; OpenURIFunc open_uri_func; - GetDataDirFunc get_data_dir_func; + GetUserDataDirFunc get_user_data_dir_func; GetLocaleFunc get_locale_func; GetModelFunc get_model_func; GetScreenDPIFunc get_screen_dpi_func; @@ -208,7 +208,7 @@ public: virtual void set_screen_orientation(ScreenOrientation p_orientation); virtual Error shell_open(String p_uri); - virtual String get_data_dir() const; + virtual String get_user_data_dir() const; virtual String get_resource_dir() const; virtual String get_locale() const; virtual String get_model_name() const; @@ -237,7 +237,7 @@ public: void joy_connection_changed(int p_device, bool p_connected, String p_name); virtual bool _check_internal_feature_support(const String &p_feature); - OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); + OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); ~OS_Android(); }; diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py index 50f9783dd2..7c62654ef6 100644 --- a/platform/haiku/detect.py +++ b/platform/haiku/detect.py @@ -67,7 +67,7 @@ def configure(env): ## Flags env.Append(CPPPATH=['#platform/haiku']) - env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) + env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES_ENABLED', '-DGLES_OVER_GL']) env.Append(CPPFLAGS=['-DMEDIA_KIT_ENABLED']) # env.Append(CCFLAGS=['-DFREETYPE_ENABLED']) env.Append(CPPFLAGS=['-DPTHREAD_NO_RENAME']) # TODO: enable when we have pthread_setname_np diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index 0c34e39655..ef5a065107 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -76,7 +76,7 @@ int OS_Haiku::get_video_driver_count() const { } const char *OS_Haiku::get_video_driver_name(int p_driver) const { - return "GLES2"; + return "GLES3"; } void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { @@ -106,7 +106,9 @@ void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_ context_gl->initialize(); context_gl->make_current(); - rasterizer = memnew(RasterizerGLES2); + /* Port to GLES 3 rasterizer */ + //rasterizer = memnew(RasterizerGLES2); + #endif visual_server = memnew(VisualServerRaster(rasterizer)); @@ -314,3 +316,36 @@ bool OS_Haiku::_check_internal_feature_support(const String &p_feature) { return p_feature == "pc" || p_feature == "s3tc"; } + +String OS_Haiku::get_config_path() const { + + if (has_environment("XDG_CONFIG_HOME")) { + return get_environment("XDG_CONFIG_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".config"); + } else { + return "."; + } +} + +String OS_Haiku::get_data_path() const { + + if (has_environment("XDG_DATA_HOME")) { + return get_environment("XDG_DATA_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".local/share"); + } else { + return get_config_path(); + } +} + +String OS_Haiku::get_cache_path() const { + + if (has_environment("XDG_CACHE_HOME")) { + return get_environment("XDG_CACHE_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".cache"); + } else { + return get_config_path(); + } +} diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index 86148f1fb4..4ee54fb48d 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -117,6 +117,10 @@ public: virtual int get_power_percent_left(); virtual bool _check_internal_feature_support(const String &p_feature); + + virtual String get_config_path() const; + virtual String get_data_path() const; + virtual String get_cache_path() const; }; #endif diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index d426b478bf..4ea358f871 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -163,7 +163,7 @@ def configure(env): env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate' env.Append(CPPPATH=['#platform/iphone']) - env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DMPC_FIXED_POINT', '-DCOREAUDIO_ENABLED']) + env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DMPC_FIXED_POINT', '-DCOREAUDIO_ENABLED']) # TODO: Move that to opus module's config if 'module_opus_enabled' in env and env['module_opus_enabled']: diff --git a/platform/iphone/globals/global_defaults.cpp b/platform/iphone/globals/global_defaults.cpp index 4bdc716d6e..b81e6def3b 100644 --- a/platform/iphone/globals/global_defaults.cpp +++ b/platform/iphone/globals/global_defaults.cpp @@ -31,11 +31,4 @@ #include "project_settings.h" void register_iphone_global_defaults() { - - /*GLOBAL_DEF("rasterizer.iOS/use_fragment_lighting",false); - GLOBAL_DEF("rasterizer.iOS/fp16_framebuffer",false); - GLOBAL_DEF("display.iOS/driver","GLES2"); - ProjectSettings::get_singleton()->set_custom_property_info("display.iOS/driver",PropertyInfo(Variant::STRING,"display.iOS/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2")); - GLOBAL_DEF("display.iOS/use_cadisplaylink",true); - */ } diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index d0865a35b9..95d7710c76 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -54,7 +54,7 @@ int OSIPhone::get_video_driver_count() const { const char *OSIPhone::get_video_driver_name(int p_driver) const { - return "GLES2"; + return "GLES3"; }; OSIPhone *OSIPhone::get_singleton() { @@ -470,7 +470,7 @@ void OSIPhone::set_cursor_shape(CursorShape p_shape){ }; -String OSIPhone::get_data_dir() const { +String OSIPhone::get_user_data_dir() const { return data_dir; }; @@ -509,7 +509,7 @@ Error OSIPhone::native_video_play(String p_path, float p_volume, String p_audio_ FileAccess *f = FileAccess::open(p_path, FileAccess::READ); bool exists = f && f->is_open(); - String tempFile = get_data_dir(); + String tempFile = get_user_data_dir(); if (!exists) return FAILED; @@ -521,7 +521,7 @@ Error OSIPhone::native_video_play(String p_path, float p_volume, String p_audio_ p_path = p_path.replace("res:/", ProjectSettings::get_singleton()->get_resource_path()); } } else if (p_path.begins_with("user://")) - p_path = p_path.replace("user:/", get_data_dir()); + p_path = p_path.replace("user:/", get_user_data_dir()); memdelete(f); diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 6627fddf08..433228b599 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -178,7 +178,7 @@ public: Error shell_open(String p_uri); - String get_data_dir() const; + String get_user_data_dir() const; void set_locale(String p_locale); String get_locale() const; diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h index 54de66082e..7ff6e7a9a9 100644 --- a/platform/iphone/platform_config.h +++ b/platform/iphone/platform_config.h @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include <alloca.h> -// #define GLES2_INCLUDE_H <ES2/gl.h> + #define GLES3_INCLUDE_H <ES3/gl.h> #define PLATFORM_REFCOUNT diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index d0d4b17874..943f6d8f35 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -30,6 +30,7 @@ #include "editor/editor_node.h" #include "editor_export.h" #include "io/zip_io.h" +#include "main/splash.gen.h" #include "platform/javascript/logo.gen.h" #include "platform/javascript/run_icon.gen.h" @@ -115,6 +116,7 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_GLOBAL_FILE, "html"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); @@ -156,6 +158,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese String custom_debug = p_preset->get("custom_template/debug"); String custom_release = p_preset->get("custom_template/release"); + String custom_html = p_preset->get("html/custom_html_shell"); String template_path = p_debug ? custom_debug : custom_release; @@ -181,14 +184,6 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese return error; } - FileAccess *f = FileAccess::open(pck_path, FileAccess::READ); - if (!f) { - EditorNode::get_singleton()->show_warning(TTR("Could not read file:\n") + pck_path); - return ERR_FILE_CANT_READ; - } - size_t pack_size = f->get_len(); - memdelete(f); - FileAccess *src_f = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); unzFile pkg = unzOpen2(template_path.utf8().get_data(), &io); @@ -199,13 +194,17 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese return ERR_FILE_NOT_FOUND; } - int ret = unzGoToFirstFile(pkg); - while (ret == UNZ_OK) { + if (unzGoToFirstFile(pkg) != UNZ_OK) { + EditorNode::get_singleton()->show_warning(TTR("Invalid export template:\n") + template_path); + unzClose(pkg); + return ERR_FILE_CORRUPT; + } + do { //get filename unz_file_info info; char fname[16384]; - ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0); + unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0); String file = fname; @@ -221,8 +220,12 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese if (file == "godot.html") { + if (!custom_html.empty()) { + continue; + } _fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug); file = p_path.get_file(); + } else if (file == "godot.js") { file = p_path.get_file().get_basename() + ".js"; @@ -241,9 +244,50 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese f->store_buffer(data.ptr(), data.size()); memdelete(f); - ret = unzGoToNextFile(pkg); + } while (unzGoToNextFile(pkg) == UNZ_OK); + unzClose(pkg); + + if (!custom_html.empty()) { + + FileAccess *f = FileAccess::open(custom_html, FileAccess::READ); + if (!f) { + EditorNode::get_singleton()->show_warning(TTR("Could not read custom HTML shell:\n") + custom_html); + return ERR_FILE_CANT_READ; + } + Vector<uint8_t> buf; + buf.resize(f->get_len()); + f->get_buffer(buf.ptr(), buf.size()); + memdelete(f); + _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug); + + f = FileAccess::open(p_path, FileAccess::WRITE); + if (!f) { + EditorNode::get_singleton()->show_warning(TTR("Could not write file:\n") + p_path); + return ERR_FILE_CANT_WRITE; + } + f->store_buffer(buf.ptr(), buf.size()); + memdelete(f); } + Ref<Image> splash; + String splash_path = GLOBAL_GET("application/boot_splash/image"); + splash_path = splash_path.strip_edges(); + if (!splash_path.empty()) { + splash.instance(); + Error err = splash->load(splash_path); + if (err) { + EditorNode::get_singleton()->show_warning(TTR("Could not read boot splash image file:\n") + splash_path + "\nUsing default boot splash image"); + splash.unref(); + } + } + if (splash.is_null()) { + splash = Ref<Image>(memnew(Image(boot_splash_png))); + } + String png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png"); + if (splash->save_png(png_path) != OK) { + EditorNode::get_singleton()->show_warning(TTR("Could not write file:\n") + png_path); + return ERR_FILE_CANT_WRITE; + } return OK; } @@ -272,7 +316,7 @@ int EditorExportPlatformJavaScript::get_device_count() const { Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { - String path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmp_export.html"; + String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_export.html"); Error err = export_project(p_preset, true, path, p_debug_flags); if (err) { return err; diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 54c0e81421..74cfec14a6 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -882,11 +882,11 @@ String OS_JavaScript::get_resource_dir() const { return "/"; //javascript has it's own filesystem for resources inside the APK } -String OS_JavaScript::get_data_dir() const { +String OS_JavaScript::get_user_data_dir() const { /* - if (get_data_dir_func) - return get_data_dir_func(); + if (get_user_data_dir_func) + return get_user_data_dir_func(); */ return "/userfs"; }; @@ -986,7 +986,7 @@ bool OS_JavaScript::is_userfs_persistent() const { return idbfs_available; } -OS_JavaScript::OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func) { +OS_JavaScript::OS_JavaScript(const char *p_execpath, GetUserDataDirFunc p_get_user_data_dir_func) { set_cmdline(p_execpath, get_cmdline_args()); main_loop = NULL; gl_extensions = NULL; @@ -994,7 +994,7 @@ OS_JavaScript::OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_d soft_fs_enabled = false; canvas_size_adjustment_requested = false; - get_data_dir_func = p_get_data_dir_func; + get_user_data_dir_func = p_get_user_data_dir_func; FileAccessUnix::close_notification_func = _close_notification_funcs; idbfs_available = false; diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 85c185c10f..77eeb02a9f 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -41,7 +41,7 @@ #include <emscripten/html5.h> -typedef String (*GetDataDirFunc)(); +typedef String (*GetUserDataDirFunc)(); class OS_JavaScript : public OS_Unix { @@ -62,7 +62,7 @@ class OS_JavaScript : public OS_Unix { CursorShape cursor_shape; MainLoop *main_loop; - GetDataDirFunc get_data_dir_func; + GetUserDataDirFunc get_user_data_dir_func; PowerJavascript *power_manager; @@ -141,7 +141,7 @@ public: void set_opengl_extensions(const char *p_gl_extensions); virtual Error shell_open(String p_uri); - virtual String get_data_dir() const; + virtual String get_user_data_dir() const; String get_executable_path() const; virtual String get_resource_dir() const; @@ -160,7 +160,7 @@ public: void set_idbfs_available(bool p_idbfs_available); - OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func); + OS_JavaScript(const char *p_execpath, GetUserDataDirFunc p_get_user_data_dir_func); ~OS_JavaScript(); }; diff --git a/platform/osx/detect.py b/platform/osx/detect.py index c24bd98bf6..ff7cf2ad2f 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -110,7 +110,7 @@ def configure(env): ## Flags env.Append(CPPPATH=['#platform/osx']) - env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED']) + env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED']) env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) env.Append(LIBS=['pthread']) diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 8a6f1dc04c..f6922377e3 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -160,7 +160,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ copy->convert(Image::FORMAT_RGBA8); copy->resize(size, size); it->create_from_image(copy); - String path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/icon.png"; + String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png"); ResourceSaver::save(path, it); FileAccess *f = FileAccess::open(path, FileAccess::READ); @@ -344,7 +344,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (use_dmg()) { // We're on OSX so we can export to DMG, but first we create our application bundle - tmp_app_path_name = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".app"; + tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app"); print_line("Exporting to " + tmp_app_path_name); DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); if (!tmp_app_path) { @@ -539,7 +539,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p OS::get_singleton()->move_to_trash(tmp_app_path_name); } else { - String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".pck"; + String pack_path = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".pck"); Error err = save_pack(p_preset, pack_path); if (err == OK) { diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 1df847eb79..aa8ee1fe83 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -154,6 +154,11 @@ public: virtual MainLoop *get_main_loop() const; + virtual String get_config_path() const; + virtual String get_data_path() const; + virtual String get_cache_path() const; + virtual String get_godot_dir_name() const; + virtual String get_system_dir(SystemDir p_dir) const; virtual bool can_draw() const; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 2e0e2620be..110cb776ee 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -36,6 +36,7 @@ #include "print_string.h" #include "sem_osx.h" #include "servers/visual/visual_server_raster.h" +#include "version_generated.gen.h" #include <Carbon/Carbon.h> #import <Cocoa/Cocoa.h> @@ -896,7 +897,7 @@ int OS_OSX::get_video_driver_count() const { const char *OS_OSX::get_video_driver_name(int p_driver) const { - return "GLES2"; + return "GLES3"; } void OS_OSX::initialize_core() { @@ -1066,8 +1067,6 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au zoomed = true; /*** END OSX INITIALIZATION ***/ - /*** END OSX INITIALIZATION ***/ - /*** END OSX INITIALIZATION ***/ bool use_gl2 = p_video_driver != 1; @@ -1077,16 +1076,12 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); - //rasterizer = instance_RasterizerGLES2(); - //visual_server = memnew( VisualServerRaster(rasterizer) ); - visual_server = memnew(VisualServerRaster); if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); } visual_server->init(); - // visual_server->cursor_set_visible(false, 0); AudioDriverManager::initialize(p_audio_driver); @@ -1095,7 +1090,7 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au power_manager = memnew(power_osx); - _ensure_data_dir(); + _ensure_user_data_dir(); restore_rect = Rect2(get_window_position(), get_window_size()); } @@ -1340,6 +1335,43 @@ MainLoop *OS_OSX::get_main_loop() const { return main_loop; } +String OS_OSX::get_config_path() const { + + if (has_environment("XDG_CONFIG_HOME")) { + return get_environment("XDG_CONFIG_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file("Library/Application Support"); + } else { + return "."; + } +} + +String OS_OSX::get_data_path() const { + + if (has_environment("XDG_DATA_HOME")) { + return get_environment("XDG_DATA_HOME"); + } else { + return get_config_path(); + } +} + +String OS_OSX::get_cache_path() const { + + if (has_environment("XDG_CACHE_HOME")) { + return get_environment("XDG_CACHE_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file("Library/Caches"); + } else { + return get_config_path(); + } +} + +// Get properly capitalized engine name for system paths +String OS_OSX::get_godot_dir_name() const { + + return String(VERSION_SHORT_NAME).capitalize(); +} + String OS_OSX::get_system_dir(SystemDir p_dir) const { NSSearchPathDirectory id = 0; diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index ca73f610e4..5b852af738 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -73,7 +73,7 @@ void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p input = memnew(InputDefault); - _ensure_data_dir(); + _ensure_user_data_dir(); } void OS_Server::finalize() { diff --git a/platform/uwp/app.h b/platform/uwp/app.h index e079fa9c9d..b812512a98 100644 --- a/platform/uwp/app.h +++ b/platform/uwp/app.h @@ -33,6 +33,7 @@ #include <wrl.h> +// ANGLE doesn't provide a specific lib for GLES3, so we keep using GLES2 #include "GLES2/gl2.h" #include "os_uwp.h" diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index 434c597449..7cc8afff06 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -136,7 +136,7 @@ def configure(env): env.Append(CPPPATH=['#platform/uwp', '#drivers/windows']) env.Append(CCFLAGS=['/DUWP_ENABLED', '/DWINDOWS_ENABLED', '/DTYPED_METHOD_BIND']) - env.Append(CCFLAGS=['/DGLES2_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED']) + env.Append(CCFLAGS=['/DGLES_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED']) winver = "0x0602" # Windows 8 is the minimum target for UWP build env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index d66bcaa91c..120df9bc3f 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -456,8 +456,8 @@ void AppxPackager::init(FileAccess *p_fa) { package = p_fa; central_dir_offset = 0; end_of_central_dir_offset = 0; - tmp_blockmap_file_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpblockmap.xml"; - tmp_content_types_file_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmpcontenttypes.xml"; + tmp_blockmap_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml"); + tmp_content_types_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml"); } void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress) { @@ -886,7 +886,7 @@ class EditorExportUWP : public EditorExportPlatform { if (!image) return data; - String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/uwp_tmp_logo.png"); + String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png"); Error err = image->get_data()->save_png(tmp_path); diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index acb0ba4bca..64e319327f 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "os_uwp.h" + #include "drivers/gles3/rasterizer_gles3.h" #include "drivers/unix/ip_unix.h" #include "drivers/windows/dir_access_windows.h" @@ -69,7 +70,7 @@ int OSUWP::get_video_driver_count() const { } const char *OSUWP::get_video_driver_name(int p_driver) const { - return "GLES2"; + return "GLES3"; } Size2 OSUWP::get_window_size() const { @@ -298,7 +299,7 @@ void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_aud ref new TypedEventHandler<Gyrometer ^, GyrometerReadingChangedEventArgs ^>(managed_object, &ManagedType::on_gyroscope_reading_changed); } - _ensure_data_dir(); + _ensure_user_data_dir(); if (is_keep_screen_on()) display_request->RequestActive(); @@ -781,7 +782,7 @@ MainLoop *OSUWP::get_main_loop() const { return main_loop; } -String OSUWP::get_data_dir() const { +String OSUWP::get_user_data_dir() const { Windows::Storage::StorageFolder ^ data_folder = Windows::Storage::ApplicationData::Current->LocalFolder; diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 2931e9b07d..3c52fc29a8 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -226,7 +226,7 @@ public: virtual String get_locale() const; virtual void move_window_to_foreground(); - virtual String get_data_dir() const; + virtual String get_user_data_dir() const; virtual bool _check_internal_feature_support(const String &p_feature); diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp index 8571f0dc65..81aa18dd23 100644 --- a/platform/windows/context_gl_win.cpp +++ b/platform/windows/context_gl_win.cpp @@ -27,25 +27,12 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED) - -// -// C++ Implementation: context_gl_x11 -// -// Description: -// -// +#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) + // Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008 -// -// Copyright: See COPYING file that comes with this distribution -// -// #include "context_gl_win.h" -//#include "drivers/opengl/glwrapper.h" -//#include "ctxgl_procaddr.h" - #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_FLAGS_ARB 0x2094 diff --git a/platform/windows/context_gl_win.h b/platform/windows/context_gl_win.h index 0059cbc311..5a280b0d08 100644 --- a/platform/windows/context_gl_win.h +++ b/platform/windows/context_gl_win.h @@ -27,18 +27,9 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED) -// -// C++ Interface: context_gl_x11 -// -// Description: -// -// +#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) + // Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008 -// -// Copyright: See COPYING file that comes with this distribution -// -// #ifndef CONTEXT_GL_WIN_H #define CONTEXT_GL_WIN_H diff --git a/platform/windows/godot_res.rc b/platform/windows/godot_res.rc index b86869d316..c535a749c0 100644 --- a/platform/windows/godot_res.rc +++ b/platform/windows/godot_res.rc @@ -23,13 +23,13 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Godot Engine" - VALUE "FileDescription", _MKSTR(VERSION_NAME) " Editor" + VALUE "FileDescription", VERSION_NAME " Editor" VALUE "FileVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." _MKSTR(VERSION_PATCH) - VALUE "ProductName", _MKSTR(VERSION_NAME) + VALUE "ProductName", VERSION_NAME VALUE "Licence", "MIT" VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur" - VALUE "Info", "http://www.godotengine.org" - VALUE "ProductVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) PATCH_STRING "." _MKSTR(VERSION_REVISION) + VALUE "Info", "https://godotengine.org" + VALUE "ProductVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) PATCH_STRING "." VERSION_BUILD END END BLOCK "VarFileInfo" diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 0f62dbb9e8..72d51ad62a 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -47,6 +47,7 @@ #include "servers/visual/visual_server_wrap_mt.h" #include "stream_peer_winsock.h" #include "tcp_server_winsock.h" +#include "version_generated.gen.h" #include "windows_terminal_logger.h" #include <process.h> @@ -143,7 +144,7 @@ int OS_Windows::get_video_driver_count() const { } const char *OS_Windows::get_video_driver_name(int p_driver) const { - return "GLES2"; + return "GLES3"; } int OS_Windows::get_audio_driver_count() const { @@ -1090,7 +1091,7 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int //RegisterTouchWindow(hWnd, 0); // Windows 7 - _ensure_data_dir(); + _ensure_user_data_dir(); DragAcceptFiles(hWnd, true); @@ -2131,6 +2132,43 @@ MainLoop *OS_Windows::get_main_loop() const { return main_loop; } +String OS_Windows::get_config_path() const { + + if (has_environment("XDG_CONFIG_HOME")) { // unlikely, but after all why not? + return get_environment("XDG_CONFIG_HOME"); + } else if (has_environment("APPDATA")) { + return get_environment("APPDATA"); + } else { + return "."; + } +} + +String OS_Windows::get_data_path() const { + + if (has_environment("XDG_DATA_HOME")) { + return get_environment("XDG_DATA_HOME"); + } else { + return get_config_path(); + } +} + +String OS_Windows::get_cache_path() const { + + if (has_environment("XDG_CACHE_HOME")) { + return get_environment("XDG_CACHE_HOME"); + } else if (has_environment("TEMP")) { + return get_environment("TEMP"); + } else { + return get_config_path(); + } +} + +// Get properly capitalized engine name for system paths +String OS_Windows::get_godot_dir_name() const { + + return String(VERSION_SHORT_NAME).capitalize(); +} + String OS_Windows::get_system_dir(SystemDir p_dir) const { int id; @@ -2167,18 +2205,17 @@ String OS_Windows::get_system_dir(SystemDir p_dir) const { ERR_FAIL_COND_V(res != S_OK, String()); return String(szPath); } -String OS_Windows::get_data_dir() const { - String an = get_safe_application_name(); - if (an != "") { +String OS_Windows::get_user_data_dir() const { - if (has_environment("APPDATA")) { + String appname = get_safe_application_name(); + if (appname != "") { - bool use_godot = ProjectSettings::get_singleton()->get("application/config/use_shared_user_dir"); - if (!use_godot) - return (OS::get_singleton()->get_environment("APPDATA") + "/" + an).replace("\\", "/"); - else - return (OS::get_singleton()->get_environment("APPDATA") + "/Godot/app_userdata/" + an).replace("\\", "/"); + bool use_godot_dir = ProjectSettings::get_singleton()->get("application/config/use_shared_user_dir"); + if (use_godot_dir) { + return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname).replace("\\", "/"); + } else { + return get_data_path().plus_file(appname).replace("\\", "/"); } } diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index fbd60e5f0d..5e0c240dba 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -253,8 +253,14 @@ public: virtual void enable_for_stealing_focus(ProcessID pid); virtual void move_window_to_foreground(); - virtual String get_data_dir() const; + + virtual String get_config_path() const; + virtual String get_data_path() const; + virtual String get_cache_path() const; + virtual String get_godot_dir_name() const; + virtual String get_system_dir(SystemDir p_dir) const; + virtual String get_user_data_dir() const; virtual void release_rendering_thread(); virtual void make_rendering_thread(); diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 6bd0ac8317..3d07851c4f 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -236,7 +236,7 @@ def configure(env): env.ParseConfig('pkg-config zlib --cflags --libs') env.Append(CPPPATH=['#platform/x11']) - env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) + env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES_ENABLED', '-DGLES_OVER_GL']) env.Append(LIBS=['GL', 'pthread']) if (platform.system() == "Linux"): diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index f018145d82..c1d744215d 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -464,7 +464,7 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au #ifdef JOYDEV_ENABLED joypad = memnew(JoypadLinux(input)); #endif - _ensure_data_dir(); + _ensure_user_data_dir(); power_manager = memnew(PowerX11); } @@ -1941,6 +1941,39 @@ bool OS_X11::_check_internal_feature_support(const String &p_feature) { return p_feature == "pc" || p_feature == "s3tc"; } +String OS_X11::get_config_path() const { + + if (has_environment("XDG_CONFIG_HOME")) { + return get_environment("XDG_CONFIG_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".config"); + } else { + return "."; + } +} + +String OS_X11::get_data_path() const { + + if (has_environment("XDG_DATA_HOME")) { + return get_environment("XDG_DATA_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".local/share"); + } else { + return get_config_path(); + } +} + +String OS_X11::get_cache_path() const { + + if (has_environment("XDG_CACHE_HOME")) { + return get_environment("XDG_CACHE_HOME"); + } else if (has_environment("HOME")) { + return get_environment("HOME").plus_file(".cache"); + } else { + return get_config_path(); + } +} + String OS_X11::get_system_dir(SystemDir p_dir) const { String xdgparam; diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 0ea5bbfdb6..67f3807d99 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -213,6 +213,10 @@ public: virtual void make_rendering_thread(); virtual void swap_buffers(); + virtual String get_config_path() const; + virtual String get_data_path() const; + virtual String get_cache_path() const; + virtual String get_system_dir(SystemDir p_dir) const; virtual Error shell_open(String p_uri); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 1287a800e3..1f6127e6eb 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1028,7 +1028,10 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const on_floor = true; floor_velocity = collision.collider_vel; - if (collision.travel.length() < 1 && ABS((lv.x - floor_velocity.x)) < p_slope_stop_min_velocity) { + Vector2 rel_v = lv - floor_velocity; + Vector2 hv = rel_v - p_floor_direction * p_floor_direction.dot(rel_v); + + if (collision.travel.length() < 1 && hv.length() < p_slope_stop_min_velocity) { Transform2D gt = get_global_transform(); gt.elements[2] -= collision.travel; set_global_transform(gt); diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 324411c5cc..126c07f0be 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -222,6 +222,7 @@ void Light::_bind_methods() { ADD_GROUP("Light", "light_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_ENERGY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); @@ -236,6 +237,7 @@ void Light::_bind_methods() { ADD_GROUP("", ""); BIND_ENUM_CONSTANT(PARAM_ENERGY); + BIND_ENUM_CONSTANT(PARAM_INDIRECT_ENERGY); BIND_ENUM_CONSTANT(PARAM_SPECULAR); BIND_ENUM_CONSTANT(PARAM_RANGE); BIND_ENUM_CONSTANT(PARAM_ATTENUATION); @@ -273,6 +275,7 @@ Light::Light(VisualServer::LightType p_type) { set_cull_mask(0xFFFFFFFF); set_param(PARAM_ENERGY, 1); + set_param(PARAM_INDIRECT_ENERGY, 1); set_param(PARAM_SPECULAR, 0.5); set_param(PARAM_RANGE, 5); set_param(PARAM_ATTENUATION, 1); diff --git a/scene/3d/light.h b/scene/3d/light.h index 37c17cbbe3..8514b429ec 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -46,6 +46,7 @@ class Light : public VisualInstance { public: enum Param { PARAM_ENERGY = VS::LIGHT_PARAM_ENERGY, + PARAM_INDIRECT_ENERGY = VS::LIGHT_PARAM_INDIRECT_ENERGY, PARAM_SPECULAR = VS::LIGHT_PARAM_SPECULAR, PARAM_RANGE = VS::LIGHT_PARAM_RANGE, PARAM_ATTENUATION = VS::LIGHT_PARAM_ATTENUATION, diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1b87771fd4..c9af7eed0d 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -274,6 +274,7 @@ void TextEdit::Text::insert(int p_at, const String &p_text) { Line line; line.marked = false; line.breakpoint = false; + line.hidden = false; line.width_cache = -1; line.data = p_text; text.insert(p_at, line); @@ -297,9 +298,11 @@ void TextEdit::_update_scrollbars() { int hscroll_rows = ((hmin.height - 1) / get_row_height()) + 1; int visible_rows = get_visible_rows(); - int total_rows = text.size(); + int num_rows = MAX(visible_rows, num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(visible_rows, text.size() - 1 - cursor.line_ofs))); + + int total_rows = (is_hiding_enabled() ? get_total_unhidden_rows() : text.size()); if (scroll_past_end_of_file_enabled) { - total_rows += get_visible_rows() - 1; + total_rows += visible_rows - 1; } int vscroll_pixels = v_scroll->get_combined_minimum_size().width; @@ -313,6 +316,10 @@ void TextEdit::_update_scrollbars() { total_width += cache.breakpoint_gutter_width; } + if (draw_fold_gutter) { + total_width += cache.fold_gutter_width; + } + bool use_hscroll = true; bool use_vscroll = true; @@ -347,12 +354,11 @@ void TextEdit::_update_scrollbars() { v_scroll->set_step(1); } - if (fabs(v_scroll->get_value() - (double)cursor.line_ofs) >= 1) { - v_scroll->set_value(cursor.line_ofs); - } - + update_line_scroll_pos(); } else { cursor.line_ofs = 0; + line_scroll_pos = 0; + v_scroll->set_value(0); v_scroll->hide(); } @@ -551,6 +557,13 @@ void TextEdit::_notification(int p_what) { cache.breakpoint_gutter_width = 0; } + if (draw_fold_gutter) { + fold_gutter_width = (get_row_height() * 55) / 100; + cache.fold_gutter_width = fold_gutter_width; + } else { + cache.fold_gutter_width = 0; + } + int line_number_char_count = 0; { @@ -573,7 +586,7 @@ void TextEdit::_notification(int p_what) { RID ci = get_canvas_item(); VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true); - int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width; + int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width; int xmargin_end = cache.size.width - cache.style_normal->get_margin(MARGIN_RIGHT); //let's do it easy for now: cache.style_normal->draw(ci, Rect2(Point2(), cache.size)); @@ -780,10 +793,22 @@ void TextEdit::_notification(int p_what) { String highlighted_text = get_selection_text(); String line_num_padding = line_numbers_zero_padded ? "0" : " "; + update_line_scroll_pos(); + int line = cursor.line_ofs - 1; for (int i = 0; i < visible_rows; i++) { - int line = i + cursor.line_ofs; + line++; + + if (line < 0 || line >= (int)text.size()) + continue; + + while (is_line_hidden(line)) { + line++; + if (line < 0 || line >= (int)text.size()) { + break; + } + } if (line < 0 || line >= (int)text.size()) continue; @@ -794,7 +819,7 @@ void TextEdit::_notification(int p_what) { int char_ofs = 0; int ofs_y = (i * get_row_height() + cache.line_spacing / 2); if (smooth_scroll_enabled) { - ofs_y -= (v_scroll->get_value() - cursor.line_ofs) * get_row_height(); + ofs_y -= (v_scroll->get_value() - get_line_scroll_pos()) * get_row_height(); } bool prev_is_char = false; @@ -857,6 +882,21 @@ void TextEdit::_notification(int p_what) { } } + // draw fold markers + if (draw_fold_gutter) { + int horizontal_gap = (cache.fold_gutter_width * 30) / 100; + int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w; + if (is_folded(line)) { + int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2; + int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2; + cache.folded_icon->draw(ci, Point2(gutter_left + xofs, ofs_y + yofs), Color(0.8f, 0.8f, 0.8f, 0.8f)); + } else if (can_fold(line)) { + int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3; + int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2; + cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs, ofs_y + yofs), Color(0.8f, 0.8f, 0.8f, 0.8f)); + } + } + if (cache.line_number_w) { String fc = String::num(line + 1); while (fc.length() < line_number_char_count) { @@ -1196,6 +1236,10 @@ void TextEdit::_notification(int p_what) { } char_ofs += char_w; + + if (j == str.length() - 1 && is_folded(line)) { + cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin, ofs_y), Color(1, 1, 1, 1), true); + } } if (cursor.column == str.length() && cursor.line == line && (char_ofs + char_margin) >= xmargin_beg) { @@ -1538,6 +1582,12 @@ void TextEdit::backspace_at_cursor() { int prev_line = cursor.column ? cursor.line : cursor.line - 1; int prev_column = cursor.column ? (cursor.column - 1) : (text[cursor.line - 1].length()); + + if (is_line_hidden(cursor.line)) + set_line_as_hidden(prev_line, true); + if (is_line_set_as_breakpoint(cursor.line)) + set_line_as_breakpoint(prev_line, true); + if (auto_brace_completion_enabled && cursor.column > 0 && _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { @@ -1577,7 +1627,7 @@ void TextEdit::backspace_at_cursor() { } } - cursor_set_line(prev_line); + cursor_set_line(prev_line, true, true); cursor_set_column(prev_column); } @@ -1651,10 +1701,18 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co float rows = p_mouse.y; rows -= cache.style_normal->get_margin(MARGIN_TOP); rows /= get_row_height(); - int row = cursor.line_ofs + (rows + (v_scroll->get_value() - cursor.line_ofs)); + int lsp = get_line_scroll_pos(true); + int row = cursor.line_ofs + (rows + (v_scroll->get_value() - lsp)); + + if (is_hiding_enabled()) { + // row will be offset by the hidden rows + int f_ofs = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(rows + 1, text.size() - cursor.line_ofs)) - 1; + row = cursor.line_ofs + (f_ofs + (v_scroll->get_value() - lsp)); + row = CLAMP(row, 0, text.size() - num_lines_from(text.size() - 1, -1)); + } if (row < 0) - row = 0; + row = 0; //todo int col = 0; @@ -1664,7 +1722,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co col = text[row].size(); } else { - col = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width); + col = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width); col += cursor.x_ofs; col = get_char_pos_for(col, get_line(row)); } @@ -1717,10 +1775,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->is_pressed()) { if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) { + float scroll_factor = 3 * mb->get_factor(); if (scrolling) { - target_v_scroll = (target_v_scroll - (3 * mb->get_factor())); + target_v_scroll = (target_v_scroll - scroll_factor); } else { - target_v_scroll = (v_scroll->get_value() - (3 * mb->get_factor())); + target_v_scroll = (v_scroll->get_value() - scroll_factor); } if (smooth_scroll_enabled) { @@ -1734,16 +1793,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) { + float scroll_factor = 3 * mb->get_factor(); if (scrolling) { - target_v_scroll = (target_v_scroll + (3 * mb->get_factor())); + target_v_scroll = (target_v_scroll + scroll_factor); } else { - target_v_scroll = (v_scroll->get_value() + (3 * mb->get_factor())); + target_v_scroll = (v_scroll->get_value() + scroll_factor); } if (smooth_scroll_enabled) { - int max_v_scroll = get_line_count() - 1; + int max_v_scroll = get_total_unhidden_rows(); if (!scroll_past_end_of_file_enabled) { - max_v_scroll -= get_visible_rows() - 1; + max_v_scroll -= get_visible_rows(); + max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows()); } if (target_v_scroll > max_v_scroll) { @@ -1766,6 +1827,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _reset_caret_blink_timer(); int row, col; + update_line_scroll_pos(); _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); if (mb->get_command() && highlighted_word != String()) { @@ -1784,10 +1846,35 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + // toggle fold on gutter click if can + if (draw_fold_gutter) { + + int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); + int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w; + if (mb->get_position().x > gutter_left - 6 && mb->get_position().x <= gutter_left + cache.fold_gutter_width - 3) { + if (is_folded(row)) { + unfold_line(row); + } else if (can_fold(row)) { + fold_line(row); + } + return; + } + } + + // unfold on folded icon click + if (is_folded(row)) { + int line_width = text.get_line_width(row); + line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width - cursor.x_ofs; + if (mb->get_position().x > line_width - 3 && mb->get_position().x <= line_width + cache.folded_eol_icon->get_width() + 3) { + unfold_line(row); + return; + } + } + int prev_col = cursor.column; int prev_line = cursor.line; - cursor_set_line(row); + cursor_set_line(row, true, false); cursor_set_column(col); if (mb->get_shift() && (cursor.column != prev_col || cursor.line != prev_line)) { @@ -2026,22 +2113,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { return; } - if (k->get_scancode() == KEY_DOWN) { - - if (completion_index < completion_options.size() - 1) { - completion_index++; - completion_current = completion_options[completion_index]; - update(); - } - accept_event(); - return; - } - if (k->get_scancode() == KEY_KP_ENTER || k->get_scancode() == KEY_ENTER || k->get_scancode() == KEY_TAB) { _confirm_completion(); accept_event(); - emit_signal("request_completion"); return; } @@ -2191,7 +2266,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { selection.active = false; update(); _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); - cursor_set_line(selection.from_line); + cursor_set_line(selection.from_line, true, false); cursor_set_column(selection.from_column); update(); } @@ -2241,6 +2316,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (is_folded(cursor.line)) + unfold_line(cursor.line); + bool brace_indent = false; // no need to indent if we are going upwards. @@ -2391,6 +2469,8 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { cursor_set_column(column); } else { + if (cursor.line > 0 && is_line_hidden(cursor.line - 1)) + unfold_line(cursor.line - 1); backspace_at_cursor(); } @@ -2449,7 +2529,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else if (cursor.column == 0) { if (cursor.line > 0) { - cursor_set_line(cursor.line - 1); + cursor_set_line(cursor.line - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1)); cursor_set_column(text[cursor.line].length()); } } else { @@ -2512,7 +2592,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else if (cursor.column == text[cursor.line].length()) { if (cursor.line < text.size() - 1) { - cursor_set_line(cursor.line + 1); + cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false); cursor_set_column(0); } } else { @@ -2553,7 +2633,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { cursor_set_line(0); else #endif - cursor_set_line(cursor_get_line() - 1); + cursor_set_line(cursor_get_line() - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1)); if (k->get_shift()) _post_shift_selection(); @@ -2587,10 +2667,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } if (k->get_command()) - cursor_set_line(text.size() - 1); + cursor_set_line(text.size() - 1, true, false); else #endif - cursor_set_line(cursor_get_line() + 1); + cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false); if (k->get_shift()) _post_shift_selection(); @@ -2737,7 +2817,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (k->get_shift()) _pre_shift_selection(); - cursor_set_line(text.size() - 1); + cursor_set_line(text.size() - 1, true, false); if (k->get_shift()) _post_shift_selection(); @@ -2752,7 +2832,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _pre_shift_selection(); if (k->get_command()) - cursor_set_line(text.size() - 1); + cursor_set_line(text.size() - 1, true, false); cursor_set_column(text[cursor.line].length()); if (k->get_shift()) @@ -2777,7 +2857,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (k->get_shift()) _pre_shift_selection(); - cursor_set_line(cursor_get_line() - get_visible_rows()); + cursor_set_line(cursor_get_line() - num_lines_from(cursor.line, -get_visible_rows()), true, false); if (k->get_shift()) _post_shift_selection(); @@ -2798,7 +2878,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (k->get_shift()) _pre_shift_selection(); - cursor_set_line(cursor_get_line() + get_visible_rows()); + cursor_set_line(cursor_get_line() + num_lines_from(cursor.line, get_visible_rows()), true, false); if (k->get_shift()) _post_shift_selection(); @@ -3016,8 +3096,9 @@ void TextEdit::_scroll_lines_up() { } // adjust the cursor - if (cursor_get_line() >= (get_visible_rows() + get_v_scroll()) && !selection.active) { - cursor_set_line((get_visible_rows() + get_v_scroll()) - 1, false); + int num_lines = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), get_visible_rows()) - 1; + if (cursor.line >= cursor.line_ofs + num_lines && !selection.active) { + cursor_set_line(cursor.line_ofs + num_lines, false, false); } } @@ -3025,9 +3106,10 @@ void TextEdit::_scroll_lines_down() { scrolling = false; // calculate the maximum vertical scroll position - int max_v_scroll = get_line_count() - 1; + int max_v_scroll = get_total_unhidden_rows(); if (!scroll_past_end_of_file_enabled) { - max_v_scroll -= get_visible_rows() - 1; + max_v_scroll -= get_visible_rows(); + max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows()); } // adjust the vertical scroll @@ -3036,8 +3118,8 @@ void TextEdit::_scroll_lines_down() { } // adjust the cursor - if ((cursor_get_line()) <= get_v_scroll() - 1 && !selection.active) { - cursor_set_line(get_v_scroll(), false); + if (cursor.line <= cursor.line_ofs - 1 && !selection.active) { + cursor_set_line(cursor.line_ofs, false, false); } } @@ -3082,6 +3164,15 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i } } + // if we are just making a new empty line, reset breakpoints and hidden status + if (p_char == 0 && p_text.replace("\r", "") == "\n") { + + text.set_breakpoint(p_line + 1, text.is_breakpoint(p_line)); + text.set_hidden(p_line + 1, text.is_hidden(p_line)); + text.set_breakpoint(p_line, false); + text.set_hidden(p_line, false); + } + r_end_line = p_line + substrings.size() - 1; r_end_column = text[r_end_line].length() - postinsert_text.length(); @@ -3280,6 +3371,7 @@ Size2 TextEdit::get_minimum_size() const { return cache.style_normal->get_minimum_size(); } + int TextEdit::get_visible_rows() const { int total = cache.size.height; @@ -3287,31 +3379,81 @@ int TextEdit::get_visible_rows() const { total /= get_row_height(); return total; } + +int TextEdit::get_total_unhidden_rows() const { + if (!is_hiding_enabled()) + return text.size(); + + int total_unhidden = 0; + for (int i = 0; i < text.size(); i++) { + if (!text.is_hidden(i)) + total_unhidden++; + } + return total_unhidden; +} + +double TextEdit::get_line_scroll_pos(bool p_recalculate) const { + + if (!is_hiding_enabled()) + return cursor.line_ofs; + if (!p_recalculate) + return line_scroll_pos; + + // count num unhidden lines to the cursor line ofs + double new_line_scroll_pos = 0; + int to = CLAMP(cursor.line_ofs, 0, text.size() - 1); + for (int i = 0; i < to; i++) { + if (!text.is_hidden(i)) + new_line_scroll_pos++; + } + return new_line_scroll_pos; +} + +void TextEdit::update_line_scroll_pos() { + + if (!is_hiding_enabled()) { + line_scroll_pos = cursor.line_ofs; + return; + } + + // count num unhidden lines to the cursor line ofs + double new_line_scroll_pos = 0; + int to = CLAMP(cursor.line_ofs, 0, text.size() - 1); + for (int i = 0; i < to; i++) { + if (!text.is_hidden(i)) + new_line_scroll_pos++; + } + line_scroll_pos = new_line_scroll_pos; +} + void TextEdit::adjust_viewport_to_cursor() { scrolling = false; - if (cursor.line_ofs > cursor.line) + if (cursor.line_ofs > cursor.line) { cursor.line_ofs = cursor.line; + } - int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width; + int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; if (v_scroll->is_visible_in_tree()) visible_width -= v_scroll->get_combined_minimum_size().width; visible_width -= 20; // give it a little more space - //printf("rowofs %i, visrows %i, cursor.line %i\n",cursor.line_ofs,get_visible_rows(),cursor.line); - int visible_rows = get_visible_rows(); if (h_scroll->is_visible_in_tree()) visible_rows -= ((h_scroll->get_combined_minimum_size().height - 1) / get_row_height()); + int num_rows = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(visible_rows, text.size() - 1 - cursor.line_ofs)); - if (cursor.line >= (cursor.line_ofs + visible_rows)) - cursor.line_ofs = cursor.line - visible_rows; - if (cursor.line < cursor.line_ofs) + // if the cursor is off the screen + if (cursor.line >= (cursor.line_ofs + MAX(num_rows, visible_rows))) { + cursor.line_ofs = cursor.line - (num_lines_from(CLAMP(cursor.line, 0, text.size() - 1), -visible_rows) - 1); + } + if (cursor.line < cursor.line_ofs) { cursor.line_ofs = cursor.line; + } - if (cursor.line_ofs + visible_rows > text.size() && !scroll_past_end_of_file_enabled) { - cursor.line_ofs = text.size() - visible_rows; - v_scroll->set_value(text.size() - visible_rows); + // fixes deleting lines from moving the line ofs in a bad way + if (!scroll_past_end_of_file_enabled && get_total_unhidden_rows() > visible_rows && num_rows < visible_rows) { + cursor.line_ofs = text.size() - 1 - (num_lines_from(text.size() - 1, -visible_rows) - 1); } int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]); @@ -3322,6 +3464,8 @@ void TextEdit::adjust_viewport_to_cursor() { if (cursor_x < cursor.x_ofs) cursor.x_ofs = cursor_x; + update_line_scroll_pos(); + v_scroll->set_value(get_line_scroll_pos() + 1); update(); /* get_range()->set_max(text.size()); @@ -3338,7 +3482,10 @@ void TextEdit::center_viewport_to_cursor() { if (cursor.line_ofs > cursor.line) cursor.line_ofs = cursor.line; - int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width; + if (is_line_hidden(cursor.line)) + unfold_line(cursor.line); + + int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; if (v_scroll->is_visible_in_tree()) visible_width -= v_scroll->get_combined_minimum_size().width; visible_width -= 20; // give it a little more space @@ -3347,9 +3494,8 @@ void TextEdit::center_viewport_to_cursor() { if (h_scroll->is_visible_in_tree()) visible_rows -= ((h_scroll->get_combined_minimum_size().height - 1) / get_row_height()); - int max_ofs = text.size() - (scroll_past_end_of_file_enabled ? 1 : visible_rows); - cursor.line_ofs = CLAMP(cursor.line - (visible_rows / 2), 0, max_ofs); - + int max_ofs = text.size() - (scroll_past_end_of_file_enabled ? 1 : num_lines_from(text.size() - 1, -visible_rows)); + cursor.line_ofs = CLAMP(cursor.line - num_lines_from(cursor.line - visible_rows / 2, -visible_rows / 2), 0, max_ofs); int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]); if (cursor_x > (cursor.x_ofs + visible_width)) @@ -3358,6 +3504,9 @@ void TextEdit::center_viewport_to_cursor() { if (cursor_x < cursor.x_ofs) cursor.x_ofs = cursor_x; + update_line_scroll_pos(); + v_scroll->set_value(get_line_scroll_pos()); + update(); } @@ -3382,7 +3531,7 @@ void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) { } } -void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport) { +void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_hidden) { if (setting_row) return; @@ -3394,6 +3543,21 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport) { if (p_row >= (int)text.size()) p_row = (int)text.size() - 1; + if (!p_can_be_hidden) { + if (is_line_hidden(CLAMP(p_row, 0, text.size() - 1))) { + int move_down = num_lines_from(p_row, 1) - 1; + if (p_row + move_down <= text.size() - 1 && !is_line_hidden(p_row + move_down)) { + p_row += move_down; + } else { + int move_up = num_lines_from(p_row, -1) - 1; + if (p_row - move_up > 0 && !is_line_hidden(p_row - move_up)) { + p_row -= move_up; + } else { + WARN_PRINTS(("Cursor set to hidden line " + itos(p_row) + " and there are no nonhidden lines.")); + } + } + } + } cursor.line = p_row; cursor.column = get_char_pos_for(cursor.last_fit_x, get_line(cursor.line)); @@ -3463,8 +3627,11 @@ void TextEdit::_scroll_moved(double p_to_val) { if (h_scroll->is_visible_in_tree()) cursor.x_ofs = h_scroll->get_value(); - if (v_scroll->is_visible_in_tree()) - cursor.line_ofs = v_scroll->get_value(); + if (v_scroll->is_visible_in_tree()) { + double val = v_scroll->get_value(); + cursor.line_ofs = num_lines_from(0, (int)floor(val)) - 1; + line_scroll_pos = (int)floor(val); + } update(); } @@ -3553,10 +3720,43 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { if (highlighted_word != String()) return CURSOR_POINTING_HAND; - int gutter = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width; - if ((completion_active && completion_rect.has_point(p_pos)) || p_pos.x < gutter) { + int gutter = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width; + if ((completion_active && completion_rect.has_point(p_pos))) { + return CURSOR_ARROW; + } + if (p_pos.x < gutter) { + + int row, col; + _get_mouse_pos(p_pos, row, col); + int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); + + // breakpoint icon + if (draw_breakpoint_gutter && p_pos.x > left_margin && p_pos.x <= left_margin + cache.breakpoint_gutter_width + 3) { + return CURSOR_POINTING_HAND; + } + + // fold icon + int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w; + if (draw_fold_gutter && p_pos.x > gutter_left - 6 && p_pos.x <= gutter_left + cache.fold_gutter_width - 3) { + if (is_folded(row) || can_fold(row)) + return CURSOR_POINTING_HAND; + else + return CURSOR_ARROW; + } return CURSOR_ARROW; + } else { + int row, col; + _get_mouse_pos(p_pos, row, col); + // eol fold icon + if (is_folded(row)) { + int line_width = text.get_line_width(row); + line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width - cursor.x_ofs; + if (p_pos.x > line_width - 3 && p_pos.x <= line_width + cache.folded_eol_icon->get_width() + 3) { + return CURSOR_POINTING_HAND; + } + } } + return CURSOR_IBEAM; } @@ -3570,6 +3770,7 @@ void TextEdit::set_text(String p_text) { cursor.line = 0; cursor.x_ofs = 0; cursor.line_ofs = 0; + line_scroll_pos = 0; cursor.last_fit_x = 0; cursor_set_line(0); cursor_set_column(0); @@ -3655,6 +3856,7 @@ void TextEdit::_clear() { cursor.line = 0; cursor.x_ofs = 0; cursor.line_ofs = 0; + line_scroll_pos = 0; cursor.last_fit_x = 0; } @@ -3733,6 +3935,9 @@ void TextEdit::_update_caches() { cache.line_spacing = get_constant("line_spacing"); cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon = get_icon("tab"); + cache.folded_icon = get_icon("GuiTreeArrowRight", "EditorIcons"); + cache.can_fold_icon = get_icon("GuiTreeArrowDown", "EditorIcons"); + cache.folded_eol_icon = get_icon("GuiTabMenu", "EditorIcons"); text.set_font(cache.font); } @@ -4179,6 +4384,198 @@ void TextEdit::get_breakpoints(List<int> *p_breakpoints) const { } } +void TextEdit::set_line_as_hidden(int p_line, bool p_hidden) { + + ERR_FAIL_INDEX(p_line, text.size()); + if (is_hiding_enabled() || !p_hidden) + text.set_hidden(p_line, p_hidden); + update(); +} + +bool TextEdit::is_line_hidden(int p_line) const { + + ERR_FAIL_INDEX_V(p_line, text.size(), false); + return text.is_hidden(p_line); +} + +void TextEdit::fold_all_lines() { + + for (int i = 0; i < text.size(); i++) { + fold_line(i); + } + _update_scrollbars(); + update(); +} + +void TextEdit::unhide_all_lines() { + + for (int i = 0; i < text.size(); i++) { + text.set_hidden(i, false); + } + _update_scrollbars(); + update(); +} + +int TextEdit::num_lines_from(int p_line_from, int unhidden_amount) const { + + // returns the number of hidden and unhidden lines from p_line_from to p_line_from + amount of visible lines + ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(unhidden_amount)); + + if (!is_hiding_enabled()) + return unhidden_amount; + int num_visible = 0; + int num_total = 0; + if (unhidden_amount >= 0) { + for (int i = p_line_from; i < text.size(); i++) { + num_total++; + if (!is_line_hidden(i)) + num_visible++; + if (num_visible >= unhidden_amount) + break; + } + } else { + unhidden_amount = ABS(unhidden_amount); + for (int i = p_line_from; i >= 0; i--) { + num_total++; + if (!is_line_hidden(i)) + num_visible++; + if (num_visible >= unhidden_amount) + break; + } + } + return num_total; +} + +int TextEdit::get_whitespace_level(int p_line) const { + + ERR_FAIL_INDEX_V(p_line, text.size(), 0); + + // counts number of tabs and spaces before line starts + int whitespace_count = 0; + int line_length = text[p_line].size(); + for (int i = 0; i < line_length - 1; i++) { + if (text[p_line][i] == '\t') { + whitespace_count++; + } else if (text[p_line][i] == ' ') { + whitespace_count++; + } else if (text[p_line][i] == '#') { + break; + } else { + break; + } + } + return whitespace_count; +} + +bool TextEdit::can_fold(int p_line) const { + + ERR_FAIL_INDEX_V(p_line, text.size(), false); + if (!is_hiding_enabled()) + return false; + if (p_line + 1 >= text.size()) + return false; + if (text[p_line].size() == 0) + return false; + if (is_folded(p_line)) + return false; + if (is_line_hidden(p_line)) + return false; + + int start_indent = get_whitespace_level(p_line); + + for (int i = p_line + 1; i < text.size(); i++) { + if (text[i].size() == 0) + continue; + int next_indent = get_whitespace_level(i); + if (next_indent > start_indent) + return true; + else + return false; + } + + return false; +} + +bool TextEdit::is_folded(int p_line) const { + + ERR_FAIL_INDEX_V(p_line, text.size(), false); + if (p_line + 1 >= text.size() - 1) + return false; + if (!is_line_hidden(p_line) && is_line_hidden(p_line + 1)) + return true; + return false; +} + +void TextEdit::fold_line(int p_line) { + + ERR_FAIL_INDEX(p_line, text.size()); + if (!is_hiding_enabled()) + return; + if (!can_fold(p_line)) + return; + + // hide lines below this one + int start_indent = get_whitespace_level(p_line); + for (int i = p_line + 1; i < text.size(); i++) { + int cur_indent = get_whitespace_level(i); + if (text[i].size() == 0 || cur_indent > start_indent) { + set_line_as_hidden(i, true); + } else { + // exclude trailing empty lines + for (int trail_i = i - 1; trail_i > p_line; trail_i--) { + if (text[trail_i].size() == 0) + set_line_as_hidden(trail_i, false); + else + break; + } + break; + } + } + + // fix selection + if (is_selection_active()) { + if (is_line_hidden(selection.from_line) && is_line_hidden(selection.to_line)) { + deselect(); + } else if (is_line_hidden(selection.from_line)) { + select(p_line, 9999, selection.to_line, selection.to_column); + } else if (is_line_hidden(selection.to_line)) { + select(selection.from_line, selection.from_column, p_line, 9999); + } + } + + // reset cursor + if (is_line_hidden(cursor.line)) { + cursor_set_line(p_line, false, false); + cursor_set_column(get_line(p_line).length(), false); + } + _update_scrollbars(); + update(); +} + +void TextEdit::unfold_line(int p_line) { + + ERR_FAIL_INDEX(p_line, text.size()); + + if (!is_folded(p_line) && !is_line_hidden(p_line)) + return; + int fold_start = p_line; + for (fold_start = p_line; fold_start > 0; fold_start--) { + if (is_folded(fold_start)) + break; + } + fold_start = is_folded(fold_start) ? fold_start : p_line; + + for (int i = fold_start + 1; i < text.size(); i++) { + if (is_line_hidden(i)) { + set_line_as_hidden(i, false); + } else { + break; + } + } + _update_scrollbars(); + update(); +} + int TextEdit::get_line_count() const { return text.size(); @@ -4405,12 +4802,14 @@ void TextEdit::set_v_scroll(int p_scroll) { p_scroll = 0; } if (!scroll_past_end_of_file_enabled) { - if (p_scroll + get_visible_rows() > get_line_count()) { - p_scroll = get_line_count() - get_visible_rows(); + if (p_scroll + get_visible_rows() > get_total_unhidden_rows()) { + int num_rows = num_lines_from(CLAMP(p_scroll, 0, text.size() - 1), MIN(get_visible_rows(), text.size() - 1 - p_scroll)); + p_scroll = text.size() - num_rows; } } v_scroll->set_value(p_scroll); - cursor.line_ofs = p_scroll; + cursor.line_ofs = num_lines_from(0, p_scroll); + line_scroll_pos = p_scroll; } int TextEdit::get_h_scroll() const { @@ -4772,7 +5171,7 @@ void TextEdit::set_line(int line, String new_text) { void TextEdit::insert_at(const String &p_text, int at) { cursor_set_column(0); - cursor_set_line(at); + cursor_set_line(at, false, true); _insert_text(at, 0, p_text + "\n"); } @@ -4820,6 +5219,35 @@ int TextEdit::get_breakpoint_gutter_width() const { return cache.breakpoint_gutter_width; } +void TextEdit::set_draw_fold_gutter(bool p_draw) { + draw_fold_gutter = p_draw; + update(); +} + +bool TextEdit::is_drawing_fold_gutter() const { + return draw_fold_gutter; +} + +void TextEdit::set_fold_gutter_width(int p_gutter_width) { + fold_gutter_width = p_gutter_width; + update(); +} + +int TextEdit::get_fold_gutter_width() const { + return cache.fold_gutter_width; +} + +void TextEdit::set_hiding_enabled(int p_enabled) { + if (!p_enabled) + unhide_all_lines(); + hiding_enabled = p_enabled; + update(); +} + +int TextEdit::is_hiding_enabled() const { + return hiding_enabled; +} + void TextEdit::set_highlight_current_line(bool p_enabled) { highlight_current_line = p_enabled; update(); @@ -4914,7 +5342,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line); ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport"), &TextEdit::cursor_set_line, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true)); ClassDB::bind_method(D_METHOD("cursor_get_column"), &TextEdit::cursor_get_column); ClassDB::bind_method(D_METHOD("cursor_get_line"), &TextEdit::cursor_get_line); @@ -4955,6 +5383,17 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_show_line_numbers", "enable"), &TextEdit::set_show_line_numbers); ClassDB::bind_method(D_METHOD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled); + ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled); + ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); + ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden); + ClassDB::bind_method(D_METHOD("is_line_hidden"), &TextEdit::is_line_hidden); + ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines); + 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("can_fold", "line"), &TextEdit::can_fold); + ClassDB::bind_method(D_METHOD("is_folded", "line"), &TextEdit::is_folded); + ClassDB::bind_method(D_METHOD("set_highlight_all_occurrences", "enable"), &TextEdit::set_highlight_all_occurrences); ClassDB::bind_method(D_METHOD("is_highlight_all_occurrences_enabled"), &TextEdit::is_highlight_all_occurrences_enabled); @@ -4988,6 +5427,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hiding_enabled"), "set_hiding_enabled", "is_hiding_enabled"); ADD_GROUP("Caret", "caret_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode"); @@ -5029,6 +5469,8 @@ TextEdit::TextEdit() { cache.line_number_w = 1; cache.breakpoint_gutter_width = 0; breakpoint_gutter_width = 0; + cache.fold_gutter_width = 0; + fold_gutter_width = 0; indent_size = 4; text.set_indent_size(indent_size); @@ -5098,6 +5540,8 @@ TextEdit::TextEdit() { line_length_guideline = false; line_length_guideline_col = 80; draw_breakpoint_gutter = false; + draw_fold_gutter = false; + hiding_enabled = false; next_operation_is_complex = false; scroll_past_end_of_file_enabled = false; auto_brace_completion_enabled = false; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 50f005ed6a..b1c7b14e58 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -73,6 +73,9 @@ class TextEdit : public Control { struct Cache { Ref<Texture> tab_icon; + Ref<Texture> can_fold_icon; + Ref<Texture> folded_icon; + Ref<Texture> folded_eol_icon; Ref<StyleBox> style_normal; Ref<StyleBox> style_focus; Ref<Font> font; @@ -105,6 +108,7 @@ class TextEdit : public Control { int line_spacing; int line_number_w; int breakpoint_gutter_width; + int fold_gutter_width; Size2 size; } cache; @@ -136,6 +140,7 @@ class TextEdit : public Control { int width_cache : 24; bool marked : 1; bool breakpoint : 1; + bool hidden : 1; Map<int, ColorRegionInfo> region_info; String data; }; @@ -160,6 +165,8 @@ class TextEdit : public Control { bool is_marked(int p_line) const { return text[p_line].marked; } void set_breakpoint(int p_line, bool p_breakpoint) { text[p_line].breakpoint = p_breakpoint; } bool is_breakpoint(int p_line) const { return text[p_line].breakpoint; } + void set_hidden(int p_line, bool p_hidden) { text[p_line].hidden = p_hidden; } + bool is_hidden(int p_line) const { return text[p_line].hidden; } void insert(int p_at, const String &p_text); void remove(int p_at); int size() const { return text.size(); } @@ -251,6 +258,9 @@ class TextEdit : public Control { int line_length_guideline_col; bool draw_breakpoint_gutter; int breakpoint_gutter_width; + bool draw_fold_gutter; + int fold_gutter_width; + bool hiding_enabled; bool highlight_all_occurrences; bool scroll_past_end_of_file_enabled; @@ -293,9 +303,14 @@ class TextEdit : public Control { int search_result_line; int search_result_col; + double line_scroll_pos; + bool context_menu_enabled; int get_visible_rows() const; + int get_total_unhidden_rows() const; + double get_line_scroll_pos(bool p_recalculate = false) const; + void update_line_scroll_pos(); int get_char_count(); @@ -303,6 +318,7 @@ class TextEdit : public Control { int get_column_x_offset(int p_char, String p_str); void adjust_viewport_to_cursor(); + double get_scroll_line_diff() const; void _scroll_moved(double); void _update_scrollbars(); void _v_scroll_input(); @@ -405,6 +421,18 @@ public: void set_line_as_breakpoint(int p_line, bool p_breakpoint); bool is_line_set_as_breakpoint(int p_line) const; void get_breakpoints(List<int> *p_breakpoints) const; + + void set_line_as_hidden(int p_line, bool p_hidden); + bool is_line_hidden(int p_line) const; + void fold_all_lines(); + void unhide_all_lines(); + int num_lines_from(int p_line_from, int unhidden_amount) const; + int get_whitespace_level(int p_line) const; + bool can_fold(int p_line) const; + bool is_folded(int p_line) const; + void fold_line(int p_line); + void unfold_line(int p_line); + String get_text(); String get_line(int line) const; void set_line(int line, String new_text); @@ -433,7 +461,7 @@ public: void center_viewport_to_cursor(); void cursor_set_column(int p_col, bool p_adjust_viewport = true); - void cursor_set_line(int p_row, bool p_adjust_viewport = true); + void cursor_set_line(int p_row, bool p_adjust_viewport = true, bool p_can_be_hidden = true); int cursor_get_column() const; int cursor_get_line() const; @@ -538,6 +566,15 @@ public: void set_breakpoint_gutter_width(int p_gutter_width); int get_breakpoint_gutter_width() const; + void set_draw_fold_gutter(bool p_draw); + bool is_drawing_fold_gutter() const; + + void set_fold_gutter_width(int p_gutter_width); + int get_fold_gutter_width() const; + + void set_hiding_enabled(int p_enabled); + int is_hiding_enabled() const; + void set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata); void set_completion(bool p_enabled, const Vector<String> &p_prefixes); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 06b147ba41..0a886c25b1 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1097,11 +1097,13 @@ void ArrayMesh::_bind_methods() { } void ArrayMesh::reload_from_file() { - for (int i = 0; i < get_surface_count(); i++) { - surface_remove(i); - } + VisualServer::get_singleton()->mesh_clear(mesh); + surfaces.clear(); + clear_blend_shapes(); + Resource::reload_from_file(); - String path = get_path(); + + _change_notify(); } ArrayMesh::ArrayMesh() { diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 3e46705ff8..4febd1a61b 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1279,7 +1279,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view camera->zfar, camera->vaspect - ); + ); ortho = true; } break; case Camera::PERSPECTIVE: { @@ -1291,7 +1291,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view camera->zfar, camera->vaspect - ); + ); ortho = false; } break; @@ -2562,7 +2562,7 @@ bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) { InstanceGIProbeData::LightCache lc; lc.type = VSG::storage->light_get_type(E->get()->base); lc.color = VSG::storage->light_get_color(E->get()->base); - lc.energy = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ENERGY); + lc.energy = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ENERGY) * VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_INDIRECT_ENERGY); lc.radius = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_RANGE); lc.attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ATTENUATION); lc.spot_angle = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ANGLE); @@ -2582,7 +2582,7 @@ bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) { InstanceGIProbeData::LightCache lc; lc.type = VSG::storage->light_get_type(E->get()->base); lc.color = VSG::storage->light_get_color(E->get()->base); - lc.energy = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ENERGY); + lc.energy = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ENERGY) * VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_INDIRECT_ENERGY); lc.radius = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_RANGE); lc.attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ATTENUATION); lc.spot_angle = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ANGLE); diff --git a/servers/visual_server.h b/servers/visual_server.h index 4e43d0bd17..3edde7ec85 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -360,6 +360,7 @@ public: enum LightParam { LIGHT_PARAM_ENERGY, + LIGHT_PARAM_INDIRECT_ENERGY, LIGHT_PARAM_SPECULAR, LIGHT_PARAM_RANGE, LIGHT_PARAM_ATTENUATION, |