diff options
115 files changed, 1501 insertions, 679 deletions
diff --git a/.clang-format b/.clang-format index 3a2c39a174..237fd9ce30 100644 --- a/.clang-format +++ b/.clang-format @@ -116,6 +116,7 @@ Standard: Cpp03 --- ### ObjC specific config ### Language: ObjC +Standard: Cpp03 ObjCBlockIndentWidth: 4 # ObjCSpaceAfterProperty: false # ObjCSpaceBeforeProtocolList: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a0310f904..b111eca07d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,251 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). +## [Unreleased] + +### Added + +- OpenGL ES 2.0 renderer. +- [Visual shader editor.](https://godotengine.org/article/visual-shader-editor-back) + - New PBR output nodes. + - Conversion between Vector3 and scalar types is now automatic. + - Ability to create custom nodes via scripting. + - Ports can now be previewed. +- [3D soft body physics.](https://godotengine.org/article/soft-body) +- [3D ragdoll system.](https://godotengine.org/article/godot-ragdoll-system) +- [Constructive solid geometry in 3D.](https://godotengine.org/article/godot-gets-csg-support) +- [2D meshes and skeletal deformation.](https://godotengine.org/article/godot-gets-2d-skeletal-deform) +- [Various improvements to KinematicBody2D.](https://godotengine.org/article/godot-31-will-get-many-improvements-kinematicbody) + - Support for snapping the body to the floor. + - Support for RayCast shapes in kinematic bodies. + - Support for synchronizing kinematic movement to physics, avoiding an one-frame delay. +- WebSockets support using [libwebsockets](https://libwebsockets.org/). +- [Revamped inspector.](https://godotengine.org/article/godot-gets-new-inspector) + - Improved visualization and editing of numeric properties. + - Vector and matrix types can now be edited directly (no pop-ups). + - Subresources can now be edited directly within the same inspector. + - Layer names can now be displayed in the inspector. + - Proper editing of arrays and dictionaries. + - Ability to reset any property to its default value. +- [Improved animation editor.](https://godotengine.org/article/godot-gets-brand-new-animation-editor-cinematic-support) + - Simpler, less cluttered layout. + - New Bezier, Audio and Animation tracks. + - Several key types can be previewed directly in the track editor. + - Tracks can now be grouped and filtered on a per-node basis. + - Copying and pasting tracks between animations is now possible. + - New Capture mode to blend from a node's current value to the first key in a track. +- [Improved animation tree and new state machine.](https://godotengine.org/article/godot-gets-new-animation-tree-state-machine) + - More visual feedback in the blend tree editor. + - 1D and 2D blend spaces are now supported. + - Ability to write custom blending logic. + - Support for root motion. +- [New FileSystem dock.](https://godotengine.org/article/godot-gets-new-filesystem-dock-3-1) + - Unified view of folders and files in the same panel. + - Files can now be marked as favorites, not only folders. + - Files now have icons representing their type, or thumbnail previews when relevant. + - New search field to filter entries in the tree. +- [OpenSimplexNoise and NoiseTexture resources.](https://godotengine.org/article/simplex-noise-lands-godot-31) +- [Optional static typing in GDScript.](https://godotengine.org/article/optional-typing-gdscript) + - Does not currently improve performance, but helps write more robust code. +- Warning system in GDScript. + - Reports potential code issues such as: + - unused variables, + - standalone expressions, + - discarded return values from functions, + - unreachable code after a `return` statement, + - … + - Warnings can be disabled in the Project Settings or by writing special comments. +- [GDScript keyword `class_name` to register scripts as classes.](http://docs.godotengine.org/en/latest/getting_started/step_by_step/scripting_continued.html#register-scripts-as-classes) +- Simple expression language independent from GDScript, used by inspector boxes that accept numeric values. + - Can also be used in projects. +- C# projects can now be exported for Windows, Linux, and macOS targets. +- The `server` platform is back as it was in Godot 2.1. + - It is now again possible to run a headless Godot instance on Linux. +- Support for BPTC texture compression on desktop platforms. +- New properties for SpatialMaterial. + - Dithering-based distance fade, for fading materials without making them transparent. + - Disable ambient light on a per-material basis. +- Option to link Mono statically on Windows. +- Unified class and reference search in the editor. +- Revamped TileSet editor with support for undo/redo operations. +- Various quality-of-life improvements to the Polygon2D and TextureRegion editors. +- RandomNumberGenerator class that allows for multiple instances at once. +- Array methods `min()` and `max()` to return the smallest and largest value respectively. +- Dictionary method `get(key[, default])` where `default` is returned if the key does not exist. +- Node method `print_tree_pretty()` to print a graphical view of the scene tree. +- String methods `trim_prefix()`, `trim_suffix()`, `lstrip()`, `rstrip()`. +- OS methods: + - `get_system_time_msecs()`: Return the system time with milliseconds. + - `get_audio_driver_name()` and `get_audio_driver_count()` to query audio driver information. + - `get_video_driver_count()` and `get_video_driver_name()` to query renderer information. + - `center_window()`: Center the window on the screen. + - `move_window_to_foreground()`: Move the window to the foreground. +- StreamPeerTCP method `set_no_delay()` to enable the `TCP_NODELAY` option. +- EditorPlugin method `remove_control_from_container()`. +- Ability to set Godot windows as "always on top". +- Ability to create windows with per-pixel transparency. +- New GLSL built-in functions in the shader language: + - `radians()` + - `degrees()` + - `asinh()` + - `acosh()` + - `atanh()` + - `exp2()` + - `log2()` + - `roundEven()` +- New command-line options: + - `--build-solutions`: Build C# solutions without starting the editor. + - `--print-fps`: Display frames per second to standard output. + - `--quit`: Quit the engine after the first main loop iteration. +- Debugger button to copy error messages. +- Support for `.escn` scenes has been added for use with the new Blender exporter. +- It is now possible to scale an OBJ mesh when importing. +- `popup_closed` signal for `ColorPickerButton`. +- Methods that are deprecated can now print warnings. +- Input actions can now provide an analog value. +- Input actions can now be mapped to either a specific device or all devices. +- DNS resolution for high-level networking. +- Servers can now kick/disconnect peers in high-level networking. +- Servers can now access IP and port information of peers in high-level networking. +- High-level multiplayer API decoupled from SceneTree (see `SceneTree.multiplayer_api`/`SceneTree.custom_multiplayer_api`), can now be extended. +- `Input.set_default_cursor_shape()` to change the default shape in the viewport. +- Custom cursors can now be as large as 256×256 (needed to be exactly 32×32 before). +- Support for radio-looking items with icon in `PopupMenu`s. +- Drag and drop to rearrange Editor docks. +- TileSet's `TileMode` is now exposed to GDScript. +- `OS.get_ticks_usec()` is now exposed to GDScript. +- Normals can now be flipped when generated via `SurfaceTool`. +- TextureProgress bars can now be bilinear (extending in both directions). +- The character used for masking secrets in LineEdit can now be changed. +- Improved DynamicFont: + - DynamicFonts can now use high-quality outlines generated by FreeType. + - DynamicFonts can now have their anti-aliasing disabled. + - DynamicFonts can now have their hinting tweaked ("Normal", "Light" or "None"). + - Colored glyphs such as emoji are now supported. +- Universal translation of touch input to mouse input. +- AudioStreamPlayer, AudioStreamPlayer2D, and AudioStreamPlayer3D now have a pitch scale property. +- Support for MIDI input. +- `GROW_DIRECTION_BOTH` for Controls. +- Selected tiles can be moved in the tile map editor. +- The editor can now be configured to display the project window on the previous or next monitor (relative to the editor). + - If either end is reached, then the project will start on the last or first monitor (respectively). +- Signal in VideoPlayer to notify when the video finished playing. +- `Image.bumpmap_to_normalmap()` to convert bump maps to normal maps. +- `File.get_path()` and `File.get_path_absolute()`. +- Unselected tabs in the editor now have a subtle background for easier identification. +- The depth fog's end distance is now configurable independently of the far plane distance. +- The alpha component of the fog color can now be used to control fog density. +- The 3D editor's information panel now displays the camera's coordinates. +- New options to hide the origin and viewport in the 2D editor. +- Improved 3D editor grid: + - The grid size and number of subdivisions can now be configured. + - Its primary and secondary colors can now also be changed. +- <kbd>Ctrl</kbd> now toggles snapping in the 3D viewport. +- Find & replace in files (<kbd>Ctrl + Shift + F</kbd> by default). +- Batch node renaming tool (<kbd>Ctrl + F2</kbd> by default). +- More editor scaling options to support HiDPI displays. +- Type icons can now be enabled in the editor again. +- Buttons in the editor to open common directories in the OS file manager: + - project data directory, + - user data directory, + - user settings directory. +- Projects can now be sorted by name or modification date in the project manager. +- Projects can now be imported from ZIP archives in the project manager. +- Improved autocompletion. + - Keywords are now present in autocompletion results. +- `editor` and `standalone` feature tags to check whether the project is running from an editor or non-editor binary. +- `android_add_asset_dir("...")` method to Android module Gradle build configuration. +- **iOS:** Support for exporting to the iPhone X. +- **iOS:** Readded support for in-app purchases. + +### Changed + +- [Built-in vector types now use copy-on-write mode as originally intended](https://godotengine.org/article/why-we-broke-your-pr), resulting in increased engine performance. +- The [mbedtls](https://tls.mbed.org/) library is now used instead of OpenSSL. +- SSL certificates are now bundled in exported projects unless a custom bundle is specified. +- Improved buffer writing performance on Windows and Linux. +- Removed many debugging prints in the console. +- Export templates now display an error dialog if no project was found when starting. +- DynamicFont oversampling is now enabled by default. +- Nodes' internal logic now consistently use internal physics processing. +- Allow attaching and clearing scripts on multiple nodes at once. +- Default values are no longer saved in scene and resource files. +- The selection rectangle of 2D nodes is now hidden when not pertinent (no more rectangle for collision shapes). +- SSE2 is now enabled in libsquish, resulting in improved S3TC encoding performance. +- Tangent and binormal coordinates are now more consistent across mesh types (primitive/imported), resulting in more predictable normal map and depth map appearance. +- Better defaults for 3D scenes. + - The default procedural sky now has a more neutral blue tone. + - The default SpatialMaterial now has a roughness value of 1 and metallic value of 0. + - The fallback material now uses the same values as the default SpatialMaterial. +- Text editor themes are now sorted alphabetically in the selection dropdown. +- The 3D manipulator gizmo now has a smoother, more detailed appearance. +- The 3D viewport menu button now has a background to make it easier to read. +- Controls inside containers are no longer movable or resizable but can still be selected. +- The `is` GDScript keyword can now be used to compare a value against built-in types. +- Named enums in GDScript no longer create script constants. + - This means `enum Name { VALUE }` must now be accessed with `Name.VALUE` instead of `VALUE`. +- Shadowing variables from parent scopes is no longer allowed in GDScript. +- Function parameters' default values can no longer depend on other parameters in GDScript. +- Indentation guides are now displayed in a more subtle way in the script editor. + - Indentation guides are now displayed when indenting using spaces. +- Multi-line strings are now highlighted as strings rather than as comments in the script editor. + - This is because GDScript does not officially support multiline comments. +- Increased the script editor's line spacing (4 pixels → 6 pixels). +- Increased the caret width in the script editor (1 pixel → 2 pixels). +- The project manager window is now resized to match the editor scale. +- The asset library now makes use of threading, making loading more responsive. +- Line spacing in the script editor, underlines and caret widths are now resized to match the editor scale. +- Replaced editor icons for checkboxes and radio buttons with simpler designs. +- Tweaked the editor's success, error, and warning text colors for better readability and consistency. +- **Android:** Custom permissions are now stored in an array and their amount is no longer limited to 20. + - Custom permissions will have to be redefined in projects imported from older versions. +- **Android:** Provide error details when an in-app purchase fails. +- **Linux:** `OS.alert()` now uses Zenity or KDialog if available instead of xmessage. +- **Mono:** Display stack traces for inner exceptions. +- **Mono:** Bundle `mscorlib.dll` with Godot to improve portability. + +### Removed + +- **macOS:** Support for 32-bit and fat binaries. + +### Fixed + +- [`move_and_slide()` now behaves differently at low velocities](https://github.com/godotengine/godot/issues/21683), which makes it function as originally intended. +- AnimatedSprite2D's `animation_finished` signal is now triggered at the end of the animation, instead of as soon as the last frame displays. +- Audio buses can now be removed in the editor while they are used by AudioStreamPlayer2D/3D nodes. +- Do not show the project manager unless no project was found at all. +- The animation editor time offset indicator no longer "walks" when resizing the editor. +- Allow creation of a built-in GDScript file even if the filename suggested already exists. +- Show tooltips in the editor when physics object picking is disabled. +- Fix a serialization bug that could cause TSCN files to grow very large. +- Gizmos are now properly hidden on scene load if the object they control is hidden. +- Camera gizmos in the 3D viewport no longer look twice as wide as they actually are. +- Copy/pasting from the editor on X11 will now work more reliably. +- `libgcc_s` and `libstdc++` are now linked statically for better Linux binary portability. +- The FPS cap set by `force_fps` in the Project Settings is no longer applied to the editor. + - Low FPS caps no longer cause the editor to feel sluggish. +- hiDPI is now detected and used if needed in the project manager. +- The Visual Studio Code external editor option now recognizes more binary names such as `code-oss`, making detection more reliable. +- The `-ffast-math` flag is no longer used when compiling Godot, resulting in increased floating-point determinism. +- Fix spelling of `apply_torque_impulse()` and deprecate the misspelled method. +- Remove spurious errors when using a PanoramaSky without textures. +- The lightmap baker will now use all available cores on Windows. +- Bullet physics now correctly calculates effective gravity on KinematicBodies. +- Setting the color `v` member now correctly sets the `s` member. +- RichTextLabels now correctly determine the baseline for all fonts. +- SpinBoxes now correctly calculate their initial size. +- OGG streams now correctly signal the end of playback. +- Android exporter no longer writes unnecessary permissions to the exported APK. +- Debugger "focus stealing" now works more reliably. +- Subresources are now always saved when saving a scene. +- Many fixes related to importers (glTF, Collada, audio), physics (Bullet), Mono/C#, GDNative, Android/iOS. +- **Mono:** Many fixes and improvements to C# support (including a `[Signal]` attribute). +- **WebAssembly:** Supply proper CORS headers. + +### Security + +- Fixed a security issue relating to deserializing Variants. + ## [3.0] - 2018-01-29 ### Added @@ -137,4 +382,5 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - HTML5 export using asm.js. - Only WebAssembly is supported now, since all browsers supporting WebGL 2.0 also support WebAssembly. +[Unreleased]: https://github.com/godotengine/godot/compare/3.0-stable...HEAD [3.0]: https://github.com/godotengine/godot/compare/2.1-stable...3.0-stable @@ -17,7 +17,6 @@ generous deed immortalized in the next stable release of Godot Engine. ## Gold sponsors Gamblify <https://www.gamblify.com> - GameDev.TV <https://gdev.tv/godot> Image Campus <https://www.imagecampus.edu.ar> ## Mini sponsors @@ -30,6 +29,7 @@ generous deed immortalized in the next stable release of Godot Engine. Christoph Woinke Edward Flick GameDev.net + GameDev.tv Hein-Pieter van Braam Jamal Alyafei Javary Games @@ -37,6 +37,8 @@ generous deed immortalized in the next stable release of Godot Engine. Justin Arnold Kyle Szklenski Leona Eden + Leonard Meagher + Ludosity AB Matthieu Huvé Maxim Karsten Mike King @@ -56,30 +58,34 @@ generous deed immortalized in the next stable release of Godot Engine. ## Gold donors Asdf + Brandon Waite cheese65536 David Gehrig Edward E + Florian Krick K9Kraken Manuele Finocchiaro Nathanael Beisiegel Officine Pixel S.n.c. Retro Village - Valorware Zashi Zaven Muradyan 13MHz Allen Schade Andreas Schüle + Asher Glick Austen McRae + Daniel James Daniel Lynn David Giardi Florian Breisch Gary Oberbrunner Gero Jay Horton - Johannes Wuensch + Jon Smith Jon Woodward + Jorge Bernal Joshua Lesperance Justo Delgado Baudí Krzysztof Dluzniewski @@ -89,8 +95,10 @@ generous deed immortalized in the next stable release of Godot Engine. paul gruenbacher Paul LaMotte Rob Messick + Scott Wadden Sergey Svenne Krap + Tom Langwaldt William Wold Wyatt Goodin Xananax @@ -107,10 +115,11 @@ generous deed immortalized in the next stable release of Godot Engine. Joan Fons John Krzysztof Jankowski - Laurence Bannister Lucas Ferreira Franca Markus Wiesner Nathan Lundquist + Pascal Grüter + Petr Malac Rami Robert Willes Robin Arys @@ -123,10 +132,8 @@ generous deed immortalized in the next stable release of Godot Engine. Alessandra Pereyra Alexey Dyadchenko - Amanda Haldy Benjamin W Flint Chau Siu Hung - Chris Brown Chris Goddard Chris Petrich Christian Leth Jeppesen @@ -139,13 +146,15 @@ generous deed immortalized in the next stable release of Godot Engine. Eric Monson Ethan Bennis Eugenio Hugo Salgüero Jáñez - Eulogio Enamorado Pallares flesk + gavlig GGGames.org + Giles Montgomery Giovanni Solimeno Guilherme Felipe de C. G. da Silva Heath Hayes Hysteria + Jalal Chaabane Jeppe Zapp Jose Malheiro Juan T Chen @@ -156,6 +165,7 @@ generous deed immortalized in the next stable release of Godot Engine. Marius Kamm Martin Eigel Marvin + Matt Eunson Max R.R. Collada Nick Nikitin Oliver Dick @@ -166,26 +176,28 @@ generous deed immortalized in the next stable release of Godot Engine. Ruben Soares Luis Samuel Judd Sofox + spilldata Stoned Xander Tobias Bocanegra WytRabbit Xavier Fumado Beltran - Zachariah Gibbons ## Silver donors 1D_Inc - 2drealms Adam Brunnmeier Adam Carr + Adam Nakonieczny Adam Smeltzer Adisibio Alder Stefano Alessandro Senese Alexander Gillberg Alexander Koppe + Alice Robinson Andreas Krampitz Anthony Bongiovanni + Arbor Interactive Arthur S. Muszynski Artur Barichello Aubrey Falconer @@ -200,19 +212,25 @@ generous deed immortalized in the next stable release of Godot Engine. Bryan Stevenson Carl Winder Carwyn Edwards + Chris Brown Chris Chapin Christian Baune Christian Winter + Christoffer Sundbom + Chris Wilson Collin Shooltz + Connor Hill Daniel Johnson - Daniel Kaplan DanielMaximiano + Daniel Reed David Cravens David May Dominik Wetzel DOXA Edward Herbert + Egon Elbre Elmeri '- Duy Kevin Nguyen + Emanuel Kotzayan Eric Martini Eric McCarthy Eric Williams @@ -232,11 +250,13 @@ generous deed immortalized in the next stable release of Godot Engine. Igor Buzatovic Jaime Ruiz-Borau Vizárraga Jako Danar + James A F Manley Jeff Hungerford Jeremy Kahn + Jesse Dubay Joao Senerchia Joel Fivat - Johan Lindberg + Johannes Wuensch Jonas Rudlang Jonas Yamazaki Jonathan G @@ -250,11 +270,11 @@ generous deed immortalized in the next stable release of Godot Engine. Juan Negrier Judd Julian Murgia - Justin Luk KC Chan Kevin Boyer - Kevin van Rooijen + Kiyohiro Kawamura (kyorohiro) Klagsam + KR McGinley KsyTek Games Kuan Cheang kycho @@ -269,7 +289,6 @@ generous deed immortalized in the next stable release of Godot Engine. Matt Welke Maxwell Mertcan Mermerkaya - mhilbrunner Michael Dürwald Michael Gringauz Michael Labbe @@ -284,9 +303,7 @@ generous deed immortalized in the next stable release of Godot Engine. Niclas Eriksen Nicolás Montaña Nicolas SAN AGUSTIN - nitenook Pan Ip - Pascal Grüter Patrick Nafarrete Paul Gieske Paul Mason @@ -298,37 +315,42 @@ generous deed immortalized in the next stable release of Godot Engine. Prokhorenko Leonid Psyagnostic Rafael - rayos Rémi Verschelde Ricardo Alcantara Richman Stewart + Robert Farr (Larington) Roger Burgess Roger Smith Roland Rząsa Roman Tinkov + Ryan Cheung + Ryan Hentz Sasori Olkof Sebastian Michailidis Shane Spoor + Simon Wenner Sootstone Theo Cranmore Théo Hay Thibault Barbaroux Thomas Bell Thomas Holmes + Thomas Kelly Thomas Kurz tiansheng li Tim Tim Drumheller Tom Larrow - Troy Austin + Torsten Crass Tryggve Sollid Tyler Stafos UltyX Vaiktorg Victor Viktor Ferenczi - Vladimir Soukup waka nya + Wayne Haak + werner mendizabal William Gervasio William Hogben Wout Standaert diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index e81468e888..f17d7372e2 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -592,17 +592,17 @@ struct Time { }; */ -int _OS::get_static_memory_usage() const { +uint64_t _OS::get_static_memory_usage() const { return OS::get_singleton()->get_static_memory_usage(); } -int _OS::get_static_memory_peak_usage() const { +uint64_t _OS::get_static_memory_peak_usage() const { return OS::get_singleton()->get_static_memory_peak_usage(); } -int _OS::get_dynamic_memory_usage() const { +uint64_t _OS::get_dynamic_memory_usage() const { return OS::get_singleton()->get_dynamic_memory_usage(); } diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index a4b4629037..1c8b985d73 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -283,9 +283,9 @@ public: uint64_t get_system_time_secs() const; uint64_t get_system_time_msecs() const; - int get_static_memory_usage() const; - int get_static_memory_peak_usage() const; - int get_dynamic_memory_usage() const; + uint64_t get_static_memory_usage() const; + uint64_t get_static_memory_peak_usage() const; + uint64_t get_dynamic_memory_usage() const; void delay_usec(uint32_t p_usec) const; void delay_msec(uint32_t p_msec) const; diff --git a/core/image.cpp b/core/image.cpp index 4fc3b4becb..3d48db872c 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1789,7 +1789,7 @@ Error Image::decompress() { _image_decompress_pvrtc(this); else if (format == FORMAT_ETC && _image_decompress_etc1) _image_decompress_etc1(this); - else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc1) + else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RGB8A1 && _image_decompress_etc2) _image_decompress_etc2(this); else return ERR_UNAVAILABLE; @@ -2632,6 +2632,9 @@ void Image::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data"); + BIND_CONSTANT(MAX_WIDTH); + BIND_CONSTANT(MAX_HEIGHT); + BIND_ENUM_CONSTANT(FORMAT_L8); //luminance BIND_ENUM_CONSTANT(FORMAT_LA8); //luminance-alpha BIND_ENUM_CONSTANT(FORMAT_R8); diff --git a/core/image.h b/core/image.h index 3604580e98..b23f8cac46 100644 --- a/core/image.h +++ b/core/image.h @@ -52,14 +52,14 @@ typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size); class Image : public Resource { GDCLASS(Image, Resource); +public: + static SavePNGFunc save_png_func; + enum { MAX_WIDTH = 16384, // force a limit somehow MAX_HEIGHT = 16384 // force a limit somehow }; -public: - static SavePNGFunc save_png_func; - enum Format { FORMAT_L8, //luminance diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index a0556ae839..b885a06834 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -260,8 +260,8 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { } // Check open list - SelfList<Point> *least_cost_point = NULL; - real_t least_cost = 1e30; + SelfList<Point> *least_cost_point = open_list.first(); + real_t least_cost = Math_INF; // TODO: Cache previous results for (SelfList<Point> *E = open_list.first(); E; E = E->next()) { diff --git a/core/math/matrix3.cpp b/core/math/basis.cpp index 0aa67078fb..8e4eacd9a6 100644 --- a/core/math/matrix3.cpp +++ b/core/math/basis.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* matrix3.cpp */ +/* basis.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "matrix3.h" +#include "basis.h" #include "core/math/math_funcs.h" #include "core/os/copymem.h" diff --git a/core/math/matrix3.h b/core/math/basis.h index e7d6ab4522..128e56b494 100644 --- a/core/math/matrix3.h +++ b/core/math/basis.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* matrix3.h */ +/* basis.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,8 +31,8 @@ // Circular dependency between Vector3 and Basis :/ #include "core/math/vector3.h" -#ifndef MATRIX3_H -#define MATRIX3_H +#ifndef BASIS_H +#define BASIS_H #include "core/math/quat.h" @@ -341,4 +341,4 @@ real_t Basis::determinant() const { elements[1][0] * (elements[0][1] * elements[2][2] - elements[2][1] * elements[0][2]) + elements[2][0] * (elements[0][1] * elements[1][2] - elements[1][1] * elements[0][2]); } -#endif +#endif // BASIS_H diff --git a/core/math/quat.cpp b/core/math/quat.cpp index c1e45f36f0..6833d5de55 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -30,7 +30,7 @@ #include "quat.h" -#include "core/math/matrix3.h" +#include "core/math/basis.h" #include "core/print_string.h" // set_euler_xyz expects a vector containing the Euler angles in the format diff --git a/core/math/transform.h b/core/math/transform.h index 9b323a6f0f..2f43f6b035 100644 --- a/core/math/transform.h +++ b/core/math/transform.h @@ -32,7 +32,7 @@ #define TRANSFORM_H #include "core/math/aabb.h" -#include "core/math/matrix3.h" +#include "core/math/basis.h" #include "core/math/plane.h" /** diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index b2e89ac7b8..1c28934422 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -30,7 +30,7 @@ #include "vector3.h" -#include "core/math/matrix3.h" +#include "core/math/basis.h" void Vector3::rotate(const Vector3 &p_axis, real_t p_phi) { diff --git a/core/math/vector3.h b/core/math/vector3.h index b0eef35635..8d6e093c4c 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -151,7 +151,7 @@ struct Vector3 { }; // Should be included after class definition, otherwise we get circular refs -#include "core/math/matrix3.h" +#include "core/math/basis.h" Vector3 Vector3::cross(const Vector3 &p_b) const { diff --git a/core/object.cpp b/core/object.cpp index 682586a7ab..05e661baab 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -1924,6 +1924,11 @@ void *Object::get_script_instance_binding(int p_script_language_index) { return _script_instance_bindings[p_script_language_index]; } +bool Object::has_script_instance_binding(int p_script_language_index) { + + return _script_instance_bindings[p_script_language_index] != NULL; +} + Object::Object() { _class_ptr = NULL; diff --git a/core/object.h b/core/object.h index a5bb6dea5d..5bfef8a439 100644 --- a/core/object.h +++ b/core/object.h @@ -729,6 +729,7 @@ public: //used by script languages to store binding data void *get_script_instance_binding(int p_script_language_index); + bool has_script_instance_binding(int p_script_language_index); void clear_internal_resource_paths(); diff --git a/core/os/os.cpp b/core/os/os.cpp index 1f967030e7..d2d39d253a 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -393,16 +393,16 @@ Error OS::dialog_input_text(String p_title, String p_description, String p_parti return OK; }; -int OS::get_static_memory_usage() const { +uint64_t OS::get_static_memory_usage() const { return Memory::get_mem_usage(); } -int OS::get_dynamic_memory_usage() const { +uint64_t OS::get_dynamic_memory_usage() const { return MemoryPool::total_memory; } -int OS::get_static_memory_peak_usage() const { +uint64_t OS::get_static_memory_peak_usage() const { return Memory::get_mem_max_usage(); } @@ -418,7 +418,7 @@ bool OS::has_touchscreen_ui_hint() const { return Input::get_singleton() && Input::get_singleton()->is_emulating_touch_from_mouse(); } -int OS::get_free_static_memory() const { +uint64_t OS::get_free_static_memory() const { return Memory::get_mem_available(); } diff --git a/core/os/os.h b/core/os/os.h index 36d4e5a8c1..396555970a 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -45,12 +45,6 @@ @author Juan Linietsky <reduzio@gmail.com> */ -enum VideoDriver { - VIDEO_DRIVER_GLES3, - VIDEO_DRIVER_GLES2, - VIDEO_DRIVER_MAX, -}; - class OS { static OS *singleton; @@ -184,9 +178,16 @@ public: virtual VideoMode get_video_mode(int p_screen = 0) const = 0; virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const = 0; + enum VideoDriver { + VIDEO_DRIVER_GLES3, + VIDEO_DRIVER_GLES2, + VIDEO_DRIVER_MAX, + }; + virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; virtual int get_current_video_driver() const = 0; + virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; @@ -266,6 +267,7 @@ public: virtual bool has_environment(const String &p_var) const = 0; virtual String get_environment(const String &p_var) const = 0; + virtual bool set_environment(const String &p_var, const String &p_value) const = 0; virtual String get_name() = 0; virtual List<String> get_cmdline_args() const { return _cmdline; } @@ -382,10 +384,10 @@ public: virtual void print_resources_in_use(bool p_short = false); virtual void print_all_resources(String p_to_file = ""); - virtual int get_static_memory_usage() const; - virtual int get_static_memory_peak_usage() const; - virtual int get_dynamic_memory_usage() const; - virtual int get_free_static_memory() const; + virtual uint64_t get_static_memory_usage() const; + virtual uint64_t get_static_memory_peak_usage() const; + virtual uint64_t get_dynamic_memory_usage() const; + virtual uint64_t get_free_static_memory() const; RenderThreadMode get_render_thread_mode() const { return _render_thread_mode; } diff --git a/core/variant.h b/core/variant.h index 0377c78ea8..6ddaf17406 100644 --- a/core/variant.h +++ b/core/variant.h @@ -41,8 +41,8 @@ #include "core/dvector.h" #include "core/io/ip_address.h" #include "core/math/aabb.h" +#include "core/math/basis.h" #include "core/math/face3.h" -#include "core/math/matrix3.h" #include "core/math/plane.h" #include "core/math/quat.h" #include "core/math/transform.h" diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml index c5f71fe55e..78623b359e 100644 --- a/doc/classes/Expression.xml +++ b/doc/classes/Expression.xml @@ -16,7 +16,7 @@ func _on_text_entered(command): var error = expression.parse(command, []) if error != OK: - print(get_error_text()) + print(expression.get_error_text()) return var result = expression.execute([], null, true) if not expression.has_execute_failed(): @@ -39,6 +39,7 @@ </argument> <description> Executes the expression that was previously parsed by [method parse] and returns the result. Before you use the returned object, you should check if the method failed by calling [method has_execute_failed]. + If you defined input variables in [method parse], you can specify their values in the inputs array, in the same order. </description> </method> <method name="get_error_text" qualifiers="const"> @@ -64,6 +65,7 @@ </argument> <description> Parses the expression and returns a [enum @GlobalScope.Error]. + You can optionally specify names of variables that may appear in the expression with [code]input_names[/code], so that you can bind them when it gets executed. </description> </method> </methods> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 56accdcd9e..8868dd778d 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -4,7 +4,7 @@ Image datatype. </brief_description> <description> - Native image datatype. Contains image data, which can be converted to a [Texture], and several functions to interact with it. The maximum width and height for an [code]Image[/code] is 16384 pixels. + Native image datatype. Contains image data, which can be converted to a [Texture], and several functions to interact with it. The maximum width and height for an [code]Image[/code] are [constant MAX_WIDTH] and [constant MAX_HEIGHT]. </description> <tutorials> </tutorials> @@ -476,6 +476,12 @@ </member> </members> <constants> + <constant name="MAX_WIDTH" value="16384"> + The maximal width allowed for [code]Image[/code] resources. + </constant> + <constant name="MAX_HEIGHT" value="16384"> + The maximal height allowed for [code]Image[/code] resources. + </constant> <constant name="FORMAT_L8" value="0" enum="Format"> </constant> <constant name="FORMAT_LA8" value="1" enum="Format"> diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 1908fdd684..7986461840 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -4,8 +4,8 @@ Provides high performance mesh instancing. </brief_description> <description> - MultiMesh provides low level mesh instancing. If the amount of [Mesh] instances needed goes from hundreds to thousands (and most need to be visible at close proximity) creating such a large amount of [MeshInstance] nodes may affect performance by using too much CPU or video memory. - For this case a MultiMesh becomes very useful, as it can draw thousands of instances with little API overhead. + MultiMesh provides low level mesh instancing. Drawing thousands of [MeshInstance] nodes can be slow because each object is submitted to the GPU to be drawn individually. + MultiMesh is much faster because it can draw thousands of instances with a single draw call, resulting in less API overhead. As a drawback, if the instances are too far away of each other, performance may be reduced as every single instance will always rendered (they are spatially indexed as one, for the whole object). Since instances may have any behavior, the AABB used for visibility must be provided by the user. </description> @@ -36,6 +36,7 @@ <argument index="0" name="instance" type="int"> </argument> <description> + Return the custom data that has been set for a specific instance. </description> </method> <method name="get_instance_transform" qualifiers="const"> @@ -66,6 +67,7 @@ <argument index="1" name="custom_data" type="Color"> </argument> <description> + Set custom data for a specific instance. Although [Color] is used, it is just a container for 4 numbers. </description> </method> <method name="set_instance_transform"> @@ -82,32 +84,45 @@ </methods> <members> <member name="color_format" type="int" setter="set_color_format" getter="get_color_format" enum="MultiMesh.ColorFormat"> + Format of colors in color array that gets passed to shader. </member> <member name="custom_data_format" type="int" setter="set_custom_data_format" getter="get_custom_data_format" enum="MultiMesh.CustomDataFormat"> + Format of custom data in custom data array that gets passed to shader. </member> <member name="instance_count" type="int" setter="set_instance_count" getter="get_instance_count"> + Number of instances that will get drawn. </member> <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh"> + Mesh to be drawn. </member> <member name="transform_format" type="int" setter="set_transform_format" getter="get_transform_format" enum="MultiMesh.TransformFormat"> + Format of transform used to transform mesh, either 2D or 3D. </member> </members> <constants> <constant name="TRANSFORM_2D" value="0" enum="TransformFormat"> + Use this when using 2D transforms. </constant> <constant name="TRANSFORM_3D" value="1" enum="TransformFormat"> + Use this when using 3D transforms. </constant> <constant name="COLOR_NONE" value="0" enum="ColorFormat"> + Use when you are not using per-instance [Color]s. </constant> <constant name="COLOR_8BIT" value="1" enum="ColorFormat"> + Compress [Color] data into 8 bits when passing to shader. This uses less memory and can be faster, but the [Color] loses precision. </constant> <constant name="COLOR_FLOAT" value="2" enum="ColorFormat"> + The [Color] passed into [method set_instance_color] will use 4 floats. Use this for highest precision [Color]. </constant> <constant name="CUSTOM_DATA_NONE" value="0" enum="CustomDataFormat"> + Use when you are not using per-instance custom data. </constant> <constant name="CUSTOM_DATA_8BIT" value="1" enum="CustomDataFormat"> + Compress custom_data into 8 bits when passing to shader. This uses less memory and can be faster, but loses precision. </constant> <constant name="CUSTOM_DATA_FLOAT" value="2" enum="CustomDataFormat"> + The [Color] passed into [method set_instance_custom_data] will use 4 floats. Use this for highest precision. </constant> </constants> </class> diff --git a/doc/classes/PhysicsDirectSpaceState.xml b/doc/classes/PhysicsDirectSpaceState.xml index c4dc103b72..118010b3cf 100644 --- a/doc/classes/PhysicsDirectSpaceState.xml +++ b/doc/classes/PhysicsDirectSpaceState.xml @@ -21,7 +21,7 @@ </argument> <description> Checks whether the shape can travel to a point. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [code][1, 1][/code]. - If the shape can not move, the returned array will be [code][0, 0][/code]. + If the shape can not move, the returned array will be [code][0, 0][/code] under Bullet, and empty under GodotPhysics. </description> </method> <method name="collide_shape"> diff --git a/doc/classes/ResourcePreloader.xml b/doc/classes/ResourcePreloader.xml index 002bcd891a..18d6e04d8e 100644 --- a/doc/classes/ResourcePreloader.xml +++ b/doc/classes/ResourcePreloader.xml @@ -4,7 +4,7 @@ Resource Preloader Node. </brief_description> <description> - Resource Preloader Node. This node is used to preload sub-resources inside a scene, so when the scene is loaded all the resources are ready to use and be retrieved from here. + This node is used to preload sub-resources inside a scene, so when the scene is loaded, all the resources are ready to use and can be retrieved from the preloader. </description> <tutorials> </tutorials> @@ -19,6 +19,7 @@ <argument index="1" name="resource" type="Resource"> </argument> <description> + Adds a resource to the preloader with the given [code]name[/code]. If a resource with the given [code]name[/code] already exists, the new resource will be renamed to "[code]name[/code] N" where N is an incrementing number starting from 2. </description> </method> <method name="get_resource" qualifiers="const"> @@ -27,14 +28,14 @@ <argument index="0" name="name" type="String"> </argument> <description> - Return the resource given a text-id. + Returns the resource associated to [code]name[/code]. </description> </method> <method name="get_resource_list" qualifiers="const"> <return type="PoolStringArray"> </return> <description> - Return the list of resources inside the preloader. + Returns the list of resources inside the preloader. </description> </method> <method name="has_resource" qualifiers="const"> @@ -43,7 +44,7 @@ <argument index="0" name="name" type="String"> </argument> <description> - Return true if the preloader has a given resource. + Returns true if the preloader contains a resource associated to [code]name[/code]. </description> </method> <method name="remove_resource"> @@ -52,7 +53,7 @@ <argument index="0" name="name" type="String"> </argument> <description> - Remove a resource from the preloader by text id. + Removes the resource associated to [code]name[/code] from the preloader. </description> </method> <method name="rename_resource"> @@ -63,7 +64,7 @@ <argument index="1" name="newname" type="String"> </argument> <description> - Rename a resource inside the preloader, from a text-id to a new text-id. + Renames a resource inside the preloader from [code]name[/code] to [code]newname[/code]. </description> </method> </methods> diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index bff031b93a..fa1242ceed 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -806,9 +806,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_COLOR"] = "#define SHADOW_COLOR_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[VS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; /** SPATIAL SHADER **/ @@ -831,7 +829,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize"; // gl_InstanceID is not available in OpenGL ES 2.0 actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0"; - actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; //builtins @@ -863,12 +860,15 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer"; - actions[VS::SHADER_SPATIAL].renames["SIDE"] = "side"; + // Defined in GLES3, but not available in GLES2 + //actions[VS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth"; actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; + actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; //for light actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view"; actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; + actions[VS::SHADER_SPATIAL].renames["LIGHT"] = "light"; actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation"; actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light"; actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light"; @@ -903,6 +903,12 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; + // Defined in GLES3, could be implemented in GLES2 too if there's a need for it + //actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; + // Defined in GLES3, might not be possible in GLES2 as gl_FrontFacing is not available + //actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; + //actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; + bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); if (!force_lambert) { @@ -928,27 +934,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; - /* PARTICLES SHADER */ - - actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color"; - actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz"; - actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass"; - actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active"; - actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart"; - actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom"; - actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform"; - actions[VS::SHADER_PARTICLES].renames["TIME"] = "time"; - actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime"; - actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta"; - actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number"; - actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index"; - actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity"; - actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform"; - actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed"; - - actions[VS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; - actions[VS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; - actions[VS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; + // No defines for particle shaders in GLES2, there are no GPU particles vertex_name = "vertex"; fragment_name = "fragment"; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index cda6dac506..4d6f37e093 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -963,9 +963,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform"; actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed"; - actions[VS::SHADER_SPATIAL].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; + actions[VS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; + actions[VS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; + actions[VS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; vertex_name = "vertex"; fragment_name = "fragment"; diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index ce1c183242..e3e2e10e82 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -469,6 +469,11 @@ String OS_Unix::get_environment(const String &p_var) const { return ""; } +bool OS_Unix::set_environment(const String &p_var, const String &p_value) const { + + return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0; +} + int OS_Unix::get_processor_count() const { return sysconf(_SC_NPROCESSORS_CONF); diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 2a23da6f28..09ab4aa1d8 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -95,6 +95,7 @@ public: virtual bool has_environment(const String &p_var) const; virtual String get_environment(const String &p_var) const; + virtual bool set_environment(const String &p_var, const String &p_value) const; virtual String get_locale() const; virtual int get_processor_count() const; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 4ab9a72694..927d915bcd 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -31,6 +31,7 @@ #include "code_editor.h" #include "core/os/keyboard.h" +#include "core/string_builder.h" #include "editor/editor_scale.h" #include "editor_node.h" #include "editor_settings.h" @@ -673,18 +674,14 @@ void CodeTextEditor::_reset_zoom() { if (font.is_valid()) { EditorSettings::get_singleton()->set("interface/editor/code_font_size", 14); font->set_size(14); - font_size_nb->set_text("14 (100%)"); } } void CodeTextEditor::_line_col_changed() { - line_nb->set_text(itos(text_editor->cursor_get_line() + 1)); - String line = text_editor->get_line(text_editor->cursor_get_line()); int positional_column = 0; - for (int i = 0; i < text_editor->cursor_get_column(); i++) { if (line[i] == '\t') { positional_column += text_editor->get_indent_size(); //tab size @@ -693,7 +690,14 @@ void CodeTextEditor::_line_col_changed() { } } - col_nb->set_text(itos(positional_column + 1)); + StringBuilder *sb = memnew(StringBuilder); + sb->append("("); + sb->append(itos(text_editor->cursor_get_line() + 1).lpad(3)); + sb->append(","); + sb->append(itos(positional_column + 1).lpad(3)); + sb->append(")"); + + line_and_col_txt->set_text(sb->as_string()); } void CodeTextEditor::_text_changed() { @@ -747,8 +751,6 @@ bool CodeTextEditor::_add_font_size(int p_delta) { if (font.is_valid()) { int new_size = CLAMP(font->get_size() + p_delta, 8 * EDSCALE, 96 * EDSCALE); - font_size_nb->set_text(itos(new_size) + " (" + itos(100 * new_size / (14 * EDSCALE)) + "%)"); - if (new_size != font->get_size()) { EditorSettings::get_singleton()->set("interface/editor/code_font_size", new_size / EDSCALE); font->set_size(new_size); @@ -1167,7 +1169,6 @@ void CodeTextEditor::_on_settings_change() { _update_font(); font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size"); - font_size_nb->set_text(itos(font_size) + " (" + itos(100 * font_size / (14 * EDSCALE)) + "%)"); // AUTO BRACE COMPLETION text_editor->set_auto_brace_completion( @@ -1188,17 +1189,48 @@ void CodeTextEditor::_text_changed_idle_timeout() { emit_signal("validate_script"); } -void CodeTextEditor::_notification(int p_what) { +void CodeTextEditor::_warning_label_gui_input(const Ref<InputEvent> &p_event) { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + _warning_button_pressed(); + } +} - if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - _load_theme_settings(); - emit_signal("load_theme_settings"); +void CodeTextEditor::_warning_button_pressed() { + emit_signal("warning_pressed"); +} + +void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + emit_signal("error_pressed"); } - if (p_what == NOTIFICATION_THEME_CHANGED) { - _update_font(); +} + +void CodeTextEditor::_notification(int p_what) { + + switch (p_what) { + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + _load_theme_settings(); + emit_signal("load_theme_settings"); + } break; + case NOTIFICATION_THEME_CHANGED: { + _update_font(); + } break; + case NOTIFICATION_ENTER_TREE: { + warning_button->set_icon(get_icon("NodeWarning", "EditorIcons")); + } break; + default: + break; } } +void CodeTextEditor::set_warning_nb(int p_warning_nb) { + warning_count_label->set_text(itos(p_warning_nb)); + warning_count_label->set_visible(p_warning_nb > 0); + warning_button->set_visible(p_warning_nb > 0); +} + void CodeTextEditor::_bind_methods() { ClassDB::bind_method("_text_editor_gui_input", &CodeTextEditor::_text_editor_gui_input); @@ -1209,9 +1241,14 @@ void CodeTextEditor::_bind_methods() { ClassDB::bind_method("_code_complete_timer_timeout", &CodeTextEditor::_code_complete_timer_timeout); ClassDB::bind_method("_complete_request", &CodeTextEditor::_complete_request); ClassDB::bind_method("_font_resize_timeout", &CodeTextEditor::_font_resize_timeout); + ClassDB::bind_method("_error_pressed", &CodeTextEditor::_error_pressed); + ClassDB::bind_method("_warning_button_pressed", &CodeTextEditor::_warning_button_pressed); + ClassDB::bind_method("_warning_label_gui_input", &CodeTextEditor::_warning_label_gui_input); ADD_SIGNAL(MethodInfo("validate_script")); ADD_SIGNAL(MethodInfo("load_theme_settings")); + ADD_SIGNAL(MethodInfo("warning_pressed")); + ADD_SIGNAL(MethodInfo("error_pressed")); } void CodeTextEditor::set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void *p_ud) { @@ -1226,15 +1263,16 @@ CodeTextEditor::CodeTextEditor() { ED_SHORTCUT("script_editor/zoom_out", TTR("Zoom Out"), KEY_MASK_CMD | KEY_MINUS); ED_SHORTCUT("script_editor/reset_zoom", TTR("Reset Zoom"), KEY_MASK_CMD | KEY_0); + text_editor = memnew(TextEdit); + add_child(text_editor); + text_editor->set_v_size_flags(SIZE_EXPAND_FILL); + + // Added second to it opens at the bottom, so it won't shift the entire text editor when opening find_replace_bar = memnew(FindReplaceBar); add_child(find_replace_bar); find_replace_bar->set_h_size_flags(SIZE_EXPAND_FILL); find_replace_bar->hide(); - text_editor = memnew(TextEdit); - add_child(text_editor); - text_editor->set_v_size_flags(SIZE_EXPAND_FILL); - find_replace_bar->set_text_edit(text_editor); text_editor->set_show_line_numbers(true); @@ -1258,95 +1296,50 @@ CodeTextEditor::CodeTextEditor() { error_line = 0; error_column = 0; + // Error + ScrollContainer *scroll = memnew(ScrollContainer); + scroll->set_h_size_flags(SIZE_EXPAND_FILL); + scroll->set_v_size_flags(SIZE_EXPAND_FILL); + scroll->set_enable_v_scroll(false); + status_bar->add_child(scroll); + error = memnew(Label); - status_bar->add_child(error); - error->set_autowrap(true); - error->set_valign(Label::VALIGN_CENTER); - error->set_h_size_flags(SIZE_EXPAND_FILL); //required for it to display, given now it's clipping contents, do not touch + scroll->add_child(error); + error->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); error->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); error->set_mouse_filter(MOUSE_FILTER_STOP); + error->connect("gui_input", this, "_error_pressed"); find_replace_bar->connect("error", error, "set_text"); - status_bar->add_child(memnew(Label)); //to keep the height if the other labels are not visible - - warning_label = memnew(Label); - status_bar->add_child(warning_label); - warning_label->set_align(Label::ALIGN_RIGHT); - warning_label->set_valign(Label::VALIGN_CENTER); - warning_label->set_v_size_flags(SIZE_FILL); - warning_label->set_default_cursor_shape(CURSOR_POINTING_HAND); - warning_label->set_mouse_filter(MOUSE_FILTER_STOP); - warning_label->set_text(TTR("Warnings:")); - warning_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + // Warnings + warning_button = memnew(ToolButton); + status_bar->add_child(warning_button); + warning_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); + warning_button->set_default_cursor_shape(CURSOR_POINTING_HAND); + warning_button->connect("pressed", this, "_warning_button_pressed"); + warning_button->set_tooltip(TTR("Warnings")); warning_count_label = memnew(Label); status_bar->add_child(warning_count_label); - warning_count_label->set_valign(Label::VALIGN_CENTER); - warning_count_label->set_v_size_flags(SIZE_FILL); - warning_count_label->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch - warning_count_label->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch - warning_count_label->set_custom_minimum_size(Size2(40, 1) * EDSCALE); + warning_count_label->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); warning_count_label->set_align(Label::ALIGN_RIGHT); warning_count_label->set_default_cursor_shape(CURSOR_POINTING_HAND); warning_count_label->set_mouse_filter(MOUSE_FILTER_STOP); + warning_count_label->set_tooltip(TTR("Warnings")); + warning_count_label->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor")); warning_count_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); - warning_count_label->set_text("0"); - - Label *font_size_txt = memnew(Label); - status_bar->add_child(font_size_txt); - font_size_txt->set_align(Label::ALIGN_RIGHT); - font_size_txt->set_valign(Label::VALIGN_CENTER); - font_size_txt->set_v_size_flags(SIZE_FILL); - font_size_txt->set_text(TTR("Font Size:")); - font_size_txt->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); - - font_size_nb = memnew(Label); - status_bar->add_child(font_size_nb); - font_size_nb->set_valign(Label::VALIGN_CENTER); - font_size_nb->set_v_size_flags(SIZE_FILL); - font_size_nb->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch - font_size_nb->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch - font_size_nb->set_custom_minimum_size(Size2(100, 1) * EDSCALE); - font_size_nb->set_align(Label::ALIGN_RIGHT); - font_size_nb->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); - - Label *line_txt = memnew(Label); - status_bar->add_child(line_txt); - line_txt->set_align(Label::ALIGN_RIGHT); - line_txt->set_valign(Label::VALIGN_CENTER); - line_txt->set_v_size_flags(SIZE_FILL); - line_txt->set_text(TTR("Line:")); - line_txt->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); - - line_nb = memnew(Label); - status_bar->add_child(line_nb); - line_nb->set_valign(Label::VALIGN_CENTER); - line_nb->set_v_size_flags(SIZE_FILL); - line_nb->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch - line_nb->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch - line_nb->set_custom_minimum_size(Size2(40, 1) * EDSCALE); - line_nb->set_align(Label::ALIGN_RIGHT); - line_nb->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); - - Label *col_txt = memnew(Label); - status_bar->add_child(col_txt); - col_txt->set_align(Label::ALIGN_RIGHT); - col_txt->set_valign(Label::VALIGN_CENTER); - col_txt->set_v_size_flags(SIZE_FILL); - col_txt->set_text(TTR("Col:")); - col_txt->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); - - col_nb = memnew(Label); - status_bar->add_child(col_nb); - col_nb->set_valign(Label::VALIGN_CENTER); - col_nb->set_v_size_flags(SIZE_FILL); - col_nb->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch - col_nb->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch - col_nb->set_custom_minimum_size(Size2(40, 1) * EDSCALE); - col_nb->set_align(Label::ALIGN_RIGHT); - col_nb->set("custom_constants/margin_right", 0); - col_nb->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + warning_count_label->connect("gui_input", this, "_warning_label_gui_input"); + + set_warning_nb(0); + + // Line and column + line_and_col_txt = memnew(Label); + status_bar->add_child(line_and_col_txt); + line_and_col_txt->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); + line_and_col_txt->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + line_and_col_txt->set_tooltip(TTR("Line and column numbers")); + line_and_col_txt->set_mouse_filter(MOUSE_FILTER_STOP); text_editor->connect("gui_input", this, "_text_editor_gui_input"); text_editor->connect("cursor_changed", this, "_line_col_changed"); @@ -1365,7 +1358,6 @@ CodeTextEditor::CodeTextEditor() { font_resize_val = 0; font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size"); - font_size_nb->set_text(itos(font_size) + " (" + itos(100 * font_size / (14 * EDSCALE)) + "%)"); font_resize_timer = memnew(Timer); add_child(font_resize_timer); font_resize_timer->set_one_shot(true); diff --git a/editor/code_editor.h b/editor/code_editor.h index 96fc5b79e5..14ce3254ea 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -142,12 +142,12 @@ class CodeTextEditor : public VBoxContainer { TextEdit *text_editor; FindReplaceBar *find_replace_bar; HBoxContainer *status_bar; - Label *warning_label; + + ToolButton *warning_button; Label *warning_count_label; - Label *line_nb; - Label *col_nb; - Label *font_size_nb; + Label *line_and_col_txt; + Label *info; Timer *idle; Timer *code_complete_timer; @@ -176,6 +176,10 @@ class CodeTextEditor : public VBoxContainer { CodeTextEditorCodeCompleteFunc code_complete_func; void *code_complete_ud; + void _warning_label_gui_input(const Ref<InputEvent> &p_event); + void _warning_button_pressed(); + void _error_pressed(const Ref<InputEvent> &p_event); + protected: virtual void _load_theme_settings() {} virtual void _validate_script() {} @@ -212,15 +216,14 @@ public: Variant get_edit_state(); void set_edit_state(const Variant &p_state); + void set_warning_nb(int p_warning_nb); + void update_editor_settings(); void set_error(const String &p_error); void set_error_pos(int p_line, int p_column); void update_line_and_column() { _line_col_changed(); } TextEdit *get_text_edit() { return text_editor; } FindReplaceBar *get_find_replace_bar() { return find_replace_bar; } - Label *get_error_label() const { return error; } - Label *get_warning_label() const { return warning_label; } - Label *get_warning_count_label() const { return warning_count_label; } virtual void apply_code() {} void goto_error(); diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index f9f1e455f5..f5a60f2553 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -475,7 +475,6 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector< Vector<RemovedDependency> removed_deps; _find_all_removed_dependencies(EditorFileSystem::get_singleton()->get_filesystem(), removed_deps); removed_deps.sort(); - if (removed_deps.empty()) { owners->hide(); text->set_text(TTR("Remove selected files from the project? (no undo)")); @@ -486,6 +485,7 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector< text->set_text(TTR("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)")); popup_centered_minsize(Size2(500, 350)); } + EditorFileSystem::get_singleton()->scan_changes(); } void DependencyRemoveDialog::ok_pressed() { diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp index 6ab41c641d..6b13d19d33 100644 --- a/editor/editor_folding.cpp +++ b/editor/editor_folding.cpp @@ -173,7 +173,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) { for (int i = 0; i < unfolds.size(); i += 2) { NodePath path = unfolds[i]; PoolVector<String> un = unfolds[i + 1]; - Node *node = p_scene->get_node(path); + Node *node = p_scene->get_node_or_null(path); if (!node) { continue; } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index f8cee6883b..7061d38a2a 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1423,10 +1423,6 @@ EditorHelp::EditorHelp() { EDITOR_DEF("text_editor/help/sort_functions_alphabetically", true); - find_bar = memnew(FindBar); - add_child(find_bar); - find_bar->hide(); - class_desc = memnew(RichTextLabel); add_child(class_desc); class_desc->set_v_size_flags(SIZE_EXPAND_FILL); @@ -1434,6 +1430,10 @@ EditorHelp::EditorHelp() { class_desc->connect("meta_clicked", this, "_class_desc_select"); class_desc->connect("gui_input", this, "_class_desc_input"); + // Added second so it opens at the bottom so it won't offset the entire widget + find_bar = memnew(FindBar); + add_child(find_bar); + find_bar->hide(); find_bar->set_rich_text_label(class_desc); class_desc->set_selection_enabled(true); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 803d7e10f7..aaca47622d 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -65,7 +65,6 @@ void EditorLog::_notification(int p_what) { } else if (p_what == NOTIFICATION_THEME_CHANGED) { Ref<DynamicFont> df_output_code = get_font("output_source", "EditorFonts"); if (df_output_code.is_valid()) { - df_output_code->set_size(int(EDITOR_DEF("run/output/font_size", 13)) * EDSCALE); if (log != NULL) { log->add_font_override("normal_font", get_font("output_source", "EditorFonts")); } @@ -132,7 +131,6 @@ void EditorLog::_bind_methods() { EditorLog::EditorLog() { VBoxContainer *vb = this; - add_constant_override("separation", get_constant("separation", "VBoxContainer")); HBoxContainer *hb = memnew(HBoxContainer); vb->add_child(hb); @@ -163,6 +161,8 @@ EditorLog::EditorLog() { current = Thread::get_caller_id(); + add_constant_override("separation", get_constant("separation", "VBoxContainer")); + EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk, this); } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index c8e00b0586..8f9bfd31a1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2972,6 +2972,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b prev_scene->set_disabled(previous_scenes.size() == 0); opening_prev = false; + scene_tree_dock->set_selected(new_scene); ScriptEditor::get_singleton()->get_debugger()->update_live_edit_root(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 9973c7354e..cbd8df315a 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -575,6 +575,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("run/auto_save/save_before_running", true); // Output + hints["run/output/font_size"] = PropertyInfo(Variant::INT, "run/output/font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT); _initial_set("run/output/always_clear_output_on_play", true); _initial_set("run/output/always_open_output_on_play", true); _initial_set("run/output/always_close_output_on_stop", false); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 4556b11708..0c0cc9d635 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -334,7 +334,7 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size OS::get_singleton()->delay_usec(10); } - Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture); + Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture); VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID()); ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>()); @@ -734,7 +734,7 @@ Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 p_ OS::get_singleton()->delay_usec(10); } - Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture); + Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture); ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>()); VS::get_singleton()->instance_set_base(mesh_instance, RID()); @@ -854,7 +854,7 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, c OS::get_singleton()->delay_usec(10); } - Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture); + Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture); ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>()); img->convert(Image::FORMAT_RGBA8); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 60dc156782..c747e8fe5c 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -273,18 +273,12 @@ void ScriptTextEditor::_set_theme_for_script() { } } -void ScriptTextEditor::_toggle_warning_pannel(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - warnings_panel->set_visible(!warnings_panel->is_visible()); - } +void ScriptTextEditor::_toggle_warning_pannel() { + warnings_panel->set_visible(!warnings_panel->is_visible()); } -void ScriptTextEditor::_error_pressed(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - code_editor->goto_error(); - } +void ScriptTextEditor::_error_pressed() { + code_editor->goto_error(); } void ScriptTextEditor::_warning_clicked(Variant p_line) { @@ -468,7 +462,7 @@ void ScriptTextEditor::_validate_script() { } } - code_editor->get_warning_count_label()->set_text(itos(warnings.size())); + code_editor->set_warning_nb(warnings.size()); warnings_panel->clear(); warnings_panel->push_table(3); for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) { @@ -1427,7 +1421,7 @@ ScriptTextEditor::ScriptTextEditor() { code_editor = memnew(CodeTextEditor); editor_box->add_child(code_editor); - code_editor->add_constant_override("separation", 0); + code_editor->add_constant_override("separation", 2); code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); code_editor->connect("validate_script", this, "_validate_script"); code_editor->connect("load_theme_settings", this, "_load_theme_settings"); @@ -1445,9 +1439,8 @@ ScriptTextEditor::ScriptTextEditor() { warnings_panel->set_focus_mode(FOCUS_CLICK); warnings_panel->hide(); - code_editor->get_error_label()->connect("gui_input", this, "_error_pressed"); - code_editor->get_warning_label()->connect("gui_input", this, "_toggle_warning_pannel"); - code_editor->get_warning_count_label()->connect("gui_input", this, "_toggle_warning_pannel"); + code_editor->connect("error_pressed", this, "_error_pressed"); + code_editor->connect("warning_pressed", this, "_toggle_warning_pannel"); warnings_panel->connect("meta_clicked", this, "_warning_clicked"); update_settings(); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 856e442d82..6e88fc2301 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -125,8 +125,8 @@ protected: void _code_complete_script(const String &p_code, List<String> *r_options, bool &r_force); void _load_theme_settings(); void _set_theme_for_script(); - void _toggle_warning_pannel(const Ref<InputEvent> &p_event); - void _error_pressed(const Ref<InputEvent> &p_event); + void _toggle_warning_pannel(); + void _error_pressed(); void _warning_clicked(Variant p_line); void _notification(int p_what); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 78bc989c5f..9ece812c49 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2865,6 +2865,18 @@ void SpatialEditorViewport::update_transform_gizmo_view() { Transform xform = spatial_editor->get_gizmo_transform(); Transform camera_xform = camera->get_transform(); + + if (xform.origin.distance_squared_to(camera_xform.origin) < 0.01) { + for (int i = 0; i < 3; i++) { + VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], false); + VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false); + VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false); + VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false); + VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); + } + return; + } + Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized(); Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized(); Plane p(camera_xform.origin, camz); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index b712cfc9d3..89bb7440fe 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -40,10 +40,8 @@ void SpriteFramesEditor::_gui_input(Ref<InputEvent> p_event) { void SpriteFramesEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_PHYSICS_PROCESS) { - } - if (p_what == NOTIFICATION_ENTER_TREE) { + load->set_icon(get_icon("Load", "EditorIcons")); copy->set_icon(get_icon("ActionCopy", "EditorIcons")); paste->set_icon(get_icon("ActionPaste", "EditorIcons")); @@ -54,14 +52,9 @@ void SpriteFramesEditor::_notification(int p_what) { _delete->set_icon(get_icon("Remove", "EditorIcons")); new_anim->set_icon(get_icon("New", "EditorIcons")); remove_anim->set_icon(get_icon("Remove", "EditorIcons")); - } - - if (p_what == NOTIFICATION_READY) { + } else if (p_what == NOTIFICATION_READY) { - //NodePath("/root")->connect("node_removed", this,"_node_removed",Vector<Variant>(),true); - } - - if (p_what == NOTIFICATION_DRAW) { + add_constant_override("autohide", 1); // Fixes the dragger always showing up. } } @@ -649,7 +642,6 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da void SpriteFramesEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &SpriteFramesEditor::_gui_input); ClassDB::bind_method(D_METHOD("_load_pressed"), &SpriteFramesEditor::_load_pressed); ClassDB::bind_method(D_METHOD("_empty_pressed"), &SpriteFramesEditor::_empty_pressed); ClassDB::bind_method(D_METHOD("_empty2_pressed"), &SpriteFramesEditor::_empty2_pressed); @@ -673,31 +665,25 @@ void SpriteFramesEditor::_bind_methods() { SpriteFramesEditor::SpriteFramesEditor() { - //add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("panel","Panel")); - - split = memnew(HSplitContainer); - add_child(split); - VBoxContainer *vbc_animlist = memnew(VBoxContainer); - split->add_child(vbc_animlist); + add_child(vbc_animlist); vbc_animlist->set_custom_minimum_size(Size2(150, 0) * EDSCALE); - //vbc_animlist->set_v_size_flags(SIZE_EXPAND_FILL); VBoxContainer *sub_vb = memnew(VBoxContainer); - vbc_animlist->add_margin_child(TTR("Animations"), sub_vb, true); + vbc_animlist->add_margin_child(TTR("Animations:"), sub_vb, true); sub_vb->set_v_size_flags(SIZE_EXPAND_FILL); HBoxContainer *hbc_animlist = memnew(HBoxContainer); sub_vb->add_child(hbc_animlist); - new_anim = memnew(Button); - new_anim->set_flat(true); + new_anim = memnew(ToolButton); + new_anim->set_tooltip(TTR("New Animation")); hbc_animlist->add_child(new_anim); new_anim->set_h_size_flags(SIZE_EXPAND_FILL); new_anim->connect("pressed", this, "_animation_add"); - remove_anim = memnew(Button); - remove_anim->set_flat(true); + remove_anim = memnew(ToolButton); + remove_anim->set_tooltip(TTR("Remove Animation")); hbc_animlist->add_child(remove_anim); remove_anim->connect("pressed", this, "_animation_remove"); @@ -722,56 +708,47 @@ SpriteFramesEditor::SpriteFramesEditor() { anim_loop->connect("pressed", this, "_animation_loop_changed"); VBoxContainer *vbc = memnew(VBoxContainer); - split->add_child(vbc); + add_child(vbc); vbc->set_h_size_flags(SIZE_EXPAND_FILL); sub_vb = memnew(VBoxContainer); - vbc->add_margin_child(TTR("Animation Frames"), sub_vb, true); + vbc->add_margin_child(TTR("Animation Frames:"), sub_vb, true); HBoxContainer *hbc = memnew(HBoxContainer); sub_vb->add_child(hbc); - //animations = memnew( ItemList ); - - load = memnew(Button); - load->set_flat(true); + load = memnew(ToolButton); load->set_tooltip(TTR("Load Resource")); hbc->add_child(load); - copy = memnew(Button); - copy->set_flat(true); + copy = memnew(ToolButton); copy->set_tooltip(TTR("Copy")); hbc->add_child(copy); - paste = memnew(Button); - paste->set_flat(true); + paste = memnew(ToolButton); paste->set_tooltip(TTR("Paste")); hbc->add_child(paste); - empty = memnew(Button); - empty->set_flat(true); + empty = memnew(ToolButton); empty->set_tooltip(TTR("Insert Empty (Before)")); hbc->add_child(empty); - empty2 = memnew(Button); - empty2->set_flat(true); + empty2 = memnew(ToolButton); empty2->set_tooltip(TTR("Insert Empty (After)")); hbc->add_child(empty2); hbc->add_spacer(false); - move_up = memnew(Button); - move_up->set_flat(true); + move_up = memnew(ToolButton); move_up->set_tooltip(TTR("Move (Before)")); hbc->add_child(move_up); - move_down = memnew(Button); - move_down->set_flat(true); + move_down = memnew(ToolButton); move_down->set_tooltip(TTR("Move (After)")); hbc->add_child(move_down); - _delete = memnew(Button); - _delete->set_flat(true); + _delete = memnew(ToolButton); + _delete->set_tooltip(TTR("Delete")); hbc->add_child(_delete); file = memnew(EditorFileDialog); @@ -787,7 +764,6 @@ SpriteFramesEditor::SpriteFramesEditor() { tree->set_fixed_column_width(thumbnail_size * 3 / 2); tree->set_max_text_lines(2); tree->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size)); - //tree->set_min_icon_size(Size2(thumbnail_size,thumbnail_size)); tree->set_drag_forwarding(this); sub_vb->add_child(tree); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 3ef4ba290b..55dd10074e 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -39,25 +39,25 @@ #include "scene/gui/split_container.h" #include "scene/gui/tree.h" -class SpriteFramesEditor : public PanelContainer { - - GDCLASS(SpriteFramesEditor, PanelContainer); - - Button *load; - Button *_delete; - Button *copy; - Button *paste; - Button *empty; - Button *empty2; - Button *move_up; - Button *move_down; +class SpriteFramesEditor : public HSplitContainer { + + GDCLASS(SpriteFramesEditor, HSplitContainer); + + ToolButton *load; + ToolButton *_delete; + ToolButton *copy; + ToolButton *paste; + ToolButton *empty; + ToolButton *empty2; + ToolButton *move_up; + ToolButton *move_down; ItemList *tree; bool loading_scene; int sel; HSplitContainer *split; - Button *new_anim; - Button *remove_anim; + ToolButton *new_anim; + ToolButton *remove_anim; Tree *animations; SpinBox *anim_speed; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 7ce4029476..e31851b3f1 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1526,6 +1526,13 @@ void ProjectManager::_open_selected_projects_ask() { } int config_version = (int)cf->get_value("", "config_version", 0); + + // Check if the config_version property was empty or 0 + if (config_version == 0) { + ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You will not be able to open the project with previous versions of the engine anymore."), conf)); + ask_update_settings->popup_centered_minsize(); + return; + } // Check if we need to convert project settings from an earlier engine version if (config_version < ProjectSettings::CONFIG_VERSION) { ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it?\nWarning: You will not be able to open the project with previous versions of the engine anymore."), conf)); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 7e4baa1533..6602d2974f 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -678,6 +678,11 @@ void SceneTreeEditor::_renamed() { error->set_text(TTR("Invalid node name, the following characters are not allowed:") + "\n" + Node::invalid_character); error->popup_centered_minsize(); + if (new_name.empty()) { + which->set_text(0, n->get_name()); + return; + } + which->set_text(0, new_name); } diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index f62391e436..268a765994 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -551,7 +551,10 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Transform t = spatial_node->get_global_transform(); t.orthonormalize(); - t.set_look_at(t.origin, p_camera->get_camera_transform().origin, Vector3(0, 1, 0)); + Vector3 camera_position = p_camera->get_camera_transform().origin; + if (camera_position.distance_squared_to(t.origin) > 0.01) { + t.set_look_at(t.origin, camera_position, Vector3(0, 1, 0)); + } float scale = t.origin.distance_to(p_camera->get_camera_transform().origin); @@ -563,16 +566,18 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Point2 center = p_camera->unproject_position(t.origin); - Transform oct = p_camera->get_camera_transform(); + Transform orig_camera_transform = p_camera->get_camera_transform(); - p_camera->look_at(t.origin, Vector3(0, 1, 0)); + if (orig_camera_transform.origin.distance_squared_to(t.origin) > 0.01) { + p_camera->look_at(t.origin, Vector3(0, 1, 0)); + } Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale); Vector3 c1 = t.xform(Vector3(-selectable_icon_size, -selectable_icon_size, 0) * scale); Point2 p0 = p_camera->unproject_position(c0); Point2 p1 = p_camera->unproject_position(c1); - p_camera->set_global_transform(oct); + p_camera->set_global_transform(orig_camera_transform); Rect2 rect(p0, p1 - p0); @@ -2409,8 +2414,8 @@ void ParticlesGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); ur->create_action(TTR("Change Particles AABB")); - ur->add_do_method(particles, "set_custom_aabb", particles->get_visibility_aabb()); - ur->add_undo_method(particles, "set_custom_aabb", p_restore); + ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb()); + ur->add_undo_method(particles, "set_visibility_aabb", p_restore); ur->commit_action(); } diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp index a082abcaba..f341159079 100644 --- a/main/tests/test_math.cpp +++ b/main/tests/test_math.cpp @@ -30,9 +30,9 @@ #include "test_math.h" +#include "core/math/basis.h" #include "core/math/camera_matrix.h" #include "core/math/math_funcs.h" -#include "core/math/matrix3.h" #include "core/math/transform.h" #include "core/os/file_access.h" #include "core/os/keyboard.h" diff --git a/methods.py b/methods.py index f8fc6c64ef..42eac7ca75 100644 --- a/methods.py +++ b/methods.py @@ -61,14 +61,22 @@ def update_version(module_version_string=""): # NOTE: It is safe to generate this file here, since this is still executed serially fhash = open("core/version_hash.gen.h", "w") githash = "" - if os.path.isfile(".git/HEAD"): - head = open(".git/HEAD", "r").readline().strip() + gitfolder = ".git" + + if os.path.isfile(".git"): + module_folder = open(".git", "r").readline().strip() + if module_folder.startswith("gitdir: "): + gitfolder = module_folder[8:] + + if os.path.isfile(os.path.join(gitfolder, "HEAD")): + head = open(os.path.join(gitfolder, "HEAD"), "r").readline().strip() if head.startswith("ref: "): - head = ".git/" + head[5:] + head = os.path.join(gitfolder, head[5:]) if os.path.isfile(head): githash = open(head, "r").readline().strip() else: githash = head + fhash.write("#define VERSION_HASH \"" + githash + "\"") fhash.close() diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub index 0416dd7f5f..7e714ba43f 100644 --- a/modules/bullet/SCsub +++ b/modules/bullet/SCsub @@ -187,8 +187,8 @@ if env['builtin_bullet']: thirdparty_sources = [thirdparty_dir + file for file in bullet2_src] env_bullet.Append(CPPPATH=[thirdparty_dir]) - if env['target'] == "debug" or env['target'] == "release_debug": - env_bullet.Append(CCFLAGS=['-DBT_DEBUG']) + # if env['target'] == "debug" or env['target'] == "release_debug": + # env_bullet.Append(CCFLAGS=['-DBT_DEBUG']) env_thirdparty = env_bullet.Clone() env_thirdparty.disable_warnings() diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h index 57c3300b3d..ba36331d07 100644 --- a/modules/bullet/bullet_types_converter.h +++ b/modules/bullet/bullet_types_converter.h @@ -31,7 +31,7 @@ #ifndef BULLET_TYPES_CONVERTER_H #define BULLET_TYPES_CONVERTER_H -#include "core/math/matrix3.h" +#include "core/math/basis.h" #include "core/math/transform.h" #include "core/math/vector3.h" #include "core/typedefs.h" diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 460ef043da..22f2214898 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -825,7 +825,8 @@ void RigidBodyBullet::reload_shapes() { // shapes incorrectly do not set the vector in calculateLocalIntertia. // Arbitrary zero is preferable to undefined behaviour. btVector3 inertia(0, 0, 0); - mainShape->calculateLocalInertia(mass, inertia); + if (EMPTY_SHAPE_PROXYTYPE != mainShape->getShapeType()) // Necessary to avoid assertion of the empty shape + mainShape->calculateLocalInertia(mass, inertia); btBody->setMassProps(mass, inertia); } btBody->updateInertiaTensor(); diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp index 4441a03ca1..d77c7d91ac 100644 --- a/modules/gdnative/gdnative/basis.cpp +++ b/modules/gdnative/gdnative/basis.cpp @@ -30,7 +30,7 @@ #include "gdnative/basis.h" -#include "core/math/matrix3.h" +#include "core/math/basis.h" #include "core/variant.h" #ifdef __cplusplus diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py index cd356ce513..5fd5971fd1 100644 --- a/modules/gdnative/gdnative_builders.py +++ b/modules/gdnative/gdnative_builders.py @@ -213,7 +213,7 @@ def _build_gdnative_api_struct_source(api): 'extern const godot_gdnative_core_api_struct api_struct = {', '\tGDNATIVE_' + api['core']['type'] + ',', '\t{' + str(api['core']['version']['major']) + ', ' + str(api['core']['version']['minor']) + '},', - '\tNULL,', + '\t(const godot_gdnative_api_struct *)&api_1_1,', '\t' + str(len(api['extensions'])) + ',', '\tgdnative_extensions_pointers,', ] diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 966c02d4ec..98871ddec3 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -1083,7 +1083,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (argc >= 1) { methodstr = String(*argptrs[0]) + " (via call)"; if (err.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { - err.argument -= 1; + err.argument += 1; } } } else if (methodstr == "free") { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index af189fdb7e..7334e8a8cc 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3494,16 +3494,20 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); if ((tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type() == Variant::STRING)) { - Variant constant = tokenizer->get_token_constant(); - String icon_path = constant.operator String(); +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + Variant constant = tokenizer->get_token_constant(); + String icon_path = constant.operator String(); - String abs_icon_path = icon_path.is_rel_path() ? self_path.get_base_dir().plus_file(icon_path).simplify_path() : icon_path; - if (!FileAccess::exists(abs_icon_path)) { - _set_error("No class icon found at: " + abs_icon_path); - return; - } + String abs_icon_path = icon_path.is_rel_path() ? self_path.get_base_dir().plus_file(icon_path).simplify_path() : icon_path; + if (!FileAccess::exists(abs_icon_path)) { + _set_error("No class icon found at: " + abs_icon_path); + return; + } - p_class->icon_path = icon_path; + p_class->icon_path = icon_path; + } +#endif tokenizer->advance(); } else { diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 0b21ba3347..5da1344595 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -139,14 +139,24 @@ void CSharpLanguage::finish() { } #endif - // Release gchandle bindings before finalizing mono runtime - script_bindings.clear(); + // Make sure all script binding gchandles are released before finalizing GDMono + for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { + CSharpScriptBinding &script_binding = E->value(); + + if (script_binding.gchandle.is_valid()) { + script_binding.gchandle->release(); + script_binding.inited = false; + } + } if (gdmono) { memdelete(gdmono); gdmono = NULL; } + // Clear here, after finalizing all domains to make sure there is nothing else referencing the elements. + script_bindings.clear(); + finalizing = false; } @@ -578,7 +588,7 @@ void CSharpLanguage::frame() { if (exc) { GDMonoUtils::debug_unhandled_exception(exc); - _UNREACHABLE_(); + GD_UNREACHABLE(); } } } @@ -1054,12 +1064,14 @@ CSharpLanguage::~CSharpLanguage() { singleton = NULL; } -void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) { +bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object) { #ifdef DEBUG_ENABLED // I don't trust you - if (p_object->get_script_instance()) - CRASH_COND(NULL != CAST_CSHARP_INSTANCE(p_object->get_script_instance())); + if (p_object->get_script_instance()) { + CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance()); + CRASH_COND(csharp_instance != NULL && !csharp_instance->is_destructing_script_instance()); + } #endif StringName type_name = p_object->get_class_name(); @@ -1068,29 +1080,21 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) { const ClassDB::ClassInfo *classinfo = ClassDB::classes.getptr(type_name); while (classinfo && !classinfo->exposed) classinfo = classinfo->inherits_ptr; - ERR_FAIL_NULL_V(classinfo, NULL); + ERR_FAIL_NULL_V(classinfo, false); type_name = classinfo->name; GDMonoClass *type_class = GDMonoUtils::type_get_proxy_class(type_name); - ERR_FAIL_NULL_V(type_class, NULL); + ERR_FAIL_NULL_V(type_class, false); MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(type_class, type_name, p_object); - ERR_FAIL_NULL_V(mono_object, NULL); - - CSharpScriptBinding script_binding; - - script_binding.type_name = type_name; - script_binding.wrapper_class = type_class; // cache - script_binding.gchandle = MonoGCHandle::create_strong(mono_object); + ERR_FAIL_NULL_V(mono_object, false); - void *data; - - { - SCOPED_MUTEX_LOCK(language_bind_mutex); - data = (void *)script_bindings.insert(p_object, script_binding); - } + r_script_binding.inited = true; + r_script_binding.type_name = type_name; + r_script_binding.wrapper_class = type_class; // cache + r_script_binding.gchandle = MonoGCHandle::create_strong(mono_object); // Tie managed to unmanaged Reference *ref = Object::cast_to<Reference>(p_object); @@ -1104,6 +1108,23 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) { ref->reference(); } + return true; +} + +void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) { + + CSharpScriptBinding script_binding; + + if (!setup_csharp_script_binding(script_binding, p_object)) + return NULL; + + void *data; + + { + SCOPED_MUTEX_LOCK(language_bind_mutex); + data = (void *)script_bindings.insert(p_object, script_binding); + } + return data; } @@ -1125,10 +1146,15 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) { Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data; - // Set the native instance field to IntPtr.Zero, if not yet garbage collected - MonoObject *mono_object = data->value().gchandle->get_target(); - if (mono_object) { - CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL); + CSharpScriptBinding &script_binding = data->value(); + + if (script_binding.inited) { + // Set the native instance field to IntPtr.Zero, if not yet garbage collected. + // This is done to avoid trying to dispose the native instance from Dispose(bool). + MonoObject *mono_object = script_binding.gchandle->get_target(); + if (mono_object) { + CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL); + } } script_bindings.erase(data); @@ -1144,9 +1170,10 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { #endif void *data = p_object->get_script_instance_binding(get_language_index()); - if (!data) - return; - Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle; + CRASH_COND(!data); + + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + Ref<MonoGCHandle> &gchandle = script_binding.gchandle; if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 // The reference count was increased after the managed side was the only one referencing our owner. @@ -1175,9 +1202,10 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { int refcount = ref_owner->reference_get_count(); void *data = p_object->get_script_instance_binding(get_language_index()); - if (!data) - return refcount == 0; - Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle; + CRASH_COND(!data); + + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + Ref<MonoGCHandle> &gchandle = script_binding.gchandle; if (refcount == 1 && gchandle.is_valid() && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 // If owner owner is no longer referenced by the unmanaged side, @@ -1223,6 +1251,10 @@ MonoObject *CSharpInstance::get_mono_object() const { return gchandle->get_target(); } +Object *CSharpInstance::get_owner() { + return owner; +} + bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND_V(!script.is_valid(), false); @@ -1483,14 +1515,8 @@ bool CSharpInstance::_unreference_owner_unsafe() { // Unsafe refcount decrement. The managed instance also counts as a reference. // See: _reference_owner_unsafe() - bool die = static_cast<Reference *>(owner)->unreference(); - - if (die) { - memdelete(owner); - owner = NULL; - } - - return die; + // Destroying the owner here means self destructing, so we defer the owner destruction to the caller. + return static_cast<Reference *>(owner)->unreference(); } MonoObject *CSharpInstance::_internal_new_managed() { @@ -1503,27 +1529,33 @@ MonoObject *CSharpInstance::_internal_new_managed() { ERR_FAIL_NULL_V(owner, NULL); ERR_FAIL_COND_V(script.is_null(), NULL); - if (base_ref) - _reference_owner_unsafe(); - MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, script->script_class->get_mono_ptr()); if (!mono_object) { + // Important to clear this before destroying the script instance here script = Ref<CSharpScript>(); - owner->set_script_instance(NULL); + owner = NULL; + + bool die = _unreference_owner_unsafe(); + // Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug. + CRASH_COND(die == true); + ERR_EXPLAIN("Failed to allocate memory for the object"); ERR_FAIL_V(NULL); } + // Tie managed to unmanaged + gchandle = MonoGCHandle::create_strong(mono_object); + + if (base_ref) + _reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback) + CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, owner); // Construct GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0); ctor->invoke_raw(mono_object, NULL); - // Tie managed to unmanaged - gchandle = MonoGCHandle::create_strong(mono_object); - return mono_object; } @@ -1536,25 +1568,36 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) { CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle); } -void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted) { +void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) { #ifdef DEBUG_ENABLED CRASH_COND(!base_ref); CRASH_COND(gchandle.is_null()); #endif + + r_remove_script_instance = false; + if (_unreference_owner_unsafe()) { - r_owner_deleted = true; + // Safe to self destruct here with memdelete(owner), but it's deferred to the caller to prevent future mistakes. + r_delete_owner = true; } else { - r_owner_deleted = false; + r_delete_owner = false; CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle); - if (p_is_finalizer && !GDMono::get_singleton()->is_finalizing_scripts_domain()) { - // If the native instance is still alive, then it was - // referenced from another thread before the finalizer could - // unreference it and delete it, so we want to keep it. - // GC.ReRegisterForFinalize(this) is not safe because the objects - // referenced by this could have already been collected. - // Instead we will create a new managed instance here. - _internal_new_managed(); + + if (!p_is_finalizer) { + // If the native instance is still alive and Dispose() was called + // (instead of the finalizer), then we remove the script instance. + r_remove_script_instance = true; + } else if (!GDMono::get_singleton()->is_finalizing_scripts_domain()) { + // If the native instance is still alive and this is called from the finalizer, + // then it was referenced from another thread before the finalizer could + // unreference and delete it, so we want to keep it. + // GC.ReRegisterForFinalize(this) is not safe because the objects referenced by 'this' + // could have already been collected. Instead we will create a new managed instance here. + MonoObject *new_managed = _internal_new_managed(); + if (!new_managed) { + r_remove_script_instance = true; + } } } } @@ -1608,7 +1651,7 @@ bool CSharpInstance::refcount_decremented() { return ref_dying; } -MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(GDMonoClassMember *p_member) const { +MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(IMonoClassMember *p_member) const { if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute))) return MultiplayerAPI::RPC_MODE_REMOTE; @@ -1750,6 +1793,8 @@ CSharpInstance::CSharpInstance() : CSharpInstance::~CSharpInstance() { + destructing_script_instance = true; + if (gchandle.is_valid()) { if (!predelete_notified && !ref_dying) { // This destructor is not called from the owners destructor. @@ -1762,9 +1807,7 @@ CSharpInstance::~CSharpInstance() { if (mono_object) { MonoException *exc = NULL; - destructing_script_instance = true; GDMonoUtils::dispose(mono_object, &exc); - destructing_script_instance = false; if (exc) { GDMonoUtils::set_pending_exception(exc); @@ -1772,11 +1815,23 @@ CSharpInstance::~CSharpInstance() { } } - gchandle->release(); // Make sure it's released + gchandle->release(); // Make sure the gchandle is released } - if (base_ref && !ref_dying && owner) { // it may be called from the owner's destructor - _unreference_owner_unsafe(); + // If not being called from the owner's destructor, and we still hold a reference to the owner + if (base_ref && !ref_dying && owner && unsafe_referenced) { + // The owner's script or script instance is being replaced (or removed) + + // Transfer ownership to an "instance binding" + + void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + CRASH_COND(data == NULL); + + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + CRASH_COND(!script_binding.inited); + + bool die = _unreference_owner_unsafe(); + CRASH_COND(die == true); // The "instance binding" should be holding a reference } if (script.is_valid() && owner) { @@ -2019,7 +2074,7 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve * Returns false if there was an error, otherwise true. * If there was an error, r_prop_info and r_exported are not assigned any value. */ -bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) { +bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) { StringName name = p_member->get_name(); @@ -2034,9 +2089,9 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p ManagedType type; - if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_FIELD) { + if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_FIELD) { type = static_cast<GDMonoField *>(p_member)->get_type(); - } else if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_PROPERTY) { + } else if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) { type = static_cast<GDMonoProperty *>(p_member)->get_type(); } else { CRASH_NOW(); @@ -2050,7 +2105,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p return true; } - if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_PROPERTY) { + if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) { GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member); if (!property->has_getter() || !property->has_setter()) { ERR_PRINTS("Cannot export property because it does not provide a getter or a setter: " + p_class->get_full_name() + "." + name.operator String()); @@ -2327,6 +2382,32 @@ StringName CSharpScript::get_instance_base_type() const { CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) { /* STEP 1, CREATE */ + Ref<Reference> ref; + if (p_isref) { + // Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance. + ref = Ref<Reference>(static_cast<Reference *>(p_owner)); + } + + // If the object had a script instance binding, dispose it before adding the CSharpInstance + if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) { + void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + CRASH_COND(data == NULL); + + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + if (script_binding.inited && script_binding.gchandle.is_valid()) { + MonoObject *mono_object = script_binding.gchandle->get_target(); + if (mono_object) { + MonoException *exc = NULL; + GDMonoUtils::dispose(mono_object, &exc); + + if (exc) { + GDMonoUtils::set_pending_exception(exc); + } + } + + script_binding.inited = false; + } + } CSharpInstance *instance = memnew(CSharpInstance); instance->base_ref = p_isref; @@ -2334,16 +2415,20 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg instance->owner = p_owner; instance->owner->set_script_instance(instance); - if (instance->base_ref) - instance->_reference_owner_unsafe(); - /* STEP 2, INITIALIZE AND CONSTRUCT */ MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_mono_ptr()); if (!mono_object) { + // Important to clear this before destroying the script instance here instance->script = Ref<CSharpScript>(); - instance->owner->set_script_instance(NULL); + instance->owner = NULL; + + bool die = instance->_unreference_owner_unsafe(); + // Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug. + CRASH_COND(die == true); + + p_owner->set_script_instance(NULL); r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; ERR_EXPLAIN("Failed to allocate memory for the object"); ERR_FAIL_V(NULL); @@ -2352,6 +2437,9 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg // Tie managed to unmanaged instance->gchandle = MonoGCHandle::create_strong(mono_object); + if (instance->base_ref) + instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback) + { SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex); instances.insert(instance->owner); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 8a09be79a6..db9d6a73a2 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -127,7 +127,7 @@ class CSharpScript : public Script { bool _update_exports(); #ifdef TOOLS_ENABLED - bool _get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported); + bool _get_member_export(GDMonoClass *p_class, IMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported); #endif CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error); @@ -206,8 +206,15 @@ class CSharpInstance : public ScriptInstance { Ref<MonoGCHandle> gchandle; bool _reference_owner_unsafe(); + + /* + * If true is returned, the caller must memdelete the script instance's owner. + */ bool _unreference_owner_unsafe(); + /* + * If NULL is returned, the caller must destroy the script instance by removing it from its owner. + */ MonoObject *_internal_new_managed(); // Do not use unless you know what you are doing @@ -216,13 +223,15 @@ class CSharpInstance : public ScriptInstance { void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount); - MultiplayerAPI::RPCMode _member_get_rpc_mode(GDMonoClassMember *p_member) const; + MultiplayerAPI::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const; public: MonoObject *get_mono_object() const; _FORCE_INLINE_ bool is_destructing_script_instance() { return destructing_script_instance; } + virtual Object *get_owner(); + virtual bool set(const StringName &p_name, const Variant &p_value); virtual bool get(const StringName &p_name, Variant &r_ret) const; virtual void get_property_list(List<PropertyInfo> *p_properties) const; @@ -235,7 +244,12 @@ public: virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); void mono_object_disposed(MonoObject *p_obj); - void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted); + + /* + * If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, if + * 'r_remove_script_instance' is set to true, the caller must destroy the script instance by removing it from its owner. + */ + void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance); virtual void refcount_incremented(); virtual bool refcount_decremented(); @@ -255,6 +269,7 @@ public: }; struct CSharpScriptBinding { + bool inited; StringName type_name; GDMonoClass *wrapper_class; Ref<MonoGCHandle> gchandle; @@ -391,6 +406,8 @@ public: virtual void refcount_incremented_instance_binding(Object *p_object); virtual bool refcount_decremented_instance_binding(Object *p_object); + bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object); + #ifdef DEBUG_ENABLED Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace); #endif diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj index f9e9f41977..9a5dd24bb1 100644 --- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj +++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj @@ -8,6 +8,7 @@ <RootNamespace>GodotSharpTools</RootNamespace> <AssemblyName>GodotSharpTools</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <BaseIntermediateOutputPath>obj</BaseIntermediateOutputPath> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 5d9f4d8d54..a040e4a344 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -517,7 +517,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) { // Remove old issues file - String issues_file = "msbuild_issues.csv"; + String issues_file = get_msbuild_issues_filename(); DirAccessRef d = DirAccess::create_for_path(log_dirpath); if (d->file_exists(issues_file)) { Error err = d->remove(issues_file); @@ -584,7 +584,8 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) { exit_code = klass->get_field("exitCode")->get_int_value(mono_object); if (exit_code != 0) { - print_verbose("MSBuild finished with exit code " + itos(exit_code)); + String log_filepath = build_info.get_log_dirpath().plus_file(get_msbuild_log_filename()); + print_verbose("MSBuild exited with code: " + itos(exit_code) + ". Log file: " + log_filepath); } build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR); diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h index 2d53583916..652d30538a 100644 --- a/modules/mono/editor/godotsharp_builds.h +++ b/modules/mono/editor/godotsharp_builds.h @@ -76,6 +76,9 @@ public: static void show_build_error_dialog(const String &p_message); + static const char *get_msbuild_issues_filename() { return "msbuild_issues.csv"; } + static const char *get_msbuild_log_filename() { return "msbuild_log.txt"; } + void build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code); void restart_build(MonoBuildTab *p_build_tab); diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index cee4405826..ee93229700 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -30,6 +30,7 @@ #include "godotsharp_editor.h" +#include "core/message_queue.h" #include "core/os/os.h" #include "core/project_settings.h" #include "scene/gui/control.h" @@ -114,10 +115,33 @@ bool GodotSharpEditor::_create_project_solution() { void GodotSharpEditor::_make_api_solutions_if_needed() { // I'm sick entirely of ProgressDialog + + static int attempts_left = 100; + + if (MessageQueue::get_singleton()->is_flushing() || !SceneTree::get_singleton()) { + ERR_FAIL_COND(attempts_left == 0); // You've got to be kidding + + if (SceneTree::get_singleton()) { + SceneTree::get_singleton()->connect("idle_frame", this, "_make_api_solutions_if_needed", Vector<Variant>()); + } else { + call_deferred("_make_api_solutions_if_needed"); + } + + attempts_left--; + return; + } + + // Recursion guard needed because signals don't play well with ProgressDialog either, but unlike + // the message queue, with signals the collateral damage should be minimal in the worst case. static bool recursion_guard = false; if (!recursion_guard) { recursion_guard = true; + + // Oneshot signals don't play well with ProgressDialog either, so we do it this way instead + SceneTree::get_singleton()->disconnect("idle_frame", this, "_make_api_solutions_if_needed"); + _make_api_solutions_if_needed_impl(); + recursion_guard = false; } } @@ -434,7 +458,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { String csproj_path = GodotSharpDirs::get_project_csproj_path(); if (FileAccess::exists(sln_path) && FileAccess::exists(csproj_path)) { - // We can't use EditorProgress here. It calls Main::iterarion() and the main loop is not initialized yet. + // Defer this task because EditorProgress calls Main::iterarion() and the main loop is not yet initialized. call_deferred("_make_api_solutions_if_needed"); } else { bottom_panel_btn->hide(); @@ -452,7 +476,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { EditorSettings *ed_settings = EditorSettings::get_singleton(); EDITOR_DEF("mono/editor/external_editor", EDITOR_NONE); - String settings_hint_str = "None"; + String settings_hint_str = "Disabled"; #ifdef WINDOWS_ENABLED settings_hint_str += ",MonoDevelop,Visual Studio Code"; diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp index 55a334bc4e..cc9822e319 100644 --- a/modules/mono/editor/mono_bottom_panel.cpp +++ b/modules/mono/editor/mono_bottom_panel.cpp @@ -156,10 +156,20 @@ void MonoBottomPanel::_build_project_pressed() { if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) return; // No solution to build - String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor"); - Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path); + String scripts_metadata_path_editor = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor"); + String scripts_metadata_path_player = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor_player"); + + Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor); ERR_FAIL_COND(metadata_err != OK); + if (FileAccess::exists(scripts_metadata_path_editor)) { + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player); + + ERR_EXPLAIN("Failed to copy scripts metadata file"); + ERR_FAIL_COND(copy_err != OK); + } + bool build_success = GodotSharpBuilds::get_singleton()->build_project_blocking("Tools"); if (build_success) { @@ -187,7 +197,7 @@ void MonoBottomPanel::_view_log_pressed() { String log_dirpath = build_tab->get_build_info().get_log_dirpath(); - OS::get_singleton()->shell_open(log_dirpath.plus_file("msbuild_log.txt")); + OS::get_singleton()->shell_open(log_dirpath.plus_file(GodotSharpBuilds::get_msbuild_log_filename())); } } @@ -421,7 +431,7 @@ void MonoBuildTab::on_build_exit(BuildResult result) { build_exited = true; build_result = result; - _load_issues_from_file(logs_dir.plus_file("msbuild_issues.csv")); + _load_issues_from_file(logs_dir.plus_file(GodotSharpBuilds::get_msbuild_issues_filename())); _update_issues_list(); MonoBottomPanel::get_singleton()->raise_build_tab(this); diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 88adc3e256..2963619b79 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -65,9 +65,12 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { - Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle; - if (gchandle.is_valid()) { - CSharpLanguage::release_script_gchandle(p_obj, gchandle); + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + if (script_binding.inited) { + Ref<MonoGCHandle> &gchandle = script_binding.gchandle; + if (gchandle.is_valid()) { + CSharpLanguage::release_script_gchandle(p_obj, gchandle); + } } } } @@ -85,11 +88,14 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance()); if (cs_instance) { if (!cs_instance->is_destructing_script_instance()) { - bool r_owner_deleted; - cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, r_owner_deleted); - if (!r_owner_deleted && !p_is_finalizer) { - // If the native instance is still alive and Dispose() was called - // (instead of the finalizer), then we remove the script instance. + bool delete_owner; + bool remove_script_instance; + + cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance); + + if (delete_owner) { + memdelete(ref); + } else if (remove_script_instance) { ref->set_script_instance(NULL); } } @@ -105,9 +111,12 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_ void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { - Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle; - if (gchandle.is_valid()) { - CSharpLanguage::release_script_gchandle(p_obj, gchandle); + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + if (script_binding.inited) { + Ref<MonoGCHandle> &gchandle = script_binding.gchandle; + if (gchandle.is_valid()) { + CSharpLanguage::release_script_gchandle(p_obj, gchandle); + } } } } @@ -138,7 +147,7 @@ MonoObject *godot_icall_Object_weakref(Object *p_obj) { wref->set_obj(p_obj); } - return GDMonoUtils::create_managed_for_godot_object(CACHED_CLASS(WeakRef), Reference::get_class_static(), Object::cast_to<Object>(wref.ptr())); + return GDMonoUtils::unmanaged_get_managed(wref.ptr()); } Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter) { diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp index b6c9b5f7dd..a9e2136a19 100644 --- a/modules/mono/mono_gc_handle.cpp +++ b/modules/mono/mono_gc_handle.cpp @@ -65,7 +65,7 @@ Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) { void MonoGCHandle::release() { #ifdef DEBUG_ENABLED - CRASH_COND(GDMono::get_singleton() == NULL); + CRASH_COND(!released && GDMono::get_singleton() == NULL); #endif if (!released && GDMono::get_singleton()->is_runtime_initialized()) { diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 900caefe1c..ca1ff9f9ff 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -54,17 +54,6 @@ #include "main/main.h" #endif -#ifdef MONO_PRINT_HANDLER_ENABLED -void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) { - - if (is_stdout) { - OS::get_singleton()->print(string); - } else { - OS::get_singleton()->printerr(string); - } -} -#endif - GDMono *GDMono::singleton = NULL; namespace { @@ -132,7 +121,7 @@ void gdmono_debug_init() { CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8(); - if (da_args == "") { + if (da_args.length() == 0) { da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) + ",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n")) .utf8(); @@ -150,6 +139,40 @@ void gdmono_debug_init() { } // namespace +void GDMono::add_mono_shared_libs_dir_to_path() { + // By default Mono seems to search shared libraries in the following directories: + // Current working directory, @executable_path@ and PATH + // The parent directory of the image file (assembly where the dllimport method is declared) + // @executable_path@/../lib + // @executable_path@/../Libraries (__MACH__ only) + + // This does not work when embedding Mono unless we use the same directory structure. + // To fix this we append the directory containing our shared libraries to PATH. + +#if defined(WINDOWS_ENABLED) || defined(UNIX_ENABLED) + String path_var("PATH"); + String path_value = OS::get_singleton()->get_environment(path_var); + +#ifdef WINDOWS_ENABLED + path_value += ';'; + + String bundled_bin_dir = GodotSharpDirs::get_data_mono_bin_dir(); + path_value += DirAccess::exists(bundled_bin_dir) ? bundled_bin_dir : mono_reg_info.bin_dir; +#else + path_value += ':'; + + String bundled_lib_dir = GodotSharpDirs::get_data_mono_lib_dir(); + if (DirAccess::exists(bundled_lib_dir)) { + path_value += bundled_lib_dir; + } else { + // TODO: Do we need to add the lib dir when using the system installed Mono on Unix platforms? + } +#endif + + OS::get_singleton()->set_environment(path_var, path_value); +#endif +} + void GDMono::initialize() { ERR_FAIL_NULL(Engine::get_singleton()); @@ -162,11 +185,6 @@ void GDMono::initialize() { GDMonoLog::get_singleton()->initialize(); -#ifdef MONO_PRINT_HANDLER_ENABLED - mono_trace_set_print_handler(gdmono_MonoPrintCallback); - mono_trace_set_printerr_handler(gdmono_MonoPrintCallback); -#endif - String assembly_rootdir; String config_dir; @@ -223,6 +241,8 @@ void GDMono::initialize() { mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL, config_dir.length() ? config_dir.utf8().get_data() : NULL); + add_mono_shared_libs_dir_to_path(); + GDMonoAssembly::initialize(); #ifdef DEBUG_ENABLED @@ -327,7 +347,7 @@ namespace GodotSharpBindings { uint64_t get_core_api_hash(); #ifdef TOOLS_ENABLED uint64_t get_editor_api_hash(); -#endif // TOOLS_ENABLED +#endif uint32_t get_bindings_version(); void register_generated_icalls(); @@ -344,29 +364,20 @@ void GDMono::_register_internal_calls() { #endif } -#ifdef DEBUG_METHODS_ENABLED void GDMono::_initialize_and_check_api_hashes() { - api_core_hash = ClassDB::get_api_hash(ClassDB::API_CORE); - #ifdef MONO_GLUE_ENABLED - if (api_core_hash != GodotSharpBindings::get_core_api_hash()) { + if (get_api_core_hash() != GodotSharpBindings::get_core_api_hash()) { ERR_PRINT("Mono: Core API hash mismatch!"); } -#endif #ifdef TOOLS_ENABLED - api_editor_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); - -#ifdef MONO_GLUE_ENABLED - if (api_editor_hash != GodotSharpBindings::get_editor_api_hash()) { + if (get_api_editor_hash() != GodotSharpBindings::get_editor_api_hash()) { ERR_PRINT("Mono: Editor API hash mismatch!"); } -#endif - #endif // TOOLS_ENABLED +#endif // MONO_GLUE_ENABLED } -#endif // DEBUG_METHODS_ENABLED void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) { @@ -915,7 +926,7 @@ void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) { ScriptDebugger::get_singleton()->idle_poll(); #endif abort(); - _UNREACHABLE_(); + GD_UNREACHABLE(); } GDMono::GDMono() { @@ -946,12 +957,10 @@ GDMono::GDMono() { editor_tools_assembly = NULL; #endif -#ifdef DEBUG_METHODS_ENABLED api_core_hash = 0; #ifdef TOOLS_ENABLED api_editor_hash = 0; #endif -#endif } GDMono::~GDMono() { @@ -1074,17 +1083,9 @@ void _GodotSharp::_bind_methods() { _GodotSharp::_GodotSharp() { singleton = this; - queue_empty = true; -#ifndef NO_THREADS - queue_mutex = Mutex::create(); -#endif } _GodotSharp::~_GodotSharp() { singleton = NULL; - - if (queue_mutex) { - memdelete(queue_mutex); - } } diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 13de3061b3..785b65ce13 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -134,13 +134,11 @@ class GDMono { Error _load_tools_domain(); #endif -#ifdef DEBUG_METHODS_ENABLED uint64_t api_core_hash; #ifdef TOOLS_ENABLED uint64_t api_editor_hash; #endif void _initialize_and_check_api_hashes(); -#endif GDMonoLog *gdmono_log; @@ -148,15 +146,23 @@ class GDMono { MonoRegInfo mono_reg_info; #endif + void add_mono_shared_libs_dir_to_path(); + protected: static GDMono *singleton; public: -#ifdef DEBUG_METHODS_ENABLED - uint64_t get_api_core_hash() { return api_core_hash; } + uint64_t get_api_core_hash() { + if (api_core_hash == 0) + api_core_hash = ClassDB::get_api_hash(ClassDB::API_CORE); + return api_core_hash; + } #ifdef TOOLS_ENABLED - uint64_t get_api_editor_hash() { return api_editor_hash; } -#endif + uint64_t get_api_editor_hash() { + if (api_editor_hash == 0) + api_editor_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); + return api_editor_hash; + } #endif #ifdef TOOLS_ENABLED @@ -268,12 +274,6 @@ class _GodotSharp : public Object { List<NodePath *> np_delete_queue; List<RID *> rid_delete_queue; - bool queue_empty; - -#ifndef NO_THREADS - Mutex *queue_mutex; -#endif - protected: static _GodotSharp *singleton; static void _bind_methods(); diff --git a/modules/mono/mono_gd/gd_mono_class_member.h b/modules/mono/mono_gd/gd_mono_class_member.h index 5bd21178ba..3058b18c05 100644 --- a/modules/mono/mono_gd/gd_mono_class_member.h +++ b/modules/mono/mono_gd/gd_mono_class_member.h @@ -35,7 +35,7 @@ #include <mono/metadata/object.h> -class GDMonoClassMember { +class IMonoClassMember { public: enum Visibility { PRIVATE, @@ -51,7 +51,7 @@ public: MEMBER_TYPE_METHOD }; - virtual ~GDMonoClassMember() {} + virtual ~IMonoClassMember() {} virtual MemberType get_member_type() = 0; diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index a9d993412e..48fa380456 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -505,20 +505,20 @@ bool GDMonoField::is_static() { return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC; } -GDMonoClassMember::Visibility GDMonoField::get_visibility() { +IMonoClassMember::Visibility GDMonoField::get_visibility() { switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) { case MONO_FIELD_ATTR_PRIVATE: - return GDMonoClassMember::PRIVATE; + return IMonoClassMember::PRIVATE; case MONO_FIELD_ATTR_FAM_AND_ASSEM: - return GDMonoClassMember::PROTECTED_AND_INTERNAL; + return IMonoClassMember::PROTECTED_AND_INTERNAL; case MONO_FIELD_ATTR_ASSEMBLY: - return GDMonoClassMember::INTERNAL; + return IMonoClassMember::INTERNAL; case MONO_FIELD_ATTR_FAMILY: - return GDMonoClassMember::PROTECTED; + return IMonoClassMember::PROTECTED; case MONO_FIELD_ATTR_PUBLIC: - return GDMonoClassMember::PUBLIC; + return IMonoClassMember::PUBLIC; default: - ERR_FAIL_V(GDMonoClassMember::PRIVATE); + ERR_FAIL_V(IMonoClassMember::PRIVATE); } } diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h index 319e895ab9..a3244101d8 100644 --- a/modules/mono/mono_gd/gd_mono_field.h +++ b/modules/mono/mono_gd/gd_mono_field.h @@ -35,7 +35,7 @@ #include "gd_mono_class_member.h" #include "gd_mono_header.h" -class GDMonoField : public GDMonoClassMember { +class GDMonoField : public IMonoClassMember { GDMonoClass *owner; MonoClassField *mono_field; @@ -47,15 +47,15 @@ class GDMonoField : public GDMonoClassMember { MonoCustomAttrInfo *attributes; public: - virtual MemberType get_member_type() { return MEMBER_TYPE_FIELD; } + virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_FIELD; } - virtual StringName get_name() { return name; } + virtual StringName get_name() GD_FINAL { return name; } - virtual bool is_static(); - virtual Visibility get_visibility(); + virtual bool is_static() GD_FINAL; + virtual Visibility get_visibility() GD_FINAL; - virtual bool has_attribute(GDMonoClass *p_attr_class); - virtual MonoObject *get_attribute(GDMonoClass *p_attr_class); + virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL; + virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL; void fetch_attributes(); _FORCE_INLINE_ ManagedType get_type() const { return type; } diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h index 23306d11b9..dd8c047386 100644 --- a/modules/mono/mono_gd/gd_mono_header.h +++ b/modules/mono/mono_gd/gd_mono_header.h @@ -35,7 +35,7 @@ class GDMonoAssembly; class GDMonoClass; -class GDMonoClassMember; +class IMonoClassMember; class GDMonoField; class GDMonoProperty; class GDMonoMethod; diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp index 0574b0025d..0daa394e63 100644 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ b/modules/mono/mono_gd/gd_mono_internals.cpp @@ -72,7 +72,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { void unhandled_exception(MonoException *p_exc) { mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well abort(); - _UNREACHABLE_(); + GD_UNREACHABLE(); } } // namespace GDMonoInternals diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h index 09cb59ee6b..2d77bde27c 100644 --- a/modules/mono/mono_gd/gd_mono_internals.h +++ b/modules/mono/mono_gd/gd_mono_internals.h @@ -45,7 +45,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged); * Do not call this function directly. * Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead. */ -_NO_RETURN_ void unhandled_exception(MonoException *p_exc); +GD_NORETURN void unhandled_exception(MonoException *p_exc); } // namespace GDMonoInternals diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index fa4850ca8c..ec89df1959 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -52,7 +52,7 @@ static int log_level_get_id(const char *p_log_level) { return -1; } -void gdmono_MonoLogCallback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) { +static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) { FileAccess *f = GDMonoLog::get_singleton()->get_log_file(); @@ -153,7 +153,7 @@ void GDMonoLog::initialize() { if (log_file) { print_verbose("Mono: Logfile is " + log_file_path); - mono_trace_set_log_handler(gdmono_MonoLogCallback, this); + mono_trace_set_log_handler(mono_log_callback, this); } else { OS::get_singleton()->printerr("Mono: No log file, using default log handler\n"); } diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 5e2deea43c..4f86e02f87 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -206,9 +206,10 @@ enum { // In the future we may force this if we want to ref return these structs #ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY -// Sometimes clang-format can be an ass -GD_STATIC_ASSERT(MATCHES_Vector2 &&MATCHES_Rect2 &&MATCHES_Transform2D &&MATCHES_Vector3 && - MATCHES_Basis &&MATCHES_Quat &&MATCHES_Transform &&MATCHES_AABB &&MATCHES_Color &&MATCHES_Plane); +/* clang-format off */ +GD_STATIC_ASSERT(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 && + MATCHES_Basis && MATCHES_Quat && MATCHES_Transform && MATCHES_AABB && MATCHES_Color &&MATCHES_Plane); +/* clang-format on */ #endif } // namespace InteropLayout diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 071d852ce7..7f11e4671d 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -78,20 +78,20 @@ bool GDMonoMethod::is_static() { return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC; } -GDMonoClassMember::Visibility GDMonoMethod::get_visibility() { +IMonoClassMember::Visibility GDMonoMethod::get_visibility() { switch (mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) { case MONO_METHOD_ATTR_PRIVATE: - return GDMonoClassMember::PRIVATE; + return IMonoClassMember::PRIVATE; case MONO_METHOD_ATTR_FAM_AND_ASSEM: - return GDMonoClassMember::PROTECTED_AND_INTERNAL; + return IMonoClassMember::PROTECTED_AND_INTERNAL; case MONO_METHOD_ATTR_ASSEM: - return GDMonoClassMember::INTERNAL; + return IMonoClassMember::INTERNAL; case MONO_METHOD_ATTR_FAMILY: - return GDMonoClassMember::PROTECTED; + return IMonoClassMember::PROTECTED; case MONO_METHOD_ATTR_PUBLIC: - return GDMonoClassMember::PUBLIC; + return IMonoClassMember::PUBLIC; default: - ERR_FAIL_V(GDMonoClassMember::PRIVATE); + ERR_FAIL_V(IMonoClassMember::PRIVATE); } } diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index c4a994177e..fc035d387c 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -35,7 +35,7 @@ #include "gd_mono_class_member.h" #include "gd_mono_header.h" -class GDMonoMethod : public GDMonoClassMember { +class GDMonoMethod : public IMonoClassMember { StringName name; @@ -57,17 +57,17 @@ class GDMonoMethod : public GDMonoClassMember { MonoMethod *mono_method; public: - virtual MemberType get_member_type() { return MEMBER_TYPE_METHOD; } + virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_METHOD; } - virtual StringName get_name() { return name; } + virtual StringName get_name() GD_FINAL { return name; } - virtual bool is_static(); + virtual bool is_static() GD_FINAL; - virtual Visibility get_visibility(); + virtual Visibility get_visibility() GD_FINAL; - virtual bool has_attribute(GDMonoClass *p_attr_class); - virtual MonoObject *get_attribute(GDMonoClass *p_attr_class); - virtual void fetch_attributes(); + virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL; + virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL; + void fetch_attributes(); _FORCE_INLINE_ int get_parameters_count() { return params_count; } _FORCE_INLINE_ ManagedType get_return_type() { return return_type; } diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index 04fd8b8e63..5842e26241 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -80,24 +80,24 @@ bool GDMonoProperty::is_static() { return mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_STATIC; } -GDMonoClassMember::Visibility GDMonoProperty::get_visibility() { +IMonoClassMember::Visibility GDMonoProperty::get_visibility() { MonoMethod *prop_method = mono_property_get_get_method(mono_property); if (prop_method == NULL) prop_method = mono_property_get_set_method(mono_property); switch (mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) { case MONO_METHOD_ATTR_PRIVATE: - return GDMonoClassMember::PRIVATE; + return IMonoClassMember::PRIVATE; case MONO_METHOD_ATTR_FAM_AND_ASSEM: - return GDMonoClassMember::PROTECTED_AND_INTERNAL; + return IMonoClassMember::PROTECTED_AND_INTERNAL; case MONO_METHOD_ATTR_ASSEM: - return GDMonoClassMember::INTERNAL; + return IMonoClassMember::INTERNAL; case MONO_METHOD_ATTR_FAMILY: - return GDMonoClassMember::PROTECTED; + return IMonoClassMember::PROTECTED; case MONO_METHOD_ATTR_PUBLIC: - return GDMonoClassMember::PUBLIC; + return IMonoClassMember::PUBLIC; default: - ERR_FAIL_V(GDMonoClassMember::PRIVATE); + ERR_FAIL_V(IMonoClassMember::PRIVATE); } } diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h index 934ce68904..d8a9f69ffb 100644 --- a/modules/mono/mono_gd/gd_mono_property.h +++ b/modules/mono/mono_gd/gd_mono_property.h @@ -35,7 +35,7 @@ #include "gd_mono_class_member.h" #include "gd_mono_header.h" -class GDMonoProperty : public GDMonoClassMember { +class GDMonoProperty : public IMonoClassMember { GDMonoClass *owner; MonoProperty *mono_property; @@ -47,15 +47,15 @@ class GDMonoProperty : public GDMonoClassMember { MonoCustomAttrInfo *attributes; public: - virtual MemberType get_member_type() { return MEMBER_TYPE_PROPERTY; } + virtual MemberType get_member_type() GD_FINAL { return MEMBER_TYPE_PROPERTY; } - virtual StringName get_name() { return name; } + virtual StringName get_name() GD_FINAL { return name; } - virtual bool is_static(); - virtual Visibility get_visibility(); + virtual bool is_static() GD_FINAL; + virtual Visibility get_visibility() GD_FINAL; - virtual bool has_attribute(GDMonoClass *p_attr_class); - virtual MonoObject *get_attribute(GDMonoClass *p_attr_class); + virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL; + virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL; void fetch_attributes(); bool has_getter(); diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 97a00a504d..ac6ccac3a7 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -265,61 +265,70 @@ void clear_cache() { } MonoObject *unmanaged_get_managed(Object *unmanaged) { - if (unmanaged) { - if (unmanaged->get_script_instance()) { - CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance()); - if (cs_instance) { - return cs_instance->get_mono_object(); - } + if (!unmanaged) + return NULL; + + if (unmanaged->get_script_instance()) { + CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance()); + + if (cs_instance) { + return cs_instance->get_mono_object(); } + } + + // If the owner does not have a CSharpInstance... + + void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + + if (!data) + return NULL; - // If the owner does not have a CSharpInstance... + CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value(); - void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + if (!script_binding.inited) { + // Already had a binding that needs to be setup + CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, unmanaged); - if (data) { - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value(); + if (!script_binding.inited) + return NULL; + } - Ref<MonoGCHandle> &gchandle = script_binding.gchandle; - ERR_FAIL_COND_V(gchandle.is_null(), NULL); + Ref<MonoGCHandle> &gchandle = script_binding.gchandle; + ERR_FAIL_COND_V(gchandle.is_null(), NULL); - MonoObject *target = gchandle->get_target(); + MonoObject *target = gchandle->get_target(); - if (target) - return target; + if (target) + return target; - CSharpLanguage::get_singleton()->release_script_gchandle(gchandle); + CSharpLanguage::get_singleton()->release_script_gchandle(gchandle); - // Create a new one + // Create a new one #ifdef DEBUG_ENABLED - CRASH_COND(script_binding.type_name == StringName()); - CRASH_COND(script_binding.wrapper_class == NULL); + CRASH_COND(script_binding.type_name == StringName()); + CRASH_COND(script_binding.wrapper_class == NULL); #endif - MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged); - ERR_FAIL_NULL_V(mono_object, NULL); - - gchandle->set_handle(MonoGCHandle::new_strong_handle(mono_object), MonoGCHandle::STRONG_HANDLE); + MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged); + ERR_FAIL_NULL_V(mono_object, NULL); - // Tie managed to unmanaged - Reference *ref = Object::cast_to<Reference>(unmanaged); + gchandle->set_handle(MonoGCHandle::new_strong_handle(mono_object), MonoGCHandle::STRONG_HANDLE); - if (ref) { - // Unsafe refcount increment. The managed instance also counts as a reference. - // This way if the unmanaged world has no references to our owner - // but the managed instance is alive, the refcount will be 1 instead of 0. - // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) + // Tie managed to unmanaged + Reference *ref = Object::cast_to<Reference>(unmanaged); - ref->reference(); - } + if (ref) { + // Unsafe refcount increment. The managed instance also counts as a reference. + // This way if the unmanaged world has no references to our owner + // but the managed instance is alive, the refcount will be 1 instead of 0. + // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) - return mono_object; - } + ref->reference(); } - return NULL; + return mono_object; } void set_main_thread(MonoThread *p_thread) { @@ -565,7 +574,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) { if (unexpected_exc) { GDMonoInternals::unhandled_exception(unexpected_exc); - _UNREACHABLE_(); + GD_UNREACHABLE(); } Vector<ScriptLanguage::StackInfo> _si; @@ -604,7 +613,7 @@ void debug_unhandled_exception(MonoException *p_exc) { ScriptDebugger::get_singleton()->idle_poll(); #endif GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well - _UNREACHABLE_(); + GD_UNREACHABLE(); } void print_unhandled_exception(MonoException *p_exc) { @@ -615,7 +624,7 @@ void set_pending_exception(MonoException *p_exc) { #ifdef HAS_PENDING_EXCEPTIONS if (get_runtime_invoke_count() == 0) { debug_unhandled_exception(p_exc); - _UNREACHABLE_(); + GD_UNREACHABLE(); } if (!mono_runtime_set_pending_exception(p_exc, false)) { @@ -624,7 +633,7 @@ void set_pending_exception(MonoException *p_exc) { } #else debug_unhandled_exception(p_exc); - _UNREACHABLE_(); + GD_UNREACHABLE(); #endif } diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 6febc50a5f..e88bf1ced9 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -44,7 +44,7 @@ #define UNLIKELY_UNHANDLED_EXCEPTION(m_exc) \ if (unlikely(m_exc != NULL)) { \ GDMonoUtils::debug_unhandled_exception(m_exc); \ - _UNREACHABLE_(); \ + GD_UNREACHABLE(); \ } namespace GDMonoUtils { @@ -214,7 +214,7 @@ void set_exception_message(MonoException *p_exc, String message); void debug_print_unhandled_exception(MonoException *p_exc); void debug_send_unhandled_exception_error(MonoException *p_exc); -_NO_RETURN_ void debug_unhandled_exception(MonoException *p_exc); +GD_NORETURN void debug_unhandled_exception(MonoException *p_exc); void print_unhandled_exception(MonoException *p_exc); /** diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h index 94e1193adf..87295a98f2 100644 --- a/modules/mono/utils/macros.h +++ b/modules/mono/utils/macros.h @@ -31,39 +31,57 @@ #ifndef UTIL_MACROS_H #define UTIL_MACROS_H -#define _GD_VARNAME_CONCAT_B(m_ignore, m_name) m_name -#define _GD_VARNAME_CONCAT_A(m_a, m_b, m_c) _GD_VARNAME_CONCAT_B(hello there, m_a##m_b##m_c) -#define _GD_VARNAME_CONCAT(m_a, m_b, m_c) _GD_VARNAME_CONCAT_A(m_a, m_b, m_c) -#define GD_UNIQUE_NAME(m_name) _GD_VARNAME_CONCAT(m_name, _, __COUNTER__) +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(attr_token) 0 +#endif -// noreturn +#define _GD_VARNAME_CONCAT_B_(m_ignore, m_name) m_name +#define _GD_VARNAME_CONCAT_A_(m_a, m_b, m_c) _GD_VARNAME_CONCAT_B_(hello there, m_a##m_b##m_c) +#define _GD_VARNAME_CONCAT_(m_a, m_b, m_c) _GD_VARNAME_CONCAT_A_(m_a, m_b, m_c) +#define GD_UNIQUE_NAME(m_name) _GD_VARNAME_CONCAT_(m_name, _, __COUNTER__) -#if __cpp_static_assert +// static assert +// TODO: Get rid of this macro once we upgrade to C++11 + +#ifdef __cpp_static_assert #define GD_STATIC_ASSERT(m_cond) static_assert((m_cond), "Condition '" #m_cond "' failed") #else #define GD_STATIC_ASSERT(m_cond) typedef int GD_UNIQUE_NAME(godot_static_assert)[((m_cond) ? 1 : -1)] #endif -#undef _NO_RETURN_ +// final +// TODO: Get rid of this macro once we upgrade to C++11 + +#if (__cplusplus >= 201103L) +#define GD_FINAL final +#else +#define GD_FINAL +#endif + +// noreturn +// TODO: Get rid of this macro once we upgrade to C++11 -#ifdef __GNUC__ -#define _NO_RETURN_ __attribute__((noreturn)) -#elif _MSC_VER -#define _NO_RETURN_ __declspec(noreturn) +#if __has_cpp_attribute(deprecated) +#define GD_NORETURN [[noreturn]] +#elif defined(__GNUC__) +#define GD_NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define GD_NORETURN __declspec(noreturn) #else -#error Platform or compiler not supported +#define GD_NORETURN +#pragma message "Macro GD_NORETURN will have no effect" #endif // unreachable #if defined(_MSC_VER) -#define _UNREACHABLE_() __assume(0) +#define GD_UNREACHABLE() __assume(0) #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 -#define _UNREACHABLE_() __builtin_unreachable() +#define GD_UNREACHABLE() __builtin_unreachable() #else -#define _UNREACHABLE_() \ - CRASH_NOW(); \ - do { \ +#define GD_UNREACHABLE() \ + CRASH_NOW(); \ + do { \ } while (true); #endif diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/osx_utils.cpp index 5ed982200f..f1362be249 100644 --- a/modules/mono/utils/osx_utils.cpp +++ b/modules/mono/utils/osx_utils.cpp @@ -30,10 +30,10 @@ #include "osx_utils.h" -#include "core/print_string.h" - #ifdef OSX_ENABLED +#include "core/print_string.h" + #include <CoreFoundation/CoreFoundation.h> #include <CoreServices/CoreServices.h> diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 404ca24482..e36844a1bc 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -109,7 +109,12 @@ Error ImageLoaderSVG::_create_image(Ref<Image> p_image, const PoolVector<uint8_t float upscale = upsample ? 2.0 : 1.0; int w = (int)(svg_image->width * p_scale * upscale); + ERR_EXPLAIN(vformat("Can't create image from SVG with scale %s, the resulting image size exceeds max width.", rtos(p_scale))); + ERR_FAIL_COND_V(w > Image::MAX_WIDTH, ERR_PARAMETER_RANGE_ERROR); + int h = (int)(svg_image->height * p_scale * upscale); + ERR_EXPLAIN(vformat("Can't create image from SVG with scale %s, the resulting image size exceeds max height.", rtos(p_scale))); + ERR_FAIL_COND_V(h > Image::MAX_HEIGHT, ERR_PARAMETER_RANGE_ERROR); PoolVector<uint8_t> dst_image; dst_image.resize(w * h * 4); diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 31fcbc0427..36a753e683 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -126,7 +126,7 @@ def configure(env): env.Append(CPPPATH=['#platform/osx']) env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED', '-DCOREMIDI_ENABLED']) - env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback', '-framework', 'CoreVideo']) env.Append(LIBS=['pthread']) env.Append(CPPFLAGS=['-mmacosx-version-min=10.9']) diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 262079fa89..927c8c9b00 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -43,8 +43,10 @@ #include "servers/visual/rasterizer.h" #include "servers/visual/visual_server_wrap_mt.h" #include "servers/visual_server.h" +#include <AppKit/AppKit.h> #include <AppKit/NSCursor.h> #include <ApplicationServices/ApplicationServices.h> +#include <CoreVideo/CoreVideo.h> #undef CursorShape /** @@ -102,10 +104,13 @@ public: id window_view; id autoreleasePool; id cursor; - id pixelFormat; - id context; + NSOpenGLPixelFormat *pixelFormat; + NSOpenGLContext *context; bool layered_window; + bool waiting_for_vsync; + NSCondition *vsync_condition; + CVDisplayLinkRef displayLink; CursorShape cursor_shape; NSCursor *cursors[CURSOR_MAX]; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 760858b2e5..6b65c1a529 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -117,6 +117,21 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto return Vector2(mouse_x, mouse_y); } +// DisplayLinkCallback is called from our DisplayLink OS thread informing us right before +// a screen update is required. We can use it to work around the broken vsync. +static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) { + OS_OSX *os = (OS_OSX *)displayLinkContext; + + // Set flag so we know we can output our next frame and signal our conditional lock + // if we're not doing vsync this will be ignored + [os->vsync_condition lock]; + os->waiting_for_vsync = false; + [os->vsync_condition signal]; + [os->vsync_condition unlock]; + + return kCVReturnSuccess; +} + @interface GodotApplication : NSApplication @end @@ -267,7 +282,9 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto NSWindow *window = (NSWindow *)[notification object]; CGFloat newBackingScaleFactor = [window backingScaleFactor]; CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; - [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:YES]; + if (OS_OSX::singleton->is_hidpi_allowed()) { + [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:YES]; + } if (newBackingScaleFactor != oldBackingScaleFactor) { //Set new display scale and window size @@ -1366,6 +1383,15 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a [context makeCurrentContext]; + // setup our display link, this will inform us when a refresh is needed + CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + CVDisplayLinkSetOutputCallback(displayLink, &DisplayLinkCallback, this); + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, context.CGLContextObj, pixelFormat.CGLPixelFormatObj); + CVDisplayLinkStart(displayLink); + + // initialise a conditional lock object + vsync_condition = [[NSCondition alloc] init]; + set_use_vsync(p_desired.use_vsync); [NSApp activateIgnoringOtherApps:YES]; @@ -1453,6 +1479,11 @@ void OS_OSX::finalize() { midi_driver.close(); #endif + if (displayLink) { + CVDisplayLinkRelease(displayLink); + } + [vsync_condition release]; + CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL); CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL); @@ -1967,6 +1998,17 @@ String OS_OSX::get_locale() const { } void OS_OSX::swap_buffers() { + if (is_vsync_enabled()) { + // Wait until our DisplayLink callback unsets our flag... + [vsync_condition lock]; + while (waiting_for_vsync) + [vsync_condition wait]; + + // Make sure we wait again next frame around + waiting_for_vsync = true; + + [vsync_condition unlock]; + } [context flushBuffer]; } @@ -2633,22 +2675,22 @@ Error OS_OSX::move_to_trash(const String &p_path) { } void OS_OSX::_set_use_vsync(bool p_enable) { - CGLContextObj ctx = CGLGetCurrentContext(); + // CGLCPSwapInterval broke in OSX 10.14 and it seems Apple is not interested in fixing + // it as OpenGL is now deprecated and Metal solves this differently. + // Following SDLs example we're working around this using DisplayLink + // When vsync is enabled we set a flag "waiting_for_vsync" to true. + // This flag is set to false when DisplayLink informs us our display is about to refresh. + + /* CGLContextObj ctx = CGLGetCurrentContext(); if (ctx) { GLint swapInterval = p_enable ? 1 : 0; CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); - } -} -/* -bool OS_OSX::is_vsync_enabled() const { - GLint swapInterval = 0; - CGLContextObj ctx = CGLGetCurrentContext(); - if (ctx) { - CGLGetParameter(ctx, kCGLCPSwapInterval, &swapInterval); - } - return swapInterval ? true : false; + }*/ + + ///TODO Maybe pause/unpause display link? + waiting_for_vsync = p_enable; } -*/ + OS_OSX *OS_OSX::singleton = NULL; OS_OSX::OS_OSX() { diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index ea0193b8ed..ea4f63b49c 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -739,6 +739,11 @@ String OSUWP::get_environment(const String &p_var) const { return ""; }; +bool OSUWP::set_environment(const String &p_var, const String &p_value) const { + + return false; +} + String OSUWP::get_stdin_string(bool p_block) { return String(); diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 491c9bce03..5475c4e60a 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -213,6 +213,7 @@ public: virtual bool has_environment(const String &p_var) const; virtual String get_environment(const String &p_var) const; + virtual bool set_environment(const String &p_var, const String &p_value) const; virtual void set_clipboard(const String &p_text); virtual String get_clipboard() const; diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index ca2f71ca18..141ab96370 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -73,7 +73,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } #endif - String icon_path = p_preset->get("application/icon"); + String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon")); String file_verion = p_preset->get("application/file_version"); String product_version = p_preset->get("application/product_version"); String company_name = p_preset->get("application/company_name"); @@ -137,7 +137,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) { EditorExportPlatformPC::get_export_options(r_options); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_GLOBAL_FILE, "*.ico"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), "")); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 35f9d541ef..9ae1be9afd 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2604,6 +2604,11 @@ String OS_Windows::get_environment(const String &p_var) const { return ""; } +bool OS_Windows::set_environment(const String &p_var, const String &p_value) const { + + return (bool)SetEnvironmentVariableW(p_var.c_str(), p_value.c_str()); +} + String OS_Windows::get_stdin_string(bool p_block) { if (p_block) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 4936a69120..771789c86b 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -268,6 +268,7 @@ public: virtual bool has_environment(const String &p_var) const; virtual String get_environment(const String &p_var) const; + virtual bool set_environment(const String &p_var, const String &p_value) const; virtual void set_clipboard(const String &p_text); virtual String get_clipboard() const; diff --git a/platform/x11/SCsub b/platform/x11/SCsub index 97d3d1b514..e302f09c88 100644 --- a/platform/x11/SCsub +++ b/platform/x11/SCsub @@ -13,6 +13,7 @@ common_x11 = [ "key_mapping_x11.cpp", "joypad_linux.cpp", "power_x11.cpp", + "detect_prime.cpp" ] prog = env.add_program('#bin/godot', ['godot_x11.cpp'] + common_x11) diff --git a/platform/x11/detect_prime.cpp b/platform/x11/detect_prime.cpp new file mode 100644 index 0000000000..04a825fac9 --- /dev/null +++ b/platform/x11/detect_prime.cpp @@ -0,0 +1,233 @@ +/*************************************************************************/ +/* detect_prime.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef X11_ENABLED +#if defined(OPENGL_ENABLED) + +#include "core/print_string.h" +#include "core/ustring.h" + +#include <stdlib.h> + +#include <GL/gl.h> +#include <GL/glx.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include <cstring> + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 + +typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *); + +struct vendor { + const char *glxvendor; + int priority; +}; + +vendor vendormap[] = { + { "Advanced Micro Devices, Inc.", 30 }, + { "NVIDIA Corporation", 30 }, + { "X.Org", 30 }, + { "Intel Open Source Technology Center", 20 }, + { "nouveau", 10 }, + { "Mesa Project", 0 }, + { NULL, 0 } +}; + +// Runs inside a child. Exiting will not quit the engine. +void create_context() { + Display *x11_display = XOpenDisplay(NULL); + Window x11_window; + GLXContext glx_context; + + GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB"); + + static int visual_attribs[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_DOUBLEBUFFER, true, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 24, + None + }; + + int fbcount; + GLXFBConfig fbconfig = 0; + XVisualInfo *vi = NULL; + + XSetWindowAttributes swa; + swa.event_mask = StructureNotifyMask; + swa.border_pixel = 0; + unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask; + + GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); + if (!fbc) + exit(1); + + vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); + + fbconfig = fbc[0]; + + static int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None + }; + + glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs); + + swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); + x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, 10, 10, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa); + + if (!x11_window) + exit(1); + + glXMakeCurrent(x11_display, x11_window, glx_context); + XFree(vi); +} + +int detect_prime() { + pid_t p; + int priorities[2]; + String vendors[2]; + String renderers[2]; + + vendors[0] = "Unknown"; + vendors[1] = "Unknown"; + renderers[0] = "Unknown"; + renderers[1] = "Unknown"; + + for (int i = 0; i < 2; ++i) { + int fdset[2]; + + if (pipe(fdset) == -1) { + print_verbose("Failed to pipe(), using default GPU"); + return 0; + } + + // Fork so the driver initialization can crash without taking down the engine. + p = fork(); + + if (p > 0) { + // Main thread + + int stat_loc = 0; + char string[201]; + string[200] = '\0'; + + close(fdset[1]); + + waitpid(p, &stat_loc, 0); + + if (!stat_loc) { + // No need to do anything complicated here. Anything less than + // PIPE_BUF will be delivered in one read() call. + read(fdset[0], string, sizeof(string) - 1); + + vendors[i] = string; + renderers[i] = string + strlen(string) + 1; + } + + close(fdset[0]); + + } else { + // In child, exit() here will not quit the engine. + + char string[201]; + + close(fdset[0]); + + if (i) setenv("DRI_PRIME", "1", 1); + create_context(); + + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + + int vendor_len = strlen(vendor) + 1; + int renderer_len = strlen(renderer) + 1; + + if (vendor_len + renderer_len >= sizeof(string)) { + renderer_len = 200 - vendor_len; + } + + memcpy(&string, vendor, vendor_len); + memcpy(&string[vendor_len], renderer, renderer_len); + + write(fdset[1], string, vendor_len + renderer_len); + + close(fdset[1]); + exit(0); + } + } + + int preferred = 0; + int priority = 0; + + if (vendors[0] == vendors[1]) { + print_verbose("Only one GPU found, using default."); + return 0; + } + + for (int i = 1; i >= 0; --i) { + vendor *v = vendormap; + while (v->glxvendor) { + if (v->glxvendor == vendors[i]) { + priorities[i] = v->priority; + + if (v->priority >= priority) { + priority = v->priority; + preferred = i; + } + } + ++v; + } + } + + print_verbose("Found renderers:"); + for (int i = 0; i < 2; ++i) { + print_verbose("Renderer " + itos(i) + ": " + renderers[i] + " with priority: " + itos(priorities[i])); + } + + print_verbose("Using renderer: " + renderers[preferred]); + return preferred; +} + +#endif +#endif diff --git a/platform/x11/detect_prime.h b/platform/x11/detect_prime.h new file mode 100644 index 0000000000..13bcf6fc38 --- /dev/null +++ b/platform/x11/detect_prime.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* detect_prime.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef X11_ENABLED +#if defined(OPENGL_ENABLED) + +int detect_prime(); + +#endif +#endif diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 0db79fa3e9..e0924fc982 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -29,6 +29,8 @@ /*************************************************************************/ #include "os_x11.h" +#include "detect_prime.h" + #include "core/os/dir_access.h" #include "core/print_string.h" #include "drivers/gles2/rasterizer_gles2.h" @@ -240,28 +242,15 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a // maybe contextgl wants to be in charge of creating the window #if defined(OPENGL_ENABLED) - // Set DRI_PRIME if not set. This means that Godot should default to a higher-power GPU if it exists. - // Note: Due to the final '0' parameter to setenv any existing DRI_PRIME environment variables will not - // be overwritten. - bool enable_dri_prime = true; - // Check if Nouveau is loaded, we don't want to force dGPU usage with that driver. - if (FileAccess *f = FileAccess::open("/proc/modules", FileAccess::READ)) { - // Match driver name + space - String nouveau_str = "nouveau "; - - while (!f->eof_reached()) { - String line = f->get_line(); - - if (line.begins_with(nouveau_str)) { - enable_dri_prime = false; - break; - } + if (getenv("DRI_PRIME") == NULL) { + print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); + int use_prime = detect_prime(); + + if (use_prime) { + print_line("Found discrete GPU, setting DRI_PRIME=1 to use it."); + print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU."); + setenv("DRI_PRIME", "1", 1); } - f->close(); - memdelete(f); - } - if (enable_dri_prime) { - setenv("DRI_PRIME", "1", 0); } ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_3_0_COMPATIBLE; diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index dced688899..41cee7335e 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -134,7 +134,7 @@ void CanvasItemMaterial::_update_shader() { code += "\tint total_frames = particles_anim_h_frames * particles_anim_v_frames;\n"; code += "\tint frame = int(float(total_frames) * INSTANCE_CUSTOM.z);\n"; code += "\tif (particles_anim_loop) {\n"; - code += "\t\tframe = abs(frame) % total_frames;\n"; + code += "\t\tframe = int(abs(frame) % total_frames);\n"; code += "\t} else {\n"; code += "\t\tframe = clamp(frame, 0, total_frames - 1);\n"; code += "\t}\n"; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 21feb6e226..eaed1da0ba 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -594,7 +594,7 @@ void CPUParticles2D::_particles_process(float p_delta) { if (restart_time >= prev_time) { restart = true; if (fractional_delta) { - local_delta = (1.0 - restart_time + time) * lifetime; + local_delta = (lifetime - restart_time + time) * lifetime; } } else if (restart_time < time) { diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index c005c33a19..9701998f5d 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -30,6 +30,7 @@ #include "particles_2d.h" +#include "core/os/os.h" #include "scene/resources/particles_material.h" #include "scene/scene_string_names.h" @@ -213,6 +214,10 @@ bool Particles2D::get_fractional_delta() const { String Particles2D::get_configuration_warning() const { + if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles\" option for this purpose."); + } + String warnings; if (process_material.is_null()) { diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index fd28b876f3..ed9374e422 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -495,6 +495,7 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode); ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking); ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking); + ClassDB::bind_method(D_METHOD("get_frustum"), &Camera::get_frustum); ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit); ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit); diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 2add50dd5d..78b2958400 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -29,6 +29,8 @@ /*************************************************************************/ #include "particles.h" + +#include "core/os/os.h" #include "scene/resources/particles_material.h" #include "servers/visual_server.h" @@ -224,6 +226,10 @@ bool Particles::get_fractional_delta() const { String Particles::get_configuration_warning() const { + if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles node instead. You can use the \"Convert to CPUParticles\" option for this purpose."); + } + String warnings; bool meshes_found = false; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index a3fa2ac98d..6b70eef662 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -382,36 +382,30 @@ void Sprite3D::_draw() { VS::get_singleton()->immediate_clear(immediate); if (!texture.is_valid()) - return; //no texuture no life + return; Vector2 tsize = texture->get_size(); if (tsize.x == 0 || tsize.y == 0) return; - Size2i s; - Rect2 src_rect; - - if (region) { - - s = region_rect.size; - src_rect = region_rect; - } else { - s = texture->get_size(); - s = s / Size2(hframes, vframes); + Rect2 base_rect; + if (region) + base_rect = region_rect; + else + base_rect = Rect2(0, 0, texture->get_width(), texture->get_height()); - src_rect.size = s; - src_rect.position.x += (frame % hframes) * s.x; - src_rect.position.y += (frame / hframes) * s.y; - } + Size2 frame_size = base_rect.size / Size2(hframes, vframes); + Point2 frame_offset = Point2(frame % hframes, frame / hframes); + frame_offset *= frame_size; - Point2 ofs = get_offset(); + Point2 dest_offset = get_offset(); if (is_centered()) - ofs -= s / 2; - - Rect2 dst_rect(ofs, s); + dest_offset -= frame_size / 2; + Rect2 src_rect(base_rect.position + frame_offset, frame_size); + Rect2 final_dst_rect(dest_offset, frame_size); Rect2 final_rect; Rect2 final_src_rect; - if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect)) + if (!texture->get_rect_region(final_dst_rect, src_rect, final_rect, final_src_rect)) return; if (final_rect.size.x == 0 || final_rect.size.y == 0) diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 1d2001c30d..4c249b117e 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -344,10 +344,16 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float for (int i = 0; i < a->get_track_count(); i++) { + // If an animation changes this animation (or it animates itself) + // we need to recreate our animation cache + if (p_anim->node_cache.size() != a->get_track_count()) { + _ensure_node_caches(p_anim); + } + TrackNodeCache *nc = p_anim->node_cache[i]; - if (!nc) // no node cache for this track, skip it - continue; + if (!nc) + continue; // no node cache for this track, skip it if (!a->track_is_enabled(i)) continue; // do nothing if the track is disabled diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 307a421016..4b1c7b3db7 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -82,11 +82,8 @@ void ColorPicker::_notification(int p_what) { } break; case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { - if (screen != NULL) { - if (screen->is_visible()) { - screen->hide(); - } - } + if (screen != NULL && screen->is_visible()) + screen->hide(); } break; } } @@ -500,21 +497,17 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) { void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> bev = p_event; - - if (bev.is_valid()) { - - if (bev->get_button_index() == BUTTON_LEFT && !bev->is_pressed()) { - emit_signal("color_changed", color); - screen->hide(); - } + if (bev.is_valid() && bev->get_button_index() == BUTTON_LEFT && !bev->is_pressed()) { + emit_signal("color_changed", color); + screen->hide(); } Ref<InputEventMouseMotion> mev = p_event; - if (mev.is_valid()) { Viewport *r = get_tree()->get_root(); if (!r->get_visible_rect().has_point(Point2(mev->get_global_position().x, mev->get_global_position().y))) return; + Ref<Image> img = r->get_texture()->get_data(); if (img.is_valid() && !img->empty()) { img->lock(); @@ -540,6 +533,8 @@ void ColorPicker::_screen_pick_pressed() { screen->set_anchors_and_margins_preset(Control::PRESET_WIDE); screen->set_default_cursor_shape(CURSOR_POINTING_HAND); screen->connect("gui_input", this, "_screen_input"); + // It immediately toggles off in the first press otherwise. + screen->call_deferred("connect", "hide", btn_pick, "set_pressed", varray(false)); } screen->raise(); screen->show_modal(); @@ -830,8 +825,6 @@ void ColorPickerButton::_update_picker() { add_child(popup); picker->connect("color_changed", this, "_color_changed"); popup->connect("modal_closed", this, "_modal_closed"); - popup->connect("about_to_show", this, "set_pressed", varray(true)); - popup->connect("popup_hide", this, "set_pressed", varray(false)); picker->set_pick_color(color); picker->set_edit_alpha(edit_alpha); } @@ -862,6 +855,4 @@ ColorPickerButton::ColorPickerButton() { picker = NULL; popup = NULL; edit_alpha = true; - - set_toggle_mode(true); } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 09fbb39866..4abde6cc0f 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2645,24 +2645,26 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } case KEY_UP: { - if (k->get_shift()) - _pre_shift_selection(); if (k->get_alt()) { scancode_handled = false; break; } #ifndef APPLE_STYLE_KEYS if (k->get_command()) { - _scroll_lines_up(); - break; - } #else if (k->get_command() && k->get_alt()) { +#endif _scroll_lines_up(); break; } + if (k->get_shift()) { + _pre_shift_selection(); + } + +#ifdef APPLE_STYLE_KEYS if (k->get_command()) { + cursor_set_line(0); } else #endif @@ -2696,24 +2698,24 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } case KEY_DOWN: { - if (k->get_shift()) - _pre_shift_selection(); if (k->get_alt()) { scancode_handled = false; break; } #ifndef APPLE_STYLE_KEYS if (k->get_command()) { - _scroll_lines_down(); - break; - } - #else if (k->get_command() && k->get_alt()) { +#endif _scroll_lines_down(); break; } + if (k->get_shift()) { + _pre_shift_selection(); + } + +#ifdef APPLE_STYLE_KEYS if (k->get_command()) { cursor_set_line(get_last_unhidden_line(), true, false, 9999); } else diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 6aa3891035..04d7107fa4 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1311,7 +1311,7 @@ Node *Node::_get_child_by_name(const StringName &p_name) const { return NULL; } -Node *Node::_get_node(const NodePath &p_path) const { +Node *Node::get_node_or_null(const NodePath &p_path) const { if (!data.inside_tree && p_path.is_absolute()) { ERR_EXPLAIN("Can't use get_node() with absolute paths from outside the active scene tree."); @@ -1376,7 +1376,7 @@ Node *Node::_get_node(const NodePath &p_path) const { Node *Node::get_node(const NodePath &p_path) const { - Node *node = _get_node(p_path); + Node *node = get_node_or_null(p_path); if (!node) { ERR_EXPLAIN("Node not found: " + p_path); ERR_FAIL_COND_V(!node, NULL); @@ -1386,7 +1386,7 @@ Node *Node::get_node(const NodePath &p_path) const { bool Node::has_node(const NodePath &p_path) const { - return _get_node(p_path) != NULL; + return get_node_or_null(p_path) != NULL; } Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const { @@ -2709,6 +2709,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_child", "idx"), &Node::get_child); ClassDB::bind_method(D_METHOD("has_node", "path"), &Node::has_node); ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node); + ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null); ClassDB::bind_method(D_METHOD("get_parent"), &Node::get_parent); ClassDB::bind_method(D_METHOD("find_node", "mask", "recursive", "owned"), &Node::find_node, DEFVAL(true), DEFVAL(true)); ClassDB::bind_method(D_METHOD("find_parent", "mask"), &Node::find_parent); diff --git a/scene/main/node.h b/scene/main/node.h index 1c451ef567..e6189389cb 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -153,7 +153,6 @@ private: void _print_tree_pretty(const String prefix, const bool last); void _print_tree(const Node *p_node); - Node *_get_node(const NodePath &p_path) const; Node *_get_child_by_name(const StringName &p_name) const; void _replace_connections_target(Node *p_new_target); @@ -252,6 +251,7 @@ public: Node *get_child(int p_index) const; bool has_node(const NodePath &p_path) const; Node *get_node(const NodePath &p_path) const; + Node *get_node_or_null(const NodePath &p_path) const; Node *find_node(const String &p_mask, bool p_recursive = true, bool p_owned = true) const; bool has_node_and_resource(const NodePath &p_path) const; Node *get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index f713851090..689f18a09d 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1154,13 +1154,14 @@ void SceneTree::_update_root_rect() { float viewport_aspect = desired_res.aspect(); float video_mode_aspect = video_mode.aspect(); + if (use_font_oversampling && stretch_aspect == STRETCH_ASPECT_IGNORE) { + WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'."); + } + if (stretch_aspect == STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect) < CMP_EPSILON) { //same aspect or ignore aspect viewport_size = desired_res; screen_size = video_mode; - if (use_font_oversampling) { - WARN_PRINT("Font oversampling only works with the following resize modes 'Keep Width', 'Keep Height', and 'Expand'.") - } } else if (viewport_aspect < video_mode_aspect) { // screen ratio is smaller vertically diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index a50a09f095..078d880d0e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -145,6 +145,7 @@ #include "scene/resources/mesh_library.h" #include "scene/resources/packed_scene.h" #include "scene/resources/particles_material.h" +#include "scene/resources/physics_material.h" #include "scene/resources/plane_shape.h" #include "scene/resources/polygon_path_finder.h" #include "scene/resources/primitive_meshes.h" @@ -207,7 +208,6 @@ #include "scene/3d/visibility_notifier.h" #include "scene/animation/skeleton_ik.h" #include "scene/resources/environment.h" -#include "scene/resources/physics_material.h" #endif static Ref<ResourceFormatSaverText> resource_saver_text; @@ -602,8 +602,8 @@ void register_scene_types() { ClassDB::register_class<SpatialVelocityTracker>(); - ClassDB::register_class<PhysicsMaterial>(); #endif + ClassDB::register_class<PhysicsMaterial>(); ClassDB::register_class<World>(); ClassDB::register_class<Environment>(); ClassDB::register_class<World2D>(); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index a57b7bbb42..3c295267dc 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -303,7 +303,7 @@ Ref<Texture> Environment::get_adjustment_color_correction() const { void Environment::_validate_property(PropertyInfo &property) const { - if (property.name == "background_sky" || property.name == "background_sky_custom_fov" || property.name == "background_sky_orientation" || property.name == "ambient_light/sky_contribution") { + if (property.name == "background_sky" || property.name == "background_sky_custom_fov" || property.name == "background_sky_orientation" || property.name == "background_sky_rotation" || property.name == "background_sky_rotation_degrees" || property.name == "ambient_light/sky_contribution") { if (bg_mode != BG_SKY && bg_mode != BG_COLOR_SKY) { property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 7ecf9a2b16..c72ccc97db 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -497,6 +497,7 @@ Size2 Font::get_string_size(const String &p_string) const { } void BitmapFont::set_fallback(const Ref<BitmapFont> &p_fallback) { + ERR_FAIL_COND(p_fallback == this); fallback = p_fallback; } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index ea810edf8c..f28a67b493 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -55,7 +55,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { Node *p_name; \ if (p_id & FLAG_ID_IS_PATH) { \ NodePath np = node_paths[p_id & FLAG_MASK]; \ - p_name = ret_nodes[0]->_get_node(np); \ + p_name = ret_nodes[0]->get_node_or_null(np); \ } else { \ ERR_FAIL_INDEX_V(p_id &FLAG_MASK, nc, NULL); \ p_name = ret_nodes[p_id & FLAG_MASK]; \ @@ -342,7 +342,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { } for (int i = 0; i < editable_instances.size(); i++) { - Node *ei = ret_nodes[0]->_get_node(editable_instances[i]); + Node *ei = ret_nodes[0]->get_node_or_null(editable_instances[i]); if (ei) { ret_nodes[0]->set_editable_instance(ei, true); } diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index dcad70451e..ff5900cd3e 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -943,6 +943,7 @@ uint32_t AtlasTexture::get_flags() const { void AtlasTexture::set_atlas(const Ref<Texture> &p_atlas) { + ERR_FAIL_COND(p_atlas == this); if (atlas == p_atlas) return; atlas = p_atlas; @@ -1182,6 +1183,7 @@ void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) { void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture> &p_texture) { + ERR_FAIL_COND(p_texture == this); ERR_FAIL_INDEX(p_idx, pieces.size()); pieces.write[p_idx].texture = p_texture; }; @@ -1747,6 +1749,7 @@ void ProxyTexture::_bind_methods() { void ProxyTexture::set_base(const Ref<Texture> &p_texture) { + ERR_FAIL_COND(p_texture == this); base = p_texture; if (base.is_valid()) { VS::get_singleton()->texture_set_proxy(proxy, base->get_rid()); @@ -1862,6 +1865,8 @@ int AnimatedTexture::get_frames() const { } void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture> &p_texture) { + + ERR_FAIL_COND(p_texture == this); ERR_FAIL_INDEX(p_frame, MAX_FRAMES); RWLockWrite w(rw_lock); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 5a2e7245a2..3c83de91fd 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -614,7 +614,7 @@ Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, if (coords.size() == 0) { return autotile_get_icon_coordinate(p_id); } else { - return coords[Math::random(0, (int)coords.size())]; + return coords[Math::rand() % coords.size()]; } } diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index a89b70d1ea..d95e0e2da1 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -324,7 +324,7 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade String u = "uniform sampler2D " + make_unique_id(p_type, p_id, "tex"); switch (texture_type) { case TYPE_DATA: break; - case TYPE_COLOR: u += " : hint_color"; break; + case TYPE_COLOR: u += " : hint_albedo"; break; case TYPE_NORMALMAP: u += " : hint_normal"; break; } return u + ";"; @@ -554,7 +554,7 @@ String VisualShaderNodeCubeMap::generate_global(Shader::Mode p_mode, VisualShade String u = "uniform sampler2DCube " + make_unique_id(p_type, p_id, "cube"); switch (texture_type) { case TYPE_DATA: break; - case TYPE_COLOR: u += " : hint_color"; break; + case TYPE_COLOR: u += " : hint_albedo"; break; case TYPE_NORMALMAP: u += " : hint_normal"; break; } return u + ";"; diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index 23f16c246e..f0fbbafe1c 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -652,7 +652,7 @@ void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) { linear_velocity=(p_xform.origin - get_transform().origin)/p_step; //compute a FAKE angular velocity, not so easy - Matrix3 rot=get_transform().basis.orthonormalized().transposed() * p_xform.basis.orthonormalized(); + Basis rot=get_transform().basis.orthonormalized().transposed() * p_xform.basis.orthonormalized(); Vector3 axis; real_t angle; diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 0c43000186..4e167be300 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -81,7 +81,6 @@ 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); } @@ -167,8 +166,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 - deprecated", &_createGodotPhysicsCallback); - PhysicsServerManager::set_default_server("GodotPhysics - deprecated"); + PhysicsServerManager::register_server("GodotPhysics", &_createGodotPhysicsCallback); + PhysicsServerManager::set_default_server("GodotPhysics"); } void unregister_server_types() { |