diff options
50 files changed, 729 insertions, 460 deletions
diff --git a/SConstruct b/SConstruct index e8f9ec2964..7a8db10931 100644 --- a/SConstruct +++ b/SConstruct @@ -65,7 +65,7 @@ platform_arg = ARGUMENTS.get("platform", ARGUMENTS.get("p", False)) if (os.name == "posix"): pass elif (os.name == "nt"): - if (os.getenv("VCINSTALLDIR") == None or platform_arg == "android" or platform_arg == "javascript"): + if platform_arg == "android" or platform_arg == "javascript" or ARGUMENTS.get("use_mingw", False): custom_tools = ['mingw'] env_base = Environment(tools=custom_tools) @@ -92,6 +92,7 @@ env_base.use_ptrcall = False env_base.split_drivers = False env_base.split_modules = False env_base.module_version_string = "" +env_base.msvc = False # To decide whether to rebuild a file, use the MD5 sum only if the timestamp has changed. # http://scons.org/doc/production/HTML/scons-user/ch06.html#idm139837621851792 @@ -240,14 +241,13 @@ sys.modules.pop('detect') """ if (env_base['target'] == 'debug'): - env_base.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC']) - env_base.Append(CPPFLAGS=['-DSCI_NAMESPACE']) + env_base.Append(CPPDEFINES=['DEBUG_MEMORY_ALLOC', 'SCI_NAMESPACE']) if (env_base['no_editor_splash']): - env_base.Append(CPPFLAGS=['-DNO_EDITOR_SPLASH']) + env_base.Append(CPPDEFINES=['NO_EDITOR_SPLASH']) if not env_base['deprecated']: - env_base.Append(CPPFLAGS=['-DDISABLE_DEPRECATED']) + env_base.Append(CPPDEFINES=['DISABLE_DEPRECATED']) env_base.platforms = {} @@ -329,9 +329,7 @@ if selected_platform in platform_list: if (env["warnings"] == 'yes'): print("WARNING: warnings=yes is deprecated; assuming warnings=all") - env.msvc = 0 - if (os.name == "nt" and os.getenv("VCINSTALLDIR") and (platform_arg == "windows" or platform_arg == "uwp")): # MSVC, needs to stand out of course - env.msvc = 1 + if env.msvc: disable_nonessential_warnings = ['/wd4267', '/wd4244', '/wd4305', '/wd4800'] # Truncations, narrowing conversions... if (env["warnings"] == 'extra'): env.Append(CCFLAGS=['/Wall']) # Implies /W4 @@ -363,7 +361,7 @@ if selected_platform in platform_list: print("Tools can only be built with targets 'debug' and 'release_debug'.") sys.exit(255) suffix += ".opt" - env.Append(CCFLAGS=['-DNDEBUG']) + env.Append(CPPDEFINES=['NDEBUG']) elif (env["target"] == "release_debug"): if env["tools"]: @@ -420,25 +418,25 @@ if selected_platform in platform_list: env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"] if (env.use_ptrcall): - env.Append(CPPFLAGS=['-DPTRCALL_ENABLED']) + env.Append(CPPDEFINES=['PTRCALL_ENABLED']) # to test 64 bits compiltion # env.Append(CPPFLAGS=['-m64']) if env['tools']: - env.Append(CPPFLAGS=['-DTOOLS_ENABLED']) + env.Append(CPPDEFINES=['TOOLS_ENABLED']) if env['disable_3d']: - env.Append(CPPFLAGS=['-D_3D_DISABLED']) + env.Append(CPPDEFINES=['_3D_DISABLED']) if env['gdscript']: - env.Append(CPPFLAGS=['-DGDSCRIPT_ENABLED']) + env.Append(CPPDEFINES=['GDSCRIPT_ENABLED']) if env['disable_advanced_gui']: - env.Append(CPPFLAGS=['-DADVANCED_GUI_DISABLED']) + env.Append(CPPDEFINES=['ADVANCED_GUI_DISABLED']) if env['minizip']: - env.Append(CPPFLAGS=['-DMINIZIP_ENABLED']) + env.Append(CPPDEFINES=['MINIZIP_ENABLED']) if env['xml']: - env.Append(CPPFLAGS=['-DXML_ENABLED']) + env.Append(CPPDEFINES=['XML_ENABLED']) if not env['verbose']: methods.no_verbose(sys, env) @@ -479,10 +477,7 @@ if selected_platform in platform_list: if ("check_c_headers" in env): for header in env["check_c_headers"]: if (conf.CheckCHeader(header[0])): - if (env.msvc): - env.Append(CCFLAGS=['/D' + header[1]]) - else: - env.Append(CCFLAGS=['-D' + header[1]]) + env.AppendUnique(CPPDEFINES=[header[1]]) else: @@ -491,122 +486,120 @@ else: for x in platform_list: print("\t" + x) print("\nPlease run scons again with argument: platform=<string>") - sys.exit(255) -screen = sys.stdout -node_count = 0 -node_count_max = 0 -node_count_interval = 1 -if ('env' in locals()): +# The following only makes sense when the env is defined, and assumes it is +if 'env' in locals(): + screen = sys.stdout + # Progress reporting is not available in non-TTY environments since it + # messes with the output (for example, when writing to a file) + show_progress = (env['progress'] and sys.stdout.isatty()) + node_count = 0 + node_count_max = 0 + node_count_interval = 1 node_count_fname = str(env.Dir('#')) + '/.scons_node_count' -# Progress reporting is not available in non-TTY environments since it -# messes with the output (for example, when writing to a file) -if sys.stdout.isatty(): - show_progress = env['progress'] -else: - show_progress = False - -import time, math - -class cache_progress: - # The default is 1 GB cache and 12 hours half life - def __init__(self, path = None, limit = 1073741824, half_life = 43200): - self.path = path - self.limit = limit - self.exponent_scale = math.log(2) / half_life - if env['verbose'] and path != None: - screen.write('Current cache limit is ' + self.convert_size(limit) + ' (used: ' + self.convert_size(self.get_size(path)) + ')\n') - self.delete(self.file_list()) - - def __call__(self, node, *args, **kw): - global node_count, node_count_max, node_count_interval, node_count_fname, show_progress - if show_progress: - # Print the progress percentage - node_count += node_count_interval - if (node_count_max > 0 and node_count <= node_count_max): - screen.write('\r[%3d%%] ' % (node_count * 100 / node_count_max)) - screen.flush() - elif (node_count_max > 0 and node_count > node_count_max): - screen.write('\r[100%] ') - screen.flush() + + import time, math + + class cache_progress: + # The default is 1 GB cache and 12 hours half life + def __init__(self, path = None, limit = 1073741824, half_life = 43200): + self.path = path + self.limit = limit + self.exponent_scale = math.log(2) / half_life + if env['verbose'] and path != None: + screen.write('Current cache limit is ' + self.convert_size(limit) + ' (used: ' + self.convert_size(self.get_size(path)) + ')\n') + self.delete(self.file_list()) + + def __call__(self, node, *args, **kw): + global node_count, node_count_max, node_count_interval, node_count_fname, show_progress + if show_progress: + # Print the progress percentage + node_count += node_count_interval + if (node_count_max > 0 and node_count <= node_count_max): + screen.write('\r[%3d%%] ' % (node_count * 100 / node_count_max)) + screen.flush() + elif (node_count_max > 0 and node_count > node_count_max): + screen.write('\r[100%] ') + screen.flush() + else: + screen.write('\r[Initial build] ') + screen.flush() + + def delete(self, files): + if len(files) == 0: + return + if env['verbose']: + # Utter something + screen.write('\rPurging %d %s from cache...\n' % (len(files), len(files) > 1 and 'files' or 'file')) + [os.remove(f) for f in files] + + def file_list(self): + if self.path == None: + # Nothing to do + return [] + # Gather a list of (filename, (size, atime)) within the + # cache directory + file_stat = [(x, os.stat(x)[6:8]) for x in glob.glob(os.path.join(self.path, '*', '*'))] + if file_stat == []: + # Nothing to do + return [] + # Weight the cache files by size (assumed to be roughly + # proportional to the recompilation time) times an exponential + # decay since the ctime, and return a list with the entries + # (filename, size, weight). + current_time = time.time() + file_stat = [(x[0], x[1][0], (current_time - x[1][1])) for x in file_stat] + # Sort by the most resently accessed files (most sensible to keep) first + file_stat.sort(key=lambda x: x[2]) + # Search for the first entry where the storage limit is + # reached + sum, mark = 0, None + for i,x in enumerate(file_stat): + sum += x[1] + if sum > self.limit: + mark = i + break + if mark == None: + return [] else: - screen.write('\r[Initial build] ') - screen.flush() - - def delete(self, files): - if len(files) == 0: - return - if env['verbose']: - # Utter something - screen.write('\rPurging %d %s from cache...\n' % (len(files), len(files) > 1 and 'files' or 'file')) - [os.remove(f) for f in files] - - def file_list(self): - if self.path == None: - # Nothing to do - return [] - # Gather a list of (filename, (size, atime)) within the - # cache directory - file_stat = [(x, os.stat(x)[6:8]) for x in glob.glob(os.path.join(self.path, '*', '*'))] - if file_stat == []: - # Nothing to do - return [] - # Weight the cache files by size (assumed to be roughly - # proportional to the recompilation time) times an exponential - # decay since the ctime, and return a list with the entries - # (filename, size, weight). - current_time = time.time() - file_stat = [(x[0], x[1][0], (current_time - x[1][1])) for x in file_stat] - # Sort by the most resently accessed files (most sensible to keep) first - file_stat.sort(key=lambda x: x[2]) - # Search for the first entry where the storage limit is - # reached - sum, mark = 0, None - for i,x in enumerate(file_stat): - sum += x[1] - if sum > self.limit: - mark = i - break - if mark == None: - return [] - else: - return [x[0] for x in file_stat[mark:]] - - def convert_size(self, size_bytes): - if size_bytes == 0: - return "0 bytes" - size_name = ("bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") - i = int(math.floor(math.log(size_bytes, 1024))) - p = math.pow(1024, i) - s = round(size_bytes / p, 2) - return "%s %s" % (int(s) if i == 0 else s, size_name[i]) - - def get_size(self, start_path = '.'): - total_size = 0 - for dirpath, dirnames, filenames in os.walk(start_path): - for f in filenames: - fp = os.path.join(dirpath, f) - total_size += os.path.getsize(fp) - return total_size - -def progress_finish(target, source, env): - global node_count, progressor - with open(node_count_fname, 'w') as f: - f.write('%d\n' % node_count) - progressor.delete(progressor.file_list()) - -try: - with open(node_count_fname) as f: - node_count_max = int(f.readline()) -except: - pass -cache_directory = os.environ.get("SCONS_CACHE") -# Simple cache pruning, attached to SCons' progress callback. Trim the -# cache directory to a size not larger than cache_limit. -cache_limit = float(os.getenv("SCONS_CACHE_LIMIT", 1024)) * 1024 * 1024 -progressor = cache_progress(cache_directory, cache_limit) -Progress(progressor, interval = node_count_interval) - -progress_finish_command = Command('progress_finish', [], progress_finish) -AlwaysBuild(progress_finish_command) + return [x[0] for x in file_stat[mark:]] + + def convert_size(self, size_bytes): + if size_bytes == 0: + return "0 bytes" + size_name = ("bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") + i = int(math.floor(math.log(size_bytes, 1024))) + p = math.pow(1024, i) + s = round(size_bytes / p, 2) + return "%s %s" % (int(s) if i == 0 else s, size_name[i]) + + def get_size(self, start_path = '.'): + total_size = 0 + for dirpath, dirnames, filenames in os.walk(start_path): + for f in filenames: + fp = os.path.join(dirpath, f) + total_size += os.path.getsize(fp) + return total_size + + def progress_finish(target, source, env): + global node_count, progressor + with open(node_count_fname, 'w') as f: + f.write('%d\n' % node_count) + progressor.delete(progressor.file_list()) + + try: + with open(node_count_fname) as f: + node_count_max = int(f.readline()) + except: + pass + + cache_directory = os.environ.get("SCONS_CACHE") + # Simple cache pruning, attached to SCons' progress callback. Trim the + # cache directory to a size not larger than cache_limit. + cache_limit = float(os.getenv("SCONS_CACHE_LIMIT", 1024)) * 1024 * 1024 + progressor = cache_progress(cache_directory, cache_limit) + Progress(progressor, interval = node_count_interval) + + progress_finish_command = Command('progress_finish', [], progress_finish) + AlwaysBuild(progress_finish_command) diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 97b469861c..842f5f0af6 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -177,7 +177,7 @@ bool Variant::booleanize() const { CASE_TYPE(m_prefix, m_op_name, m_name) { \ if (p_b.type == INT) _RETURN(p_a._data.m_type m_op p_b._data._int); \ if (p_b.type == REAL) _RETURN(p_a._data.m_type m_op p_b._data._real); \ - if (p_b.type == NIL) _RETURN(!p_b.type m_op NIL); \ + if (p_b.type == NIL) _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ }; @@ -252,7 +252,7 @@ bool Variant::booleanize() const { CASE_TYPE(m_prefix, m_op_name, m_name) { \ if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \ if (p_b.type == NODE_PATH) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \ - if (p_b.type == NIL) _RETURN(!p_b.type m_op NIL); \ + if (p_b.type == NIL) _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ }; @@ -278,7 +278,7 @@ bool Variant::booleanize() const { if (p_b.type == m_name) \ _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \ if (p_b.type == NIL) \ - _RETURN(!p_b.type m_op NIL); \ + _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ }; @@ -323,7 +323,7 @@ bool Variant::booleanize() const { if (p_b.type == m_name) \ _RETURN(*p_a._data.m_sub m_op *p_b._data.m_sub); \ if (p_b.type == NIL) \ - _RETURN(!p_b.type m_op NIL); \ + _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ } diff --git a/doc/classes/DynamicFontData.xml b/doc/classes/DynamicFontData.xml index 510f19dd78..7b34d02316 100644 --- a/doc/classes/DynamicFontData.xml +++ b/doc/classes/DynamicFontData.xml @@ -16,7 +16,19 @@ <member name="font_path" type="String" setter="set_font_path" getter="get_font_path"> The path to the vector font file. </member> + <member name="hinting" type="int" setter="set_hinting" getter="get_hinting" enum="DynamicFontData.Hinting"> + The font hinting mode used by FreeType. + </member> </members> <constants> + <constant name="HINTING_NONE" value="0" enum="Hinting"> + Disable font hinting (smoother but less crisp). + </constant> + <constant name="HINTING_LIGHT" value="1" enum="Hinting"> + Use the light font hinting mode. + </constant> + <constant name="HINTING_NORMAL" value="2" enum="Hinting"> + Use the default font hinting mode (crisper but less smooth). + </constant> </constants> </class> diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml index 048c90e515..18adaa645c 100644 --- a/doc/classes/Environment.xml +++ b/doc/classes/Environment.xml @@ -4,8 +4,9 @@ Resource for environment nodes (like [WorldEnvironment]) that define multiple rendering options. </brief_description> <description> - Resource for environment nodes (like [WorldEnvironment]) that define multiple environment operations (such as background [Sky] or [Color], ambient light, fog, depth-of-field...). These parameters affect the final render of the scene. The order of these operations is: - - DOF Blur + Resource for environment nodes (like [WorldEnvironment]) that define multiple environment operations (such as background [Sky] or [Color], ambient light, fog, depth-of-field...). These parameters affect the final render of the scene. The order of these operations is: + + - DOF Blur - Motion Blur - Bloom - Tonemap (auto exposure) @@ -13,7 +14,7 @@ </description> <tutorials> http://docs.godotengine.org/en/3.0/tutorials/3d/environment_and_post_processing.html - http://docs.godotengine.org/en/3.0/tutorials/3d/high_dynamic_range.html + http://docs.godotengine.org/en/3.0/tutorials/3d/high_dynamic_range.html </tutorials> <demos> </demos> diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index a7a6c2ef45..5b2e019c4c 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -7,6 +7,7 @@ A Singleton that deals with inputs. This includes key presses, mouse buttons and movement, joypads, and input actions. Actions and their events can be set in the Project Settings / Input Map tab. Or be set with [InputMap]. </description> <tutorials> + http://docs.godotengine.org/en/3.0/tutorials/inputs/index.html </tutorials> <demos> </demos> @@ -44,7 +45,7 @@ <return type="Vector3"> </return> <description> - If the device has an accelerometer, this will return the movement. + If the device has an accelerometer, this will return the acceleration. Otherwise, it returns an empty [Vector3]. </description> </method> <method name="get_connected_joypads"> @@ -58,13 +59,14 @@ <return type="Vector3"> </return> <description> + If the device has an accelerometer, this will return the gravity. Otherwise, it returns an empty [Vector3]. </description> </method> <method name="get_gyroscope" qualifiers="const"> <return type="Vector3"> </return> <description> - If the device has a gyroscope, this will return the rate of rotation in rad/s around a device's x, y, and z axis. + If the device has a gyroscope, this will return the rate of rotation in rad/s around a device's x, y, and z axis. Otherwise, it returns an empty [Vector3]. </description> </method> <method name="get_joy_axis" qualifiers="const"> @@ -259,6 +261,7 @@ <argument index="0" name="event" type="InputEvent"> </argument> <description> + Feeds an [InputEvent] to the game. Can be used to artificially trigger input events from code. </description> </method> <method name="remove_joy_mapping"> @@ -334,7 +337,7 @@ <argument index="1" name="connected" type="bool"> </argument> <description> - Emitted when a joypad device has been connected or disconnected + Emitted when a joypad device has been connected or disconnected. </description> </signal> </signals> @@ -349,40 +352,58 @@ Captures the mouse. The mouse will be hidden and unable to leave the game window. But it will still register movement and mouse button presses. </constant> <constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode"> + Makes the mouse cursor visible but confines it to the game window. </constant> <constant name="CURSOR_ARROW" value="0" enum="CursorShape"> + Arrow cursor. Standard, default pointing cursor. </constant> <constant name="CURSOR_IBEAM" value="1" enum="CursorShape"> + I-beam cursor. Usually used to show where the text cursor will appear when the mouse is clicked. </constant> <constant name="CURSOR_POINTING_HAND" value="2" enum="CursorShape"> + Pointing hand cursor. Usually used to indicate the pointer is over a link or other interactable item. </constant> <constant name="CURSOR_CROSS" value="3" enum="CursorShape"> + Cross cursor. Typically appears over regions in which a drawing operation can be performance or for selections. </constant> <constant name="CURSOR_WAIT" value="4" enum="CursorShape"> + Wait cursor. Indicates that the application is busy performing an operation. </constant> <constant name="CURSOR_BUSY" value="5" enum="CursorShape"> + Busy cursor. See [code]CURSOR_WAIT[/code]. </constant> <constant name="CURSOR_DRAG" value="6" enum="CursorShape"> + Drag cursor. Usually displayed when dragging something. </constant> <constant name="CURSOR_CAN_DROP" value="7" enum="CursorShape"> + Can drop cursor. Usually displayed when dragging something to indicate that it can be dropped at the current position. </constant> <constant name="CURSOR_FORBIDDEN" value="8" enum="CursorShape"> + Forbidden cursor. Indicates that the current action is forbidden (for example, when dragging something) or that the control at a position is disabled. </constant> <constant name="CURSOR_VSIZE" value="9" enum="CursorShape"> + Vertical resize mouse cursor. A double headed vertical arrow. It tells the user they can resize the window or the panel vertically. </constant> <constant name="CURSOR_HSIZE" value="10" enum="CursorShape"> + Horizontal resize mouse cursor. A double headed horizontal arrow. It tells the user they can resize the window or the panel horizontally. </constant> <constant name="CURSOR_BDIAGSIZE" value="11" enum="CursorShape"> + Window resize mouse cursor. The cursor is a double headed arrow that goes from the bottom left to the top right. It tells the user they can resize the window or the panel both horizontally and vertically. </constant> <constant name="CURSOR_FDIAGSIZE" value="12" enum="CursorShape"> + Window resize mouse cursor. The cursor is a double headed arrow that goes from the top left to the bottom right, the opposite of [code]CURSOR_BDIAGSIZE[/code]. It tells the user they can resize the window or the panel both horizontally and vertically. </constant> <constant name="CURSOR_MOVE" value="13" enum="CursorShape"> + Move cursor. Indicates that something can be moved. </constant> <constant name="CURSOR_VSPLIT" value="14" enum="CursorShape"> + Vertical split mouse cursor. On Windows, it's the same as [code]CURSOR_VSIZE[/code]. </constant> <constant name="CURSOR_HSPLIT" value="15" enum="CursorShape"> + Horizontal split mouse cursor. On Windows, it's the same as [code]CURSOR_HSIZE[/code]. </constant> <constant name="CURSOR_HELP" value="16" enum="CursorShape"> + Help cursor. Usually a question mark. </constant> </constants> </class> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 237b5f62d4..6ee9489995 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -19,6 +19,13 @@ Clear all cells. </description> </method> + <method name="fix_invalid_tiles"> + <return type="void"> + </return> + <description> + Clear cells that does not exist in the tileset. + </description> + </method> <method name="get_cell" qualifiers="const"> <return type="int"> </return> diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 3944431516..5a4be6df4f 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -244,7 +244,7 @@ static void _get_drives(List<String> *list) { // Parse only file:// links if (strncmp(string, "file://", 7) == 0) { // Strip any unwanted edges on the strings and push_back if it's not a duplicate - String fpath = String(string + 7).strip_edges(); + String fpath = String(string + 7).strip_edges().split_spaces()[0].percent_decode(); if (!list->find(fpath)) { list->push_back(fpath); } diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 9ab539da07..360ed620f6 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -44,9 +44,11 @@ void EditorAbout::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - Ref<Font> font = EditorNode::get_singleton()->get_gui_base()->get_font("source", "EditorFonts"); + Control *base = EditorNode::get_singleton()->get_gui_base(); + Ref<Font> font = base->get_font("source", "EditorFonts"); _tpl_text->add_font_override("normal_font", font); _license_text->add_font_override("normal_font", font); + _logo->set_texture(base->get_icon("Logo", "EditorIcons")); } break; } } diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 0b39540273..ac4402d50b 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -121,6 +121,26 @@ void EditorAudioBus::_notification(int p_what) { set_process(is_visible_in_tree()); } + + if (p_what == NOTIFICATION_THEME_CHANGED) { + + for (int i = 0; i < cc; i++) { + channel[i].vu_l->set_under_texture(get_icon("BusVuEmpty", "EditorIcons")); + channel[i].vu_l->set_progress_texture(get_icon("BusVuFull", "EditorIcons")); + channel[i].vu_r->set_under_texture(get_icon("BusVuEmpty", "EditorIcons")); + channel[i].vu_r->set_progress_texture(get_icon("BusVuFull", "EditorIcons")); + channel[i].prev_active = true; + } + scale->set_texture(get_icon("BusVuDb", "EditorIcons")); + + disabled_vu = get_icon("BusVuFrozen", "EditorIcons"); + + solo->set_icon(get_icon("AudioBusSolo", "EditorIcons")); + mute->set_icon(get_icon("AudioBusMute", "EditorIcons")); + bypass->set_icon(get_icon("AudioBusBypass", "EditorIcons")); + + bus_options->set_icon(get_icon("GuiMiniTabMenu", "EditorIcons")); + } } void EditorAudioBus::update_send() { diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 27d086d19e..d8ae1da72e 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -275,9 +275,13 @@ void EditorFileSystem::_scan_filesystem() { memdelete(d); f = FileAccess::open(fscache, FileAccess::WRITE); - _save_filesystem_cache(new_filesystem, f); - f->close(); - memdelete(f); + if (f == NULL) { + ERR_PRINTS("Error writing fscache: " + fscache); + } else { + _save_filesystem_cache(new_filesystem, f); + f->close(); + memdelete(f); + } scanning = false; } @@ -286,9 +290,13 @@ void EditorFileSystem::_save_filesystem_cache() { 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); - f->close(); - memdelete(f); + if (f == NULL) { + ERR_PRINTS("Error writing fscache: " + fscache); + } else { + _save_filesystem_cache(filesystem, f); + f->close(); + memdelete(f); + } } void EditorFileSystem::_thread_func(void *_userdata) { diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index a58257962a..2ec3cdb08f 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -103,9 +103,11 @@ void editor_register_fonts(Ref<Theme> p_theme) { /* Custom font */ String custom_font = EditorSettings::get_singleton()->get("interface/editor/main_font"); + DynamicFontData::Hinting font_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/main_font_hinting"); Ref<DynamicFontData> CustomFont; if (custom_font.length() > 0) { CustomFont.instance(); + CustomFont->set_hinting(font_hinting); CustomFont->set_font_path(custom_font); CustomFont->set_force_autohinter(true); //just looks better..i think? } @@ -113,9 +115,11 @@ void editor_register_fonts(Ref<Theme> p_theme) { /* Custom source code font */ String custom_font_source = EditorSettings::get_singleton()->get("interface/editor/code_font"); + DynamicFontData::Hinting font_source_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/code_font_hinting"); Ref<DynamicFontData> CustomFontSource; if (custom_font_source.length() > 0) { CustomFontSource.instance(); + CustomFontSource->set_hinting(font_source_hinting); CustomFontSource->set_font_path(custom_font_source); } @@ -123,38 +127,45 @@ void editor_register_fonts(Ref<Theme> p_theme) { Ref<DynamicFontData> DefaultFont; DefaultFont.instance(); + DefaultFont->set_hinting(font_hinting); DefaultFont->set_font_ptr(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size); DefaultFont->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontFallback; FontFallback.instance(); + FontFallback->set_hinting(font_hinting); FontFallback->set_font_ptr(_font_DroidSansFallback, _font_DroidSansFallback_size); FontFallback->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontJapanese; FontJapanese.instance(); + FontJapanese->set_hinting(font_hinting); FontJapanese->set_font_ptr(_font_DroidSansJapanese, _font_DroidSansJapanese_size); FontJapanese->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontArabic; FontArabic.instance(); + FontArabic->set_hinting(font_hinting); FontArabic->set_font_ptr(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); FontArabic->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontHebrew; FontHebrew.instance(); + FontHebrew->set_hinting(font_hinting); FontHebrew->set_font_ptr(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size); FontHebrew->set_force_autohinter(true); //just looks better..i think? Ref<DynamicFontData> FontThai; FontThai.instance(); + FontThai->set_hinting(font_hinting); FontThai->set_font_ptr(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size); FontThai->set_force_autohinter(true); //just looks better..i think? - /* Source Code Pro */ + /* Hack */ Ref<DynamicFontData> dfmono; dfmono.instance(); + dfmono->set_hinting(font_source_hinting); dfmono->set_font_ptr(_font_Hack_Regular, _font_Hack_Regular_size); //dfd->set_force_autohinter(true); //just looks better..i think? diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 309a3b42ab..e627263909 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -349,14 +349,20 @@ void EditorNode::_notification(int p_what) { // update_icons for (int i = 0; i < singleton->main_editor_buttons.size(); i++) { - Ref<Texture> icon = singleton->main_editor_buttons[i]->get_icon(); + + ToolButton *tb = singleton->main_editor_buttons[i]; + EditorPlugin *p_editor = singleton->editor_table[i]; + Ref<Texture> icon = p_editor->get_icon(); if (icon.is_valid()) { - main_editor_buttons[i]->set_icon(icon); - } else if (singleton->gui_base->has_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons")) { - main_editor_buttons[i]->set_icon(gui_base->get_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons")); + tb->set_icon(icon); + } else if (singleton->gui_base->has_icon(p_editor->get_name(), "EditorIcons")) { + tb->set_icon(singleton->gui_base->get_icon(p_editor->get_name(), "EditorIcons")); } } + + _build_icon_type_cache(); + play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons")); play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons")); play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom", "EditorIcons")); @@ -382,6 +388,15 @@ void EditorNode::_notification(int p_what) { dock_tab_move_left->set_icon(theme->get_icon("Back", "EditorIcons")); dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons")); update_menu->set_icon(gui_base->get_icon("Progress1", "EditorIcons")); + + PopupMenu *p = help_menu->get_popup(); + p->set_item_icon(p->get_item_index(HELP_CLASSES), gui_base->get_icon("ClassList", "EditorIcons")); + p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_icon("HelpSearch", "EditorIcons")); + p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_icon("Instance", "EditorIcons")); + p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_icon("Instance", "EditorIcons")); + p->set_item_icon(p->get_item_index(HELP_ISSUES), gui_base->get_icon("Instance", "EditorIcons")); + p->set_item_icon(p->get_item_index(HELP_COMMUNITY), gui_base->get_icon("Instance", "EditorIcons")); + p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_icon("Godot", "EditorIcons")); } if (p_what == Control::NOTIFICATION_RESIZED) { @@ -984,6 +999,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { String file = cache_base + ".png"; + post_process_preview(img); img->save_png(file); } @@ -3444,6 +3460,19 @@ Ref<Texture> EditorNode::_file_dialog_get_icon(const String &p_path) { return singleton->icon_type_cache["Object"]; } +void EditorNode::_build_icon_type_cache() { + + List<StringName> tl; + StringName ei = "EditorIcons"; + theme_base->get_theme()->get_icon_list(ei, &tl); + for (List<StringName>::Element *E = tl.front(); E; E = E->next()) { + + if (!ClassDB::class_exists(E->get())) + continue; + icon_type_cache[E->get()] = theme_base->get_theme()->get_icon(E->get(), ei); + } +} + void EditorNode::_file_dialog_register(FileDialog *p_dialog) { singleton->file_dialogs.insert(p_dialog); @@ -5135,7 +5164,6 @@ EditorNode::EditorNode() { gui_base->add_child(export_template_manager); about = memnew(EditorAbout); - about->get_logo()->set_texture(gui_base->get_icon("Logo", "EditorIcons")); gui_base->add_child(about); warning = memnew(AcceptDialog); @@ -5801,17 +5829,7 @@ EditorNode::EditorNode() { EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_fs_changed"); EditorFileSystem::get_singleton()->connect("resources_reimported", this, "_resources_reimported"); - { - List<StringName> tl; - StringName ei = "EditorIcons"; - theme_base->get_theme()->get_icon_list(ei, &tl); - for (List<StringName>::Element *E = tl.front(); E; E = E->next()) { - - if (!ClassDB::class_exists(E->get())) - continue; - icon_type_cache[E->get()] = theme_base->get_theme()->get_icon(E->get(), ei); - } - } + _build_icon_type_cache(); Node::set_human_readable_collision_renaming(true); diff --git a/editor/editor_node.h b/editor/editor_node.h index 6d96c2dea7..9090066dea 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -496,6 +496,7 @@ private: Set<EditorFileDialog *> editor_file_dialogs; Map<String, Ref<Texture> > icon_type_cache; + void _build_icon_type_cache(); bool _initializing_addons; Map<String, EditorPlugin *> plugin_addons; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 29363e29c1..3a75673560 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -290,6 +290,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["interface/editor/main_font_size"] = PropertyInfo(Variant::INT, "interface/editor/main_font_size", PROPERTY_HINT_RANGE, "10,40,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/code_font_size", 14); hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + _initial_set("interface/editor/main_font_hinting", 2); + hints["interface/editor/main_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/main_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + _initial_set("interface/editor/code_font_hinting", 2); + hints["interface/editor/code_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/code_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/main_font", ""); hints["interface/editor/main_font"] = PropertyInfo(Variant::STRING, "interface/editor/main_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/code_font", ""); @@ -959,11 +963,8 @@ void EditorSettings::save() { Error err = ResourceSaver::save(singleton->config_file_path, singleton); if (err != OK) { - ERR_PRINT("Can't Save!"); - return; - } - - if (OS::get_singleton()->is_stdout_verbose()) { + ERR_PRINTS("Error saving editor settings to " + singleton->config_file_path); + } else if (OS::get_singleton()->is_stdout_verbose()) { print_line("EditorSettings Save OK!"); } } diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 4b9e5ae301..c203b4b81e 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -514,6 +514,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { download = memnew(HTTPRequest); add_child(download); download->connect("request_completed", this, "_http_download_completed"); + download->set_use_threads(EDITOR_DEF("asset_library/use_threads", true)); download_error = memnew(AcceptDialog); add_child(download_error); @@ -533,11 +534,9 @@ void EditorAssetLibrary::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { - TextureRect *tf = memnew(TextureRect); - tf->set_texture(get_icon("Error", "EditorIcons")); + error_tr->set_texture(get_icon("Error", "EditorIcons")); reverse->set_icon(get_icon("Sort", "EditorIcons")); - error_hb->add_child(tf); error_label->raise(); } break; @@ -585,6 +584,8 @@ void EditorAssetLibrary::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { library_scroll_bg->add_style_override("panel", get_stylebox("bg", "Tree")); + error_tr->set_texture(get_icon("Error", "EditorIcons")); + reverse->set_icon(get_icon("Sort", "EditorIcons")); } break; } } @@ -832,6 +833,7 @@ void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, Imag iq.image_index = p_image_index; iq.image_type = p_type; iq.request = memnew(HTTPRequest); + iq.request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true)); iq.target = p_for; iq.queue_id = ++last_queue_id; @@ -1452,6 +1454,8 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { error_label = memnew(Label); error_label->add_color_override("color", get_color("error_color", "Editor")); error_hb->add_child(error_label); + error_tr = memnew(TextureRect); + error_hb->add_child(error_tr); description = NULL; diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index b344716c1d..89b79d7cfb 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -194,6 +194,7 @@ class EditorAssetLibrary : public PanelContainer { Button *search; ProgressBar *load_status; HBoxContainer *error_hb; + TextureRect *error_tr; Label *error_label; MenuButton *support; diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 47d730cdf1..8542296bde 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -40,7 +40,7 @@ #include "scene/resources/material.h" #include "scene/resources/mesh.h" -static void post_process_preview(Ref<Image> p_image) { +void post_process_preview(Ref<Image> p_image) { if (p_image->get_format() != Image::FORMAT_RGBA8) p_image->convert(Image::FORMAT_RGBA8); diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index 2e12515e30..35b5c3a5f0 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -33,6 +33,8 @@ #include "editor/editor_resource_preview.h" +void post_process_preview(Ref<Image> p_image); + class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorTexturePreviewPlugin, EditorResourcePreviewGenerator) public: diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp index fd5a1f185f..5020f5b851 100644 --- a/editor/plugins/item_list_editor_plugin.cpp +++ b/editor/plugins/item_list_editor_plugin.cpp @@ -247,7 +247,7 @@ void ItemListEditor::_node_removed(Node *p_node) { void ItemListEditor::_notification(int p_notification) { - if (p_notification == NOTIFICATION_ENTER_TREE) { + if (p_notification == NOTIFICATION_ENTER_TREE || p_notification == NOTIFICATION_THEME_CHANGED) { add_button->set_icon(get_icon("Add", "EditorIcons")); del_button->set_icon(get_icon("Remove", "EditorIcons")); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 8272ec2efd..4367fe8976 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -601,6 +601,7 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) { void TextureRegionEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_READY: { zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons")); zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index c97e949403..c5c7272ed2 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -48,6 +48,20 @@ void TileMapEditor::_notification(int p_what) { } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + + bool new_show_tile_info = EditorSettings::get_singleton()->get("editors/tile_map/show_tile_info_on_hover"); + if (new_show_tile_info != show_tile_info) { + show_tile_info = new_show_tile_info; + tile_info->set_visible(show_tile_info); + } + + if (is_visible_in_tree()) { + _update_palette(); + } + + } // fallthrough + case NOTIFICATION_ENTER_TREE: { transp->set_icon(get_icon("Transpose", "EditorIcons")); @@ -60,19 +74,13 @@ void TileMapEditor::_notification(int p_what) { search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); - } break; - - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - - bool new_show_tile_info = EditorSettings::get_singleton()->get("editors/tile_map/show_tile_info_on_hover"); - if (new_show_tile_info != show_tile_info) { - show_tile_info = new_show_tile_info; - tile_info->set_visible(show_tile_info); - } + PopupMenu *p = options->get_popup(); + p->set_item_icon(p->get_item_index(OPTION_PAINTING), get_icon("Edit", "EditorIcons")); + p->set_item_icon(p->get_item_index(OPTION_PICK_TILE), get_icon("ColorPick", "EditorIcons")); + p->set_item_icon(p->get_item_index(OPTION_SELECT), get_icon("ToolSelect", "EditorIcons")); + p->set_item_icon(p->get_item_index(OPTION_DUPLICATE), get_icon("Duplicate", "EditorIcons")); + p->set_item_icon(p->get_item_index(OPTION_ERASE_SELECTION), get_icon("Remove", "EditorIcons")); - if (is_visible_in_tree()) { - _update_palette(); - } } break; } } @@ -139,6 +147,15 @@ void TileMapEditor::_menu_option(int p_option) { canvas_item_editor->update(); } break; + case OPTION_FIX_INVALID: { + + undo_redo->create_action(TTR("Fix Invalid Tiles")); + undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + node->fix_invalid_tiles(); + undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); + undo_redo->commit_action(); + + } break; } } @@ -1511,8 +1528,8 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { bucket_cache_tile = -1; bucket_cache_visited = 0; - ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase selection"), KEY_DELETE); - ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find tile"), KEY_MASK_CMD + KEY_F); + ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase Selection"), KEY_DELETE); + ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find Tile"), KEY_MASK_CMD + KEY_F); ED_SHORTCUT("tile_map_editor/transpose", TTR("Transpose"), KEY_T); ED_SHORTCUT("tile_map_editor/mirror_x", TTR("Mirror X"), KEY_A); ED_SHORTCUT("tile_map_editor/mirror_y", TTR("Mirror Y"), KEY_S); @@ -1575,6 +1592,8 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { p->add_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_MASK_CMD + KEY_B), OPTION_SELECT); p->add_shortcut(ED_SHORTCUT("tile_map_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_CMD + KEY_D), OPTION_DUPLICATE); p->add_shortcut(ED_GET_SHORTCUT("tile_map_editor/erase_selection"), OPTION_ERASE_SELECTION); + p->add_separator(); + p->add_item(TTR("Fix Invalid Tiles"), OPTION_FIX_INVALID); p->connect("id_pressed", this, "_menu_option"); diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index 0a937e200e..2d582d030b 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -71,6 +71,7 @@ class TileMapEditor : public VBoxContainer { OPTION_DUPLICATE, OPTION_ERASE_SELECTION, OPTION_PAINTING, + OPTION_FIX_INVALID, }; TileMap *node; diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index fb16c59dc9..2311439728 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -257,7 +257,7 @@ void TileSetEditor::_bind_methods() { } void TileSetEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons")); tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons")); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index d15a37a19c..4dbd9d500e 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -56,6 +56,12 @@ void ProjectExportDialog::_notification(int p_what) { case NOTIFICATION_POPUP_HIDE: { EditorSettings::get_singleton()->set("interface/dialogs/export_bounds", get_rect()); } break; + case NOTIFICATION_THEME_CHANGED: { + delete_preset->set_icon(get_icon("Remove", "EditorIcons")); + Control *panel = custom_feature_display->get_parent_control(); + if (panel) + panel->add_style_override("panel", get_stylebox("bg", "Tree")); + } break; } } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 096d9c1a90..8080a04a67 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -110,6 +110,14 @@ void ProjectSettingsEditor::_notification(int p_what) { EditorSettings::get_singleton()->set("interface/dialogs/project_settings_bounds", get_rect()); } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + + search_button->set_icon(get_icon("Search", "EditorIcons")); + clear_button->set_icon(get_icon("Close", "EditorIcons")); + action_add_error->add_color_override("font_color", get_color("error_color", "Editor")); + popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY), get_icon("Keyboard", "EditorIcons")); + popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_BUTTON), get_icon("JoyButton", "EditorIcons")); + popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_MOTION), get_icon("JoyAxis", "EditorIcons")); + popup_add->set_item_icon(popup_add->get_item_index(INPUT_MOUSE_BUTTON), get_icon("Mouse", "EditorIcons")); _update_actions(); } break; } diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 8f3113c816..e38347a653 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -550,6 +550,10 @@ void SceneTreeEditor::_notification(int p_what) { get_tree()->disconnect("node_configuration_warning_changed", this, "_warning_changed"); EditorSettings::get_singleton()->disconnect("settings_changed", this, "_editor_settings_changed"); } + if (p_what == NOTIFICATION_THEME_CHANGED) { + + _update_tree(); + } } TreeItem *SceneTreeEditor::_find(TreeItem *p_node, const NodePath &p_path) { diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index b893b098ac..892d854315 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -41,10 +41,12 @@ void ScriptCreateDialog::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_ENTER_TREE: { path_button->set_icon(get_icon("Folder", "EditorIcons")); parent_browse_button->set_icon(get_icon("Folder", "EditorIcons")); - } + status_panel->add_style_override("panel", get_stylebox("bg", "Tree")); + } break; } } @@ -609,10 +611,10 @@ ScriptCreateDialog::ScriptCreateDialog() { hb->add_child(path_error_label); vb->add_child(hb); - PanelContainer *pc = memnew(PanelContainer); - pc->set_h_size_flags(Control::SIZE_FILL); - pc->add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("bg", "Tree")); - pc->add_child(vb); + status_panel = memnew(PanelContainer); + status_panel->set_h_size_flags(Control::SIZE_FILL); + status_panel->add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("bg", "Tree")); + status_panel->add_child(vb); /* Margins */ @@ -631,7 +633,7 @@ ScriptCreateDialog::ScriptCreateDialog() { vb->add_child(empty_h->duplicate()); vb->add_child(gc); vb->add_child(empty_h->duplicate()); - vb->add_child(pc); + vb->add_child(status_panel); vb->add_child(empty_h->duplicate()); hb = memnew(HBoxContainer); hb->add_child(empty_v->duplicate()); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 99e5bc9e6a..1ad4a1b7a1 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -46,6 +46,7 @@ class ScriptCreateDialog : public ConfirmationDialog { LineEdit *class_name; Label *error_label; Label *path_error_label; + PanelContainer *status_panel; LineEdit *parent_name; Button *parent_browse_button; OptionButton *language_menu; diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 7fa3ed34f0..e9529eb1c0 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1160,6 +1160,16 @@ void ScriptEditorDebugger::_notification(int p_what) { inspect_scene_tree->add_color_override("relationship_line_color", rl_color); } else inspect_scene_tree->add_constant_override("draw_relationship_lines", 0); + + copy->set_icon(get_icon("ActionCopy", "EditorIcons")); + step->set_icon(get_icon("DebugStep", "EditorIcons")); + next->set_icon(get_icon("DebugNext", "EditorIcons")); + back->set_icon(get_icon("Back", "EditorIcons")); + forward->set_icon(get_icon("Forward", "EditorIcons")); + dobreak->set_icon(get_icon("Pause", "EditorIcons")); + docontinue->set_icon(get_icon("DebugContinue", "EditorIcons")); + vmem_refresh->set_icon(get_icon("Reload", "EditorIcons")); + } break; } } diff --git a/misc/dist/html/default.html b/misc/dist/html/default.html index a1a4e89d02..4e3515a7b6 100644 --- a/misc/dist/html/default.html +++ b/misc/dist/html/default.html @@ -244,9 +244,6 @@ $GODOT_HEAD_INCLUDE var statusMode = 'hidden'; var indeterminiateStatusAnimationId = 0; - setStatusMode('indeterminate'); - engine.setCanvas(canvas); - function setStatusMode(mode) { if (statusMode === mode || !initializing) @@ -367,18 +364,27 @@ $GODOT_HEAD_INCLUDE }); } - engine.startGame(BASENAME + '.pck').then(() => { - setStatusMode('hidden'); - initializing = false; - }, err => { + function displayFailureNotice(err) { + var msg = err.message || err; if (DEBUG_ENABLED) { - printError(err.message); - console.warn(err); + printError(msg); } - setStatusNotice(err.message); + console.error(msg); + setStatusNotice(msg); setStatusMode('notice'); initializing = false; - }); + }; + + if (!Engine.isWebGLAvailable()) { + displayFailureNotice("WebGL not available"); + } else { + setStatusMode('indeterminate'); + engine.setCanvas(canvas); + engine.startGame(BASENAME + '.pck').then(() => { + setStatusMode('hidden'); + initializing = false; + }, displayFailureNotice); + } })(); //]]></script> </body> diff --git a/misc/dist/linux/godot.desktop b/misc/dist/linux/godot.desktop index 545c491256..974352b117 100644 --- a/misc/dist/linux/godot.desktop +++ b/misc/dist/linux/godot.desktop @@ -2,7 +2,7 @@ Name=Godot Engine GenericName=Libre game engine Comment=Multi-platform 2D and 3D game engine with a feature rich editor -Exec=godot -pm +Exec=godot -p Icon=godot Terminal=false Type=Application diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 4a0c7499b4..6246a295ec 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -89,7 +89,9 @@ BulletPhysicsServer::BulletPhysicsServer() : active(true), active_spaces_count(0) {} -BulletPhysicsServer::~BulletPhysicsServer() {} +BulletPhysicsServer::~BulletPhysicsServer() { + bulletdelete(emptyShape); +} RID BulletPhysicsServer::shape_create(ShapeType p_shape) { ShapeBullet *shape = NULL; diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml index 5f94353840..7bee63019b 100644 --- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml +++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml @@ -32,7 +32,7 @@ <argument index="3" name="out_bandwidth" type="int" default="0"> </argument> <description> - Create client that connects to a server at address [code]ip[/code] using specified [code]port[/code]. The given IP needs to be in IPv4 or IPv6 address format, for example: [code]192.168.1.1[/code]. The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. + Create client that connects to a server at address [code]ip[/code] using specified [code]port[/code]. The given IP needs to be in IPv4 or IPv6 address format, for example: [code]192.168.1.1[/code]. The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [code]OK[/code] if a client was created, [code]ERR_ALREADY_IN_USE[/code] if this NetworkedMultiplayerEnet instance already has an open connection (in which case you need to call [method close_connection] first) or [code]ERR_CANT_CREATE[/code] if the client could not be created. </description> </method> <method name="create_server"> @@ -47,7 +47,7 @@ <argument index="3" name="out_bandwidth" type="int" default="0"> </argument> <description> - Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]*[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4096 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. + Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]*[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4096 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [code]OK[/code] if a server was created, [code]ERR_ALREADY_IN_USE[/code] if this NetworkedMultiplayerEnet instance already has an open connection (in which case you need to call [method close_connection] first) or [code]ERR_CANT_CREATE[/code] if the server could not be created. </description> </method> <method name="set_bind_ip"> diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index e91c1ebd85..869492232c 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -1269,9 +1269,10 @@ GridMapEditor::~GridMapEditor() { VisualServer::get_singleton()->free(grid_instance[i]); if (cursor_instance.is_valid()) VisualServer::get_singleton()->free(cursor_instance); - if (selection_level_instance[i].is_valid()) { + if (selection_level_instance[i].is_valid()) VisualServer::get_singleton()->free(selection_level_instance[i]); - } + if (selection_level_mesh[i].is_valid()) + VisualServer::get_singleton()->free(selection_level_mesh[i]); } VisualServer::get_singleton()->free(selection_mesh); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 315c1e2f1c..a210b8e480 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -103,7 +103,7 @@ #define C_METHOD_MANAGED_TO_DICT C_NS_MONOMARSHAL "::mono_object_to_Dictionary" #define C_METHOD_MANAGED_FROM_DICT C_NS_MONOMARSHAL "::Dictionary_to_mono_object" -#define BINDINGS_GENERATOR_VERSION UINT32_C(1) +#define BINDINGS_GENERATOR_VERSION UINT32_C(2) const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n"; @@ -730,7 +730,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } output.push_back(INDENT1 "public "); - output.push_back(itype.is_singleton ? "static class " : "class "); + bool is_abstract = !ClassDB::can_instance(itype.name) && ClassDB::is_class_enabled(itype.name); // can_instance returns true if there's a constructor and the class is not 'disabled' + output.push_back(itype.is_singleton ? "static class " : (is_abstract ? "abstract class " : "class ")); output.push_back(itype.proxy_name); if (itype.is_singleton) { diff --git a/modules/mono/glue/cs_files/StringExtensions.cs b/modules/mono/glue/cs_files/StringExtensions.cs index 5c3ceff97d..cbc337ab19 100644 --- a/modules/mono/glue/cs_files/StringExtensions.cs +++ b/modules/mono/glue/cs_files/StringExtensions.cs @@ -287,7 +287,7 @@ namespace Godot if (sep == -1) return @base; - return @base + rs.substr(0, sep); + return @base + rs.Substr(0, sep); } // <summary> @@ -478,7 +478,7 @@ namespace Godot // </summary> public static bool IsValidIpAddress(this string instance) { - string[] ip = instance.split("."); + string[] ip = instance.Split("."); if (ip.Length != 4) return false; @@ -489,7 +489,7 @@ namespace Godot if (!n.IsValidInteger()) return false; - int val = n.to_int(); + int val = n.ToInt(); if (val < 0 || val > 255) return false; } @@ -571,7 +571,7 @@ namespace Godot // <summary> // Do a simple case insensitive expression match, using ? and * wildcards (see [method expr_match]). // </summary> - public static bool matchn(this string instance, string expr) + public static bool Matchn(this string instance, string expr) { return instance.ExprMatch(expr, false); } @@ -830,7 +830,7 @@ namespace Godot // <summary> // Split the string by a divisor string, return an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". // </summary> - public static string[] split(this string instance, string divisor, bool allow_empty = true) + public static string[] Split(this string instance, string divisor, bool allow_empty = true) { return instance.Split(new string[] { divisor }, StringSplitOptions.RemoveEmptyEntries); } @@ -838,7 +838,7 @@ namespace Godot // <summary> // Split the string in floats by using a divisor string, return an array of the substrings. Example "1,2.5,3" will return [1,2.5,3] if split by ",". // </summary> - public static float[] split_floats(this string instance, string divisor, bool allow_empty = true) + public static float[] SplitFloats(this string instance, string divisor, bool allow_empty = true) { List<float> ret = new List<float>(); int from = 0; @@ -872,7 +872,7 @@ namespace Godot // <summary> // Return a copy of the string stripped of any non-printable character at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively. // </summary> - public static string strip_edges(this string instance, bool left = true, bool right = true) + public static string StripEdges(this string instance, bool left = true, bool right = true) { if (left) { @@ -890,7 +890,7 @@ namespace Godot // <summary> // Return part of the string from the position [code]from[/code], with length [code]len[/code]. // </summary> - public static string substr(this string instance, int from, int len) + public static string Substr(this string instance, int from, int len) { return instance.Substring(from, len); } @@ -898,7 +898,7 @@ namespace Godot // <summary> // Convert the String (which is a character array) to PoolByteArray (which is an array of bytes). The conversion is speeded up in comparison to to_utf8() with the assumption that all the characters the String contains are only ASCII characters. // </summary> - public static byte[] to_ascii(this string instance) + public static byte[] ToAscii(this string instance) { return Encoding.ASCII.GetBytes(instance); } @@ -906,7 +906,7 @@ namespace Godot // <summary> // Convert a string, containing a decimal number, into a [code]float[/code]. // </summary> - public static float to_float(this string instance) + public static float ToFloat(this string instance) { return float.Parse(instance); } @@ -914,7 +914,7 @@ namespace Godot // <summary> // Convert a string, containing an integer number, into an [code]int[/code]. // </summary> - public static int to_int(this string instance) + public static int ToInt(this string instance) { return int.Parse(instance); } @@ -922,7 +922,7 @@ namespace Godot // <summary> // Return the string converted to lowercase. // </summary> - public static string to_lower(this string instance) + public static string ToLower(this string instance) { return instance.ToLower(); } @@ -930,7 +930,7 @@ namespace Godot // <summary> // Return the string converted to uppercase. // </summary> - public static string to_upper(this string instance) + public static string ToUpper(this string instance) { return instance.ToUpper(); } @@ -938,7 +938,7 @@ namespace Godot // <summary> // Convert the String (which is an array of characters) to PoolByteArray (which is an array of bytes). The conversion is a bit slower than to_ascii(), but supports all UTF-8 characters. Therefore, you should prefer this function over to_ascii(). // </summary> - public static byte[] to_utf8(this string instance) + public static byte[] ToUtf8(this string instance) { return Encoding.UTF8.GetBytes(instance); } @@ -946,7 +946,7 @@ namespace Godot // <summary> // Return a copy of the string with special characters escaped using the XML standard. // </summary> - public static string xml_escape(this string instance) + public static string XmlEscape(this string instance) { return SecurityElement.Escape(instance); } @@ -954,7 +954,7 @@ namespace Godot // <summary> // Return a copy of the string with escaped characters replaced by their meanings according to the XML standard. // </summary> - public static string xml_unescape(this string instance) + public static string XmlUnescape(this string instance) { return SecurityElement.FromString(instance).Text; } diff --git a/modules/mono/glue/cs_files/Transform.cs b/modules/mono/glue/cs_files/Transform.cs index 5214100d36..9853721f98 100644 --- a/modules/mono/glue/cs_files/Transform.cs +++ b/modules/mono/glue/cs_files/Transform.cs @@ -24,7 +24,7 @@ namespace Godot public Transform LookingAt(Vector3 target, Vector3 up) { Transform t = this; - t.set_look_at(origin, target, up); + t.SetLookAt(origin, target, up); return t; } @@ -43,7 +43,7 @@ namespace Godot return new Transform(basis.Scaled(scale), origin * scale); } - public void set_look_at(Vector3 eye, Vector3 target, Vector3 up) + public void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) { // Make rotation matrix // Z vector diff --git a/modules/mono/glue/cs_files/VERSION.txt b/modules/mono/glue/cs_files/VERSION.txt index d00491fd7e..0cfbf08886 100755 --- a/modules/mono/glue/cs_files/VERSION.txt +++ b/modules/mono/glue/cs_files/VERSION.txt @@ -1 +1 @@ -1 +2 diff --git a/platform/javascript/engine.js b/platform/javascript/engine.js index bca1851f40..8f22e41660 100644 --- a/platform/javascript/engine.js +++ b/platform/javascript/engine.js @@ -138,18 +138,6 @@ } var actualCanvas = this.rtenv.canvas; - var testContext = false; - var testCanvas; - try { - testCanvas = document.createElement('canvas'); - testContext = testCanvas.getContext('webgl2') || testCanvas.getContext('experimental-webgl2'); - } catch (e) {} - if (!testContext) { - throw new Error("WebGL 2 not available"); - } - testCanvas = null; - testContext = null; - // canvas can grab focus on click if (actualCanvas.tabIndex < 0) { actualCanvas.tabIndex = 0; @@ -273,6 +261,20 @@ Engine.RuntimeEnvironment = engine.RuntimeEnvironment; + Engine.isWebGLAvailable = function(majorVersion = 1) { + + var testContext = false; + try { + var testCanvas = document.createElement('canvas'); + if (majorVersion === 1) { + testContext = testCanvas.getContext('webgl') || testCanvas.getContet('experimental-webgl'); + } else if (majorVersion === 2) { + testContext = testCanvas.getContext('webgl2') || testCanvas.getContet('experimental-webgl2'); + } + } catch (e) {} + return !!testContext; + }; + Engine.load = function(newBasePath) { if (newBasePath !== undefined) basePath = getBasePath(newBasePath); diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index ace0bdad60..cbfe99ba2d 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -444,6 +444,7 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, break; } EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(NULL, &attributes); + ERR_EXPLAIN("WebGL " + itos(attributes.majorVersion) + ".0 not available"); ERR_FAIL_COND_V(emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS, ERR_UNAVAILABLE); video_mode = p_desired; diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index f2c5c5d42e..3ee195e4f9 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -25,8 +25,11 @@ def can_build(): def get_opts(): + from SCons.Variables import BoolVariable return [ + ('msvc_version', 'MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.', None), + BoolVariable('use_mingw', 'Use the Mingw compiler, even if MSVC is installed. Only used on Windows.', False), ] diff --git a/platform/windows/detect.py b/platform/windows/detect.py index b8ee2cd19f..3cf1482a65 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -12,23 +12,17 @@ def get_name(): def can_build(): - if (os.name == "nt"): # Building natively on Windows - if (os.getenv("VCINSTALLDIR")): # MSVC + # If VCINSTALLDIR is set in the OS environ, use traditional Godot logic to set up MSVC + if (os.getenv("VCINSTALLDIR")): # MSVC, manual setup return True - print("MSVC not detected (no VCINSTALLDIR environment variable), attempting MinGW.") - mingw32 = "" - mingw64 = "" - if (os.getenv("MINGW32_PREFIX")): - mingw32 = os.getenv("MINGW32_PREFIX") - if (os.getenv("MINGW64_PREFIX")): - mingw64 = os.getenv("MINGW64_PREFIX") - - test = "gcc --version > NUL 2>&1" - if (os.system(test) == 0 or os.system(mingw32 + test) == 0 or os.system(mingw64 + test) == 0): - return True + # Otherwise, let SCons find MSVC if installed, or else Mingw. + # Since we're just returning True here, if there's no compiler + # installed, we'll get errors when it tries to build with the + # null compiler. + return True if (os.name == "posix"): # Cross-compiling with MinGW-w64 (old MinGW32 is not supported) @@ -70,6 +64,8 @@ def get_opts(): ('target_win_version', 'Targeted Windows version, >= 0x0601 (Windows 7)', '0x0601'), EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')), BoolVariable('separate_debug_symbols', 'Create a separate file with the debug symbols', False), + ('msvc_version', 'MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.', None), + BoolVariable('use_mingw', 'Use the Mingw compiler, even if MSVC is installed. Only used on Windows.', False), ] @@ -98,192 +94,252 @@ def build_res_file(target, source, env): return 0 -def configure(env): - - env.Append(CPPPATH=['#platform/windows']) - - if (os.name == "nt" and os.getenv("VCINSTALLDIR")): # MSVC - - env['ENV']['TMP'] = os.environ['TMP'] - - ## Build type - - if (env["target"] == "release"): - env.Append(CCFLAGS=['/O2']) - env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) - env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) - - elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['/O2', '/DDEBUG_ENABLED']) - env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) - - elif (env["target"] == "debug_release"): - env.Append(CCFLAGS=['/Z7', '/Od']) - env.Append(LINKFLAGS=['/DEBUG']) - env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) - env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) - - elif (env["target"] == "debug"): - env.Append(CCFLAGS=['/Z7', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED', '/DD3D_DEBUG_INFO', '/Od', '/EHsc']) - env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) - env.Append(LINKFLAGS=['/DEBUG']) - - ## Architecture - - # Note: this detection/override code from here onward should be here instead of in SConstruct because it's platform and compiler specific (MSVC/Windows) - if (env["bits"] != "default"): - print("Error: bits argument is disabled for MSVC") - print(""" - Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console - (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits - argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you. - """) - sys.exit() - - # Forcing bits argument because MSVC does not have a flag to set this through SCons... it's different compilers (cl.exe's) called from the proper command prompt - # that decide the architecture that is build for. Scons can only detect the os.getenviron (because vsvarsall.bat sets a lot of stuff for cl.exe to work with) - env["bits"] = "32" - env["x86_libtheora_opt_vc"] = True - - ## Compiler configuration +def setup_msvc_manual(env): + """Set up env to use MSVC manually, using VCINSTALLDIR""" + if (env["bits"] != "default"): + print(""" + Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console + (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits + argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you. + """) + raise SCons.Errors.UserError("Bits argument should not be used when using VCINSTALLDIR") + + # Force bits arg + # (Actually msys2 mingw can support 64-bit, we could detect that) + env["bits"] = "32" + env["x86_libtheora_opt_vc"] = True + + # find compiler manually + compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV']) + print("Found MSVC compiler: " + compiler_version_str) + + # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writing)... vc compiler for 64bit can not compile _asm + if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"): + env["bits"] = "64" + env["x86_libtheora_opt_vc"] = False + print("Compiled program architecture will be a 64 bit executable (forcing bits=64).") + elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"): + print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).") + else: + print("Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR.") + +def setup_msvc_auto(env): + """Set up MSVC using SCons's auto-detection logic""" + + # If MSVC_VERSION is set by SCons, we know MSVC is installed. + # But we may want a different version or target arch. + + # The env may have already been set up with default MSVC tools, so + # reset a few things so we can set it up with the tools we want. + # (Ideally we'd decide on the tool config before configuring any + # environment, and just set the env up once, but this function runs + # on an existing env so this is the simplest way.) + env['MSVC_SETUP_RUN'] = False # Need to set this to re-run the tool + env['MSVS_VERSION'] = None + env['MSVC_VERSION'] = None + env['TARGET_ARCH'] = None + if env['bits'] != 'default': + env['TARGET_ARCH'] = {'32': 'x86', '64': 'x86_64'}[env['bits']] + if env.has_key('msvc_version'): + env['MSVC_VERSION'] = env['msvc_version'] + env.Tool('msvc') + env.Tool('mssdk') # we want the MS SDK + # Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015 + # Get actual target arch into bits (it may be "default" at this point): + if env['TARGET_ARCH'] in ('amd64', 'x86_64'): + env['bits'] = 64 + else: + env['bits'] = 32 + print(" Found MSVC version %s, arch %s, bits=%s" % (env['MSVC_VERSION'], env['TARGET_ARCH'], env['bits'])) + if env['TARGET_ARCH'] in ('amd64', 'x86_64'): + env["x86_libtheora_opt_vc"] = False + +def setup_mingw(env): + """Set up env for use with mingw""" + # Nothing to do here + print("Using Mingw") + pass + +def configure_msvc(env, manual_msvc_config): + """Configure env to work with MSVC""" + + # Build type + + if (env["target"] == "release"): + env.Append(CCFLAGS=['/O2']) + env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) + env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) + + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['/O2']) + env.AppendUnique(CPPDEFINES = ['DEBUG_ENABLED']) + env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + + elif (env["target"] == "debug_release"): + env.Append(CCFLAGS=['/Z7', '/Od']) + env.Append(LINKFLAGS=['/DEBUG']) + env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) + env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) + + elif (env["target"] == "debug"): + env.AppendUnique(CCFLAGS=['/Z7', '/Od', '/EHsc']) + env.AppendUnique(CPPDEFINES = ['DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED', + 'D3D_DEBUG_INFO']) + env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + env.Append(LINKFLAGS=['/DEBUG']) + + ## Compile/link flags + + env.AppendUnique(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo']) + env.AppendUnique(CXXFLAGS=['/TP']) # assume all sources are C++ + if manual_msvc_config: # should be automatic if SCons found it + env.Append(CPPPATH=[os.getenv("WindowsSdkDir") + "/Include"]) + + env.AppendUnique(CPPDEFINES = ['WINDOWS_ENABLED', 'OPENGL_ENABLED', + 'RTAUDIO_ENABLED', 'WASAPI_ENABLED', + 'TYPED_METHOD_BIND', 'WIN32', 'MSVC', + {'WINVER' : '$target_win_version', + '_WIN32_WINNT': '$target_win_version'}]) + if env["bits"] == "64": + env.AppendUnique(CPPDEFINES=['_WIN64']) + + ## Libs + + LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', + 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32', + 'shell32', 'advapi32', 'dinput8', 'dxguid', 'imm32', 'bcrypt'] + env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) + + if manual_msvc_config: + env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"]) - env['ENV'] = os.environ - # This detection function needs the tools env (that is env['ENV'], not SCons's env), and that is why it's this far below in the code - compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV']) + ## LTO - print("Detected MSVC compiler: " + compiler_version_str) - # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writing)... vc compiler for 64bit can not compile _asm - if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"): - env["bits"] = "64" - env["x86_libtheora_opt_vc"] = False - print("Compiled program architecture will be a 64 bit executable (forcing bits=64).") - elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"): - print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).") + if (env["use_lto"]): + env.AppendUnique(CCFLAGS=['/GL']) + env.AppendUnique(ARFLAGS=['/LTCG']) + if env["progress"]: + env.AppendUnique(LINKFLAGS=['/LTCG:STATUS']) else: - print("Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup.") + env.AppendUnique(LINKFLAGS=['/LTCG']) - ## Compile flags + if manual_msvc_config: + env.Append(CPPPATH=[p for p in os.getenv("INCLUDE").split(";")]) + env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) - env.Append(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo']) - env.Append(CXXFLAGS=['/TP']) - env.Append(CPPFLAGS=['/DMSVC', '/GR', ]) - env.Append(CCFLAGS=['/I' + os.getenv("WindowsSdkDir") + "/Include"]) + # Incremental linking fix + env['BUILDERS']['ProgramOriginal'] = env['BUILDERS']['Program'] + env['BUILDERS']['Program'] = methods.precious_program - env.Append(CCFLAGS=['/DWINDOWS_ENABLED']) - env.Append(CCFLAGS=['/DOPENGL_ENABLED']) - env.Append(CCFLAGS=['/DRTAUDIO_ENABLED']) - env.Append(CCFLAGS=['/DWASAPI_ENABLED']) - env.Append(CCFLAGS=['/DTYPED_METHOD_BIND']) - env.Append(CCFLAGS=['/DWIN32']) - env.Append(CCFLAGS=['/DWINVER=%s' % env['target_win_version'], '/D_WIN32_WINNT=%s' % env['target_win_version']]) - if env["bits"] == "64": - env.Append(CCFLAGS=['/D_WIN64']) +def configure_mingw(env): + # Workaround for MinGW. See: + # http://www.scons.org/wiki/LongCmdLinesOnWin32 + env.use_windows_spawn_fix() - LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32', 'shell32', 'advapi32', 'dinput8', 'dxguid', 'imm32', 'bcrypt'] - env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) + ## Build type - env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"]) + if (env["target"] == "release"): + env.Append(CCFLAGS=['-msse2']) - if (os.getenv("VCINSTALLDIR")): - VC_PATH = os.getenv("VCINSTALLDIR") + if (env["bits"] == "64"): + env.Append(CCFLAGS=['-O3']) else: - VC_PATH = "" - - if (env["use_lto"]): - env.Append(CCFLAGS=['/GL']) - env.Append(ARFLAGS=['/LTCG']) - if env["progress"]: - env.Append(LINKFLAGS=['/LTCG:STATUS']) - else: - env.Append(LINKFLAGS=['/LTCG']) - - env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")]) - env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) - - # Incremental linking fix - env['BUILDERS']['ProgramOriginal'] = env['BUILDERS']['Program'] - env['BUILDERS']['Program'] = methods.precious_program - - else: # MinGW + env.Append(CCFLAGS=['-O2']) - # Workaround for MinGW. See: - # http://www.scons.org/wiki/LongCmdLinesOnWin32 - env.use_windows_spawn_fix() + env.Append(LINKFLAGS=['-Wl,--subsystem,windows']) - ## Build type + if (env["debug_symbols"] == "yes"): + env.Prepend(CCFLAGS=['-g1']) + if (env["debug_symbols"] == "full"): + env.Prepend(CCFLAGS=['-g2']) - if (env["target"] == "release"): - env.Append(CCFLAGS=['-msse2']) + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + if (env["debug_symbols"] == "yes"): + env.Prepend(CCFLAGS=['-g1']) + if (env["debug_symbols"] == "full"): + env.Prepend(CCFLAGS=['-g2']) - if (env["bits"] == "64"): - env.Append(CCFLAGS=['-O3']) - else: - env.Append(CCFLAGS=['-O2']) + elif (env["target"] == "debug"): + env.Append(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) - env.Append(LINKFLAGS=['-Wl,--subsystem,windows']) + ## Compiler configuration - if (env["debug_symbols"] == "yes"): - env.Prepend(CCFLAGS=['-g1']) - if (env["debug_symbols"] == "full"): - env.Prepend(CCFLAGS=['-g2']) + if (os.name == "nt"): + env['ENV']['TMP'] = os.environ['TMP'] # way to go scons, you can be so stupid sometimes + else: + env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation - elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) - if (env["debug_symbols"] == "yes"): - env.Prepend(CCFLAGS=['-g1']) - if (env["debug_symbols"] == "full"): - env.Prepend(CCFLAGS=['-g2']) + if (env["bits"] == "default"): + if (os.name == "nt"): + env["bits"] = "64" if "PROGRAMFILES(X86)" in os.environ else "32" + else: # default to 64-bit on Linux + env["bits"] = "64" - elif (env["target"] == "debug"): - env.Append(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + mingw_prefix = "" - ## Compiler configuration + if (env["bits"] == "32"): + env.Append(LINKFLAGS=['-static']) + env.Append(LINKFLAGS=['-static-libgcc']) + env.Append(LINKFLAGS=['-static-libstdc++']) + mingw_prefix = env["mingw_prefix_32"] + else: + env.Append(LINKFLAGS=['-static']) + mingw_prefix = env["mingw_prefix_64"] - if (os.name == "nt"): - env['ENV']['TMP'] = os.environ['TMP'] # way to go scons, you can be so stupid sometimes - else: - env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation + env["CC"] = mingw_prefix + "gcc" + env['AS'] = mingw_prefix + "as" + env['CXX'] = mingw_prefix + "g++" + env['AR'] = mingw_prefix + "gcc-ar" + env['RANLIB'] = mingw_prefix + "gcc-ranlib" + env['LINK'] = mingw_prefix + "g++" + env["x86_libtheora_opt_gcc"] = True - if (env["bits"] == "default"): - if (os.name == "nt"): - env["bits"] = "64" if "PROGRAMFILES(X86)" in os.environ else "32" - else: # default to 64-bit on Linux - env["bits"] = "64" + if env['use_lto']: + env.Append(CCFLAGS=['-flto']) + env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))]) - mingw_prefix = "" - if (env["bits"] == "32"): - env.Append(LINKFLAGS=['-static']) - env.Append(LINKFLAGS=['-static-libgcc']) - env.Append(LINKFLAGS=['-static-libstdc++']) - mingw_prefix = env["mingw_prefix_32"] - else: - env.Append(LINKFLAGS=['-static']) - mingw_prefix = env["mingw_prefix_64"] + ## Compile flags - env["CC"] = mingw_prefix + "gcc" - env['AS'] = mingw_prefix + "as" - env['CXX'] = mingw_prefix + "g++" - env['AR'] = mingw_prefix + "gcc-ar" - env['RANLIB'] = mingw_prefix + "gcc-ranlib" - env['LINK'] = mingw_prefix + "g++" - env["x86_libtheora_opt_gcc"] = True + env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows']) + env.Append(CCFLAGS=['-DOPENGL_ENABLED']) + env.Append(CCFLAGS=['-DRTAUDIO_ENABLED']) + env.Append(CCFLAGS=['-DWASAPI_ENABLED']) + env.Append(CCFLAGS=['-DWINVER=%s' % env['target_win_version'], '-D_WIN32_WINNT=%s' % env['target_win_version']]) + env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt']) - if env['use_lto']: - env.Append(CCFLAGS=['-flto']) - env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))]) + env.Append(CPPFLAGS=['-DMINGW_ENABLED']) + # resrc + env.Append(BUILDERS={'RES': env.Builder(action=build_res_file, suffix='.o', src_suffix='.rc')}) - ## Compile flags +def configure(env): + # At this point the env has been set up with basic tools/compilers. + env.Append(CPPPATH=['#platform/windows']) - env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows']) - env.Append(CCFLAGS=['-DOPENGL_ENABLED']) - env.Append(CCFLAGS=['-DRTAUDIO_ENABLED']) - env.Append(CCFLAGS=['-DWASAPI_ENABLED']) - env.Append(CCFLAGS=['-DWINVER=%s' % env['target_win_version'], '-D_WIN32_WINNT=%s' % env['target_win_version']]) - env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt']) + print("Configuring for Windows: target=%s, bits=%s" % (env['target'], env['bits'])) + + env['ENV'] = os.environ # this makes build less repeatable, but simplifies some things + env['ENV']['TMP'] = os.environ['TMP'] + + # First figure out which compiler, version, and target arch we're using + if os.getenv("VCINSTALLDIR"): + # Manual setup of MSVC + setup_msvc_manual(env) + env.msvc = True + manual_msvc_config = True + elif env.get('MSVC_VERSION', ''): + setup_msvc_auto(env) + env.msvc = True + manual_msvc_config = False + else: + setup_mingw(env) + env.msvc = False - env.Append(CPPFLAGS=['-DMINGW_ENABLED']) + # Now set compiler/linker flags + if env.msvc: + configure_msvc(env, manual_msvc_config) - # resrc - env.Append(BUILDERS={'RES': env.Builder(action=build_res_file, suffix='.o', src_suffix='.rc')}) + else: # MinGW + configure_mingw(env) diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 978fb379ac..7e2026d225 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -175,7 +175,8 @@ void CollisionPolygon2D::_notification(int p_what) { Vector2 p = polygon[i]; Vector2 n = polygon[(i + 1) % polygon.size()]; - draw_line(p, n, Color(0.9, 0.2, 0.0, 0.8), 3); + // draw line with width <= 1, so it does not scale with zoom and break pixel exact editing + draw_line(p, n, Color(0.9, 0.2, 0.0, 0.8), 1); } #define DEBUG_DECOMPOSE #if defined(TOOLS_ENABLED) && defined(DEBUG_DECOMPOSE) diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 3af77bfcc7..b602839b99 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -834,6 +834,16 @@ void TileMap::update_dirty_bitmask() { } } +void TileMap::fix_invalid_tiles() { + + for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) { + + if (!tile_set->has_tile(get_cell(E->key().x, E->key().y))) { + set_cell(E->key().x, E->key().y, INVALID_CELL); + } + } +} + int TileMap::get_cell(int p_x, int p_y) const { PosKey pk(p_x, p_y); @@ -1519,6 +1529,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("is_cell_y_flipped", "x", "y"), &TileMap::is_cell_y_flipped); ClassDB::bind_method(D_METHOD("is_cell_transposed", "x", "y"), &TileMap::is_cell_transposed); + ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles); ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear); ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMap::get_used_cells); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 104842d52f..587bd3b684 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -310,6 +310,7 @@ public: void set_clip_uv(bool p_enable); bool get_clip_uv() const; + void fix_invalid_tiles(); void clear(); TileMap(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 50041ffd89..cc17e6bcd8 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -295,35 +295,21 @@ int ItemList::get_current() const { return current; } -void ItemList::move_item(int p_item, int p_to_pos) { +void ItemList::move_item(int p_from_idx, int p_to_idx) { - ERR_FAIL_INDEX(p_item, items.size()); - ERR_FAIL_INDEX(p_to_pos, items.size() + 1); + ERR_FAIL_INDEX(p_from_idx, items.size()); + ERR_FAIL_INDEX(p_to_idx, items.size()); - Item it = items[p_item]; - items.remove(p_item); - - if (p_to_pos > p_item) { - p_to_pos--; - } - - if (p_to_pos >= items.size()) { - items.push_back(it); - } else { - items.insert(p_to_pos, it); + if (is_anything_selected() && get_selected_items()[0] == p_from_idx) { + current = p_to_idx; } - if (current < 0) { - //do none - } else if (p_item == current) { - current = p_to_pos; - } else if (p_to_pos > p_item && current > p_item && current < p_to_pos) { - current--; - } else if (p_to_pos < p_item && current < p_item && current > p_to_pos) { - current++; - } + Item item = items[p_from_idx]; + items.remove(p_from_idx); + items.insert(p_to_idx, item); update(); + shape_changed = true; } int ItemList::get_item_count() const { @@ -1423,9 +1409,13 @@ void ItemList::_bind_methods() { ClassDB::bind_method(D_METHOD("select", "idx", "single"), &ItemList::select, DEFVAL(true)); ClassDB::bind_method(D_METHOD("unselect", "idx"), &ItemList::unselect); + ClassDB::bind_method(D_METHOD("unselect_all"), &ItemList::unselect_all); + ClassDB::bind_method(D_METHOD("is_selected", "idx"), &ItemList::is_selected); ClassDB::bind_method(D_METHOD("get_selected_items"), &ItemList::get_selected_items); + ClassDB::bind_method(D_METHOD("move_item", "p_from_idx", "p_to_idx"), &ItemList::move_item); + ClassDB::bind_method(D_METHOD("get_item_count"), &ItemList::get_item_count); ClassDB::bind_method(D_METHOD("remove_item", "idx"), &ItemList::remove_item); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 7f34a250bd..0fa0dd415b 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -169,7 +169,7 @@ public: void set_current(int p_current); int get_current() const; - void move_item(int p_item, int p_to_pos); + void move_item(int p_from_idx, int p_to_idx); int get_item_count() const; void remove_item(int p_idx); diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 23c6dc200b..26e29b3ccb 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -80,6 +80,14 @@ void DynamicFontData::set_force_autohinter(bool p_force) { void DynamicFontData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_font_path", "path"), &DynamicFontData::set_font_path); ClassDB::bind_method(D_METHOD("get_font_path"), &DynamicFontData::get_font_path); + ClassDB::bind_method(D_METHOD("set_hinting", "mode"), &DynamicFontData::set_hinting); + ClassDB::bind_method(D_METHOD("get_hinting"), &DynamicFontData::get_hinting); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting"); + + BIND_ENUM_CONSTANT(HINTING_NONE); + BIND_ENUM_CONSTANT(HINTING_LIGHT); + BIND_ENUM_CONSTANT(HINTING_NORMAL); ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_path", PROPERTY_HINT_FILE, "*.ttf,*.otf"), "set_font_path", "get_font_path"); } @@ -87,6 +95,7 @@ void DynamicFontData::_bind_methods() { DynamicFontData::DynamicFontData() { force_autohinter = false; + hinting = DynamicFontData::HINTING_NORMAL; font_mem = NULL; font_mem_size = 0; } @@ -212,8 +221,6 @@ Error DynamicFontAtSize::_load() { if (id.filter) texture_flags |= Texture::FLAG_FILTER; - //print_line("ASCENT: "+itos(ascent)+" descent "+itos(descent)+" hinted: "+itos(face->face_flags&FT_FACE_FLAG_HINTER)); - valid = true; return OK; } @@ -454,15 +461,28 @@ void DynamicFontAtSize::_update_char(CharType p_char) { char_map[p_char] = ch; return; } - int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); + + int ft_hinting; + + switch (font->hinting) { + case DynamicFontData::HINTING_NONE: + ft_hinting = FT_LOAD_NO_HINTING; + break; + case DynamicFontData::HINTING_LIGHT: + ft_hinting = FT_LOAD_TARGET_LIGHT; + break; + default: + ft_hinting = FT_LOAD_TARGET_NORMAL; + break; + } + + int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting); if (!error) { error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); } if (error) { int advance = 0; - //stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); - //print_line("char has no bitmap: "+itos(p_char)+" but advance is "+itos(advance*scale)); Character ch; ch.texture_idx = -1; ch.advance = advance; @@ -477,7 +497,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) { int w = slot->bitmap.width; int h = slot->bitmap.rows; - //int p = slot->bitmap.pitch; int yofs = slot->bitmap_top; int xofs = slot->bitmap_left; int advance = slot->advance.x >> 6; @@ -536,8 +555,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) { break; } - //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" X: "+itos(tex_x)+" Y: "+itos(tex_y)); - if (tex_index == -1) { //could not find texture to fit, create one tex_x = 0; @@ -645,8 +662,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) { chr.rect.position /= oversampling; chr.rect.size /= oversampling; - //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" RECT: "+chr.rect+" X OFS: "+itos(xofs)+" Y OFS: "+itos(yofs)); - char_map[p_char] = chr; } @@ -758,6 +773,18 @@ void DynamicFont::set_use_filter(bool p_enable) { _reload_cache(); } +DynamicFontData::Hinting DynamicFontData::get_hinting() const { + + return hinting; +} + +void DynamicFontData::set_hinting(Hinting p_hinting) { + + if (hinting == p_hinting) + return; + hinting = p_hinting; +} + int DynamicFont::get_spacing(int p_type) const { if (p_type == SPACING_TOP) { diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h index d8adf35b6b..db8bd87587 100644 --- a/scene/resources/dynamic_font.h +++ b/scene/resources/dynamic_font.h @@ -64,10 +64,20 @@ public: } }; + enum Hinting { + HINTING_NONE, + HINTING_LIGHT, + HINTING_NORMAL + }; + + Hinting get_hinting() const; + void set_hinting(Hinting p_hinting); + private: const uint8_t *font_mem; int font_mem_size; bool force_autohinter; + Hinting hinting; String font_path; Map<CacheID, DynamicFontAtSize *> size_cache; @@ -91,6 +101,8 @@ public: ~DynamicFontData(); }; +VARIANT_ENUM_CAST(DynamicFontData::Hinting); + class DynamicFontAtSize : public Reference { GDCLASS(DynamicFontAtSize, Reference) diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index aaac32a4f2..1bad7e652b 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -80,6 +80,7 @@ static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsag ShaderTypes *shader_types = NULL; PhysicsServer *_createGodotPhysicsCallback() { + WARN_PRINT("The GodotPhysics 3D physics engine is deprecated and will be removed in Godot 3.2. You should use the Bullet physics engine instead (configurable in your project settings)."); return memnew(PhysicsServerSW); } @@ -163,8 +164,8 @@ void register_server_types() { GLOBAL_DEF(PhysicsServerManager::setting_property_name, "DEFAULT"); ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServerManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServerManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT")); - PhysicsServerManager::register_server("GodotPhysics", &_createGodotPhysicsCallback); - PhysicsServerManager::set_default_server("GodotPhysics"); + PhysicsServerManager::register_server("GodotPhysics - deprecated", &_createGodotPhysicsCallback); + PhysicsServerManager::set_default_server("GodotPhysics - deprecated"); } void unregister_server_types() { |