summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS.md2
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--DONORS.md92
-rw-r--r--SConstruct1
-rw-r--r--core/bind/core_bind.cpp14
-rw-r--r--core/bind/core_bind.h15
-rw-r--r--core/class_db.cpp5
-rw-r--r--core/class_db.h1
-rw-r--r--core/math/a_star.cpp22
-rw-r--r--core/math/a_star.h4
-rw-r--r--core/math/audio_frame.h6
-rw-r--r--core/math/expression.cpp8
-rw-r--r--core/math/expression.h1
-rw-r--r--core/math/geometry.h6
-rw-r--r--core/math/math_funcs.h11
-rw-r--r--core/math/quat.h8
-rw-r--r--core/math/random_number_generator.cpp1
-rw-r--r--core/math/random_number_generator.h2
-rw-r--r--core/math/random_pcg.h9
-rw-r--r--core/math/vector2.h7
-rw-r--r--core/math/vector3.h7
-rw-r--r--core/project_settings.cpp2
-rw-r--r--core/ucaps.h1332
-rw-r--r--core/ustring.h8
-rw-r--r--core/variant_call.cpp8
-rw-r--r--core/vmap.h2
-rw-r--r--core/vset.h2
-rw-r--r--doc/classes/@GDScript.xml18
-rw-r--r--doc/classes/ARVRAnchor.xml16
-rw-r--r--doc/classes/ARVRController.xml14
-rw-r--r--doc/classes/ARVRPositionalTracker.xml7
-rw-r--r--doc/classes/AStar.xml20
-rw-r--r--doc/classes/File.xml8
-rw-r--r--doc/classes/HeightMapShape.xml28
-rw-r--r--doc/classes/RandomNumberGenerator.xml11
-rw-r--r--doc/classes/StyleBoxFlat.xml3
-rw-r--r--doc/classes/TextureRect.xml6
-rw-r--r--doc/classes/TileMap.xml7
-rw-r--r--doc/classes/Vector2.xml9
-rw-r--r--doc/classes/Vector3.xml9
-rwxr-xr-xdoc/tools/makerst.py3
-rw-r--r--drivers/dummy/rasterizer_dummy.h3
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp9
-rw-r--r--drivers/gles2/rasterizer_gles2.h2
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp6
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp120
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h12
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp16
-rw-r--r--drivers/gles3/rasterizer_gles3.h2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp14
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp114
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h11
-rw-r--r--drivers/windows/file_access_windows.cpp33
-rw-r--r--drivers/windows/file_access_windows.h1
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp4
-rw-r--r--editor/dependency_editor.cpp6
-rw-r--r--editor/editor_audio_buses.cpp185
-rw-r--r--editor/editor_audio_buses.h57
-rw-r--r--editor/editor_builders.py2
-rw-r--r--editor/editor_file_dialog.cpp2
-rw-r--r--editor/editor_node.cpp36
-rw-r--r--editor/editor_profiler.cpp57
-rw-r--r--editor/editor_profiler.h2
-rw-r--r--editor/editor_properties.cpp12
-rw-r--r--editor/editor_settings.cpp6
-rw-r--r--editor/editor_themes.cpp62
-rw-r--r--editor/filesystem_dock.cpp14
-rw-r--r--editor/import/resource_importer_wav.cpp40
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp52
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h4
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp74
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h4
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp15
-rw-r--r--editor/plugins/script_editor_plugin.cpp4
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp8
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp4
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp122
-rw-r--r--editor/plugins/tile_set_editor_plugin.h2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp806
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h59
-rw-r--r--editor/script_editor_debugger.cpp65
-rw-r--r--editor/script_editor_debugger.h9
-rw-r--r--main/tests/test_string.cpp14
-rw-r--r--methods.py1
-rw-r--r--modules/assimp/editor_scene_importer_assimp.cpp2
-rw-r--r--modules/assimp/register_types.cpp6
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.cpp11
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.h1
-rw-r--r--modules/gdnative/include/arvr/godot_arvr.h4
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp3
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp2
-rw-r--r--modules/gdscript/gdscript.cpp2
-rw-r--r--modules/gdscript/gdscript.h1
-rw-r--r--modules/gdscript/gdscript_editor.cpp59
-rw-r--r--modules/gdscript/gdscript_functions.cpp14
-rw-r--r--modules/gdscript/gdscript_functions.h1
-rw-r--r--modules/mono/SCsub1
-rw-r--r--modules/mono/config.py2
-rw-r--r--modules/mono/csharp_script.cpp15
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp6
-rw-r--r--modules/mono/editor/godotsharp_editor.h6
-rw-r--r--modules/mono/glue/Managed/Files/Array.cs196
-rw-r--r--modules/mono/glue/Managed/Files/Dictionary.cs258
-rw-r--r--modules/mono/glue/Managed/Files/MarshalUtils.cs60
-rw-r--r--modules/mono/glue/Managed/Files/Mathf.cs10
-rw-r--r--modules/mono/glue/Managed/Files/Vector2.cs5
-rw-r--r--modules/mono/glue/Managed/Files/Vector3.cs5
-rw-r--r--modules/mono/glue/Managed/IgnoredFiles/Variant.cs11
-rw-r--r--modules/mono/glue/base_object_glue.cpp2
-rw-r--r--modules/mono/glue/collections_glue.cpp3
-rw-r--r--modules/mono/glue/collections_glue.h2
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp32
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h18
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp128
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h21
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp27
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h40
-rw-r--r--modules/mono/mono_gd/managed_type.cpp58
-rw-r--r--modules/mono/mono_gd/managed_type.h (renamed from drivers/gl_context/context_gl.cpp)41
-rw-r--r--modules/mono/mono_reg_utils.py14
-rw-r--r--modules/mono/signal_awaiter_utils.cpp4
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp6
-rw-r--r--modules/mono/utils/thread_local.h4
-rw-r--r--modules/opensimplex/open_simplex_noise.cpp6
-rw-r--r--modules/opensimplex/open_simplex_noise.h1
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml9
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp19
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h1
-rw-r--r--modules/visual_script/visual_script_editor.cpp6
-rw-r--r--platform/android/SCsub1
-rw-r--r--platform/android/audio_driver_opensl.cpp2
-rw-r--r--platform/android/detect.py1
-rw-r--r--platform/haiku/audio_driver_media_kit.cpp4
-rw-r--r--platform/haiku/context_gl_haiku.h22
-rw-r--r--platform/iphone/SCsub2
-rw-r--r--platform/iphone/detect.py1
-rw-r--r--platform/javascript/detect.py1
-rw-r--r--platform/osx/SCsub1
-rw-r--r--platform/server/SCsub2
-rw-r--r--platform/uwp/context_egl_uwp.h21
-rw-r--r--platform/uwp/detect.py3
-rw-r--r--platform/windows/context_gl_windows.h21
-rw-r--r--platform/windows/detect.py1
-rw-r--r--platform/x11/SCsub1
-rw-r--r--platform/x11/context_gl_x11.h21
-rw-r--r--platform/x11/detect.py2
-rw-r--r--scene/2d/animated_sprite.cpp2
-rw-r--r--scene/2d/path_2d.cpp2
-rw-r--r--scene/3d/arvr_nodes.cpp28
-rw-r--r--scene/3d/arvr_nodes.h7
-rw-r--r--scene/3d/soft_body.cpp8
-rw-r--r--scene/3d/soft_body.h1
-rw-r--r--scene/gui/texture_rect.cpp79
-rw-r--r--scene/gui/texture_rect.h8
-rw-r--r--scene/register_scene_types.cpp19
-rw-r--r--scene/resources/animation.cpp2
-rw-r--r--scene/resources/convex_polygon_shape.cpp2
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp6
-rwxr-xr-xscene/resources/default_theme/make_header.py2
-rw-r--r--scene/resources/gradient.h2
-rw-r--r--scene/resources/height_map_shape.cpp196
-rw-r--r--scene/resources/height_map_shape.h (renamed from drivers/gl_context/context_gl.h)52
-rw-r--r--scene/resources/style_box.cpp219
-rw-r--r--scene/resources/style_box.h12
-rw-r--r--scene/resources/tile_set.cpp29
-rw-r--r--scene/resources/tile_set.h20
-rw-r--r--scene/resources/visual_shader.cpp26
-rw-r--r--scene/resources/visual_shader.h2
-rw-r--r--scene/resources/visual_shader_nodes.cpp1040
-rw-r--r--scene/resources/visual_shader_nodes.h570
-rw-r--r--servers/arvr/arvr_interface.cpp5
-rw-r--r--servers/arvr/arvr_interface.h1
-rw-r--r--servers/arvr/arvr_positional_tracker.cpp15
-rw-r--r--servers/arvr/arvr_positional_tracker.h7
-rw-r--r--servers/audio_server.cpp6
-rw-r--r--servers/physics_2d_server.h6
-rw-r--r--servers/physics_server.h6
-rw-r--r--servers/visual/rasterizer.h3
-rw-r--r--servers/visual/visual_server_canvas.cpp2
-rw-r--r--servers/visual/visual_server_viewport.cpp49
-rw-r--r--servers/visual/visual_server_viewport.h1
185 files changed, 5865 insertions, 1624 deletions
diff --git a/AUTHORS.md b/AUTHORS.md
index b7eca2d9b1..99482fb4df 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -45,6 +45,7 @@ name is available.
Błażej Szczygieł (zaps166)
Bojidar Marinov (bojidar-bg)
bruvzg
+ Camille Mohr-Daurat (pouleyKetchoupp)
Carl Olsson (not-surt)
Carter Anderson (cart)
Chris Bradfield (cbscribe)
@@ -115,6 +116,7 @@ name is available.
Pieter-Jan Briers (PJB3005)
Poommetee Ketson (Noshyaar)
Przemysław Gołąb (n-pigeon)
+ Rafał Mikrut (qarmin)
Ralf Hölzemer (rollenrolm)
Ramesh Ravone (RameshRavone)
Ray Koopa (RayKoopa)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4c4a8a37a6..c27bee2b5c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -51,7 +51,7 @@ understand that:
and then figure out why it's failing.
To speed up our work, please prepare for us **a simple project** that isolates
-and reproduces the issue. This is always the **the best way for us to fix it**.
+and reproduces the issue. This is always the **best way for us to fix it**.
You can attach a zip file with the minimal project directly to the bug report,
by drag and dropping the file in the GitHub edition field.
diff --git a/DONORS.md b/DONORS.md
index 05d7f3b7c1..fc332d4beb 100644
--- a/DONORS.md
+++ b/DONORS.md
@@ -18,22 +18,21 @@ generous deed immortalized in the next stable release of Godot Engine.
Gamblify <https://www.gamblify.com>
Image Campus <https://www.imagecampus.edu.ar>
- Yakaz.com <https://yakaz.com>
## Mini sponsors
Alan Beauchamp
Anandarup Mallik
Andrew Dunai
- Arda Erol
Brandon Lamb
Christian Uldall Pedersen
Christoph Woinke
+ Connor Hill
Edward Flick
GameDev.net
GameDev.tv
Hein-Pieter van Braam
- Jamal Alyafei
+ Jacob McKenney
Javary Games
Jay Sistar
Justin Arnold
@@ -43,22 +42,18 @@ generous deed immortalized in the next stable release of Godot Engine.
Matthieu Huvé
Maxim Karsten
Mike King
- Nathan Warden
Neal Gompa (Conan Kudo)
Patrick Aarstad
"Rainway "
- Ruslan Mustakov
Slobodan Milnovic
StarFlare Software
Stephan Lanfermann
- Stoney Meyerhoeffer
- thechris
+ TigerJ
VilliHaukka
Zashi
## Gold donors
- Asdf
Brandon Waite
cheese65536
David Gehrig
@@ -69,8 +64,10 @@ generous deed immortalized in the next stable release of Godot Engine.
Nathanael Beisiegel
Officine Pixel S.n.c.
Retro Village
+ Sofox
Zaven Muradyan
+ Alexander Trey Saunders
Allen Schade
Andreas Schüle
Asher Glick
@@ -80,7 +77,6 @@ generous deed immortalized in the next stable release of Godot Engine.
David Giardi
Edward E
Florian Breisch
- Gary Oberbrunner
Gero
Jay Horton
Jon Smith
@@ -88,6 +84,8 @@ generous deed immortalized in the next stable release of Godot Engine.
Jorge Bernal
Joshua Lesperance
Justo Delgado Baudí
+ Karl Werf
+ Kommentgames
Krzysztof Dluzniewski
Moonwards
Mored1984
@@ -95,6 +93,7 @@ generous deed immortalized in the next stable release of Godot Engine.
paul gruenbacher
Paul LaMotte
Rob Messick
+ Ross Esmond
Scott Wadden
Sergey
Svenne Krap
@@ -103,19 +102,20 @@ generous deed immortalized in the next stable release of Godot Engine.
Wyatt Goodin
Xananax
- BanjoNode2D
- Beliar
+ Abel Oroz Vicente
Chris Serino
Christian Padilla
Conrad Curry
Craig Smith
Daniel Egger
Dean Harmon
+ Ian Richard Kunert
Ivan Trombley
Joan Fons
Krzysztof Jankowski
Lord Bloodhound
Lucas Ferreira Franca
+ Michele Zilli
Nathan Lundquist
Pascal Grüter
Petr Malac
@@ -125,27 +125,34 @@ generous deed immortalized in the next stable release of Godot Engine.
Ronnie Ashlock
ScottMakesGames
Thomas Bjarnelöf
+ Vincent Henderson
Wojciech Chojnacki
Xavier PATRICELLI
Alessandra Pereyra
Alexey Dyadchenko
Andrew Bowen
+ Asdf
Benjamin W Flint
Chau Siu Hung
Chris Goddard
Chris Petrich
Christian Leth Jeppesen
+ Christoph Schröder
Cody Parker
ComicSads
D
+ Daniel
+ Daniel Eichler
Deadly Lampshade
+ Eagle 3d
E.G.
Eric
Eric Monson
Ethan Bennis
Eugenio Hugo Salgüero Jáñez
flesk
+ Francisco Javier Moreno Carracedo
gavlig
GGGames.org
Giles Montgomery
@@ -153,21 +160,24 @@ generous deed immortalized in the next stable release of Godot Engine.
Guilherme Felipe de C. G. da Silva
Heath Hayes
Hysteria
- Jalal Chaabane
- Jeppe Zapp
Jose Malheiro
+ Joshua Flores
Juan T Chen
Juraj Móza
Kasper Jeppesen
Klavdij Voncina
Leandro Voltolino
- Lukáš Rendvanský
+ Maarten Elings
+ Malcolm Peralty
Marius Kamm
+ Markus Fehr
Markus Wiesner
Martin Eigel
Marvin
Matt Eunson
+ Matthew Hillier
Max R.R. Collada
+ MegaC
Nick Nikitin
Oliver Dick
oziatek
@@ -175,39 +185,45 @@ generous deed immortalized in the next stable release of Godot Engine.
Paul Von Zimmerman
Pete Goodwin
Ranoller
- ray-tracer
- Ruben Soares Luis
Samuel Judd
- Sofox
+ Scott Pilet
spilldata
Stoned Xander
+ Thomas Krampl
Tobias Bocanegra
+ Urho
WytRabbit
Xavier Fumado Beltran
+ yuanzhe zhou
## Silver donors
1D_Inc
+ Abraham Haskins
Adam Brunnmeier
Adam Carr
Adam Nakonieczny
Adam Smeltzer
Adisibio
+ Aidan O'Flannagain
Alder Stefano
Alessandro Senese
Alexander Gillberg
Alexander Koppe
+ Alex Davies-Moore
Alice Robinson
+ Andreas Evers
Andreas Krampitz
Anthony Bongiovanni
- Arbor Interactive
+ Arda Erol
Arthur S. Muszynski
Aubrey Falconer
Avencherus
- Bailey
Balázs Batári
Bastian Böhm
+ Beliar
Benedikt
+ Ben Phelan
Ben Vercammen
Bernd Jänichen
Blair Allen
@@ -221,14 +237,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Christian Baune
Christian Winter
Christoffer Sundbom
+ Christopher Fisher
Chris Wilson
+ Clay Heaton
Collin Shooltz
- Connor Hill
Daniel Johnson
DanielMaximiano
Daniel Reed
+ David Bullock
David Cravens
David May
+ Diliup Gabadamudalige
Dominik Wetzel
Duobix
Edward Herbert
@@ -238,20 +257,24 @@ generous deed immortalized in the next stable release of Godot Engine.
Eric Martini
Eric McCarthy
Eric Williams
- Fabian Becker
+ Fabian Lökes
fengjiongmax
Foomf
G3Dev sàrl
+ Gary Hulst
Gerrit Großkopf
Grant Clarke
Greg Olson
+ Greg Pennefather
Guldoman
- Haley Aycock
Heribert Hirth
Hiroshi Naruo
+ HMan
Hunter Jones
ialex32x
Igor Buzatovic
+ Iiari
+ Isaac Morton
Jaime Ruiz-Borau Vizárraga
Jako Danar
James A F Manley
@@ -259,6 +282,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Jeremy Kahn
Jesse Dubay
Joel Fivat
+ Joel Setterberg
Johannes Wuensch
Jonas Rudlang
Jonas Yamazaki
@@ -267,14 +291,16 @@ generous deed immortalized in the next stable release of Godot Engine.
Jonathon
Jon Bonazza
Jon Sully
+ Jose Aleman
Josh 'Cheeseness' Bush
Juanfran
Juan Negrier
Judd
Julian Murgia
+ Julius Hackel
Kajornthep Piyanun
KC Chan
- Kevin Boyer
+ kickmaniac
Kiyohiro Kawamura (kyorohiro)
Klagsam
KR McGinley
@@ -289,10 +315,13 @@ generous deed immortalized in the next stable release of Godot Engine.
Major Haul
Malcolm
Markus Michael Egger
+ Martin Holas
+ Matthew Little
Matthias Grandis
Matt Welke
Maxwell
medecau
+ Menno Finlay-Smits
Mertcan Mermerkaya
mhilbrunner
Michael Dürwald
@@ -300,17 +329,19 @@ generous deed immortalized in the next stable release of Godot Engine.
Michael Labbe
Mikael Olsson
Mikayla Hutchinson
+ Mike Cunningham
MoM
Moritz Laass
Moritz Weissenberger
+ MuffinManKen
Natrim
nee
Neil Blakey-Milner
Nerdforge
- Nick Pavlica
Niclas Eriksen
Nicolás Montaña
Nicolas SAN AGUSTIN
+ Nithin Jino
Oscar Norlander
Pan Ip
Patrick Nafarrete
@@ -321,20 +352,29 @@ generous deed immortalized in the next stable release of Godot Engine.
Pierre-Igor Berthet
Pietro Vertechi
Piotr Kaczmarski
+ Pitsanu Tongprasin
+ Poryg
Prokhorenko Leonid
Psyagnostic
Rafael
+ Raphael Leroux
Rémi Verschelde
+ Reneator
Ricardo Alcantara
Richman Stewart
+ Rob Crowle
Robert Farr (Larington)
+ Robert Hernandez
+ Rodrigo Loli
Roger Burgess
Roger Smith
Roland Rząsa
Roman Tinkov
Ryan Cheung
+ Ryan Groom
Ryan Hentz
Sasori Olkof
+ Scott D. Yelich
Sebastian Michailidis
Shane Spoor
Simon Wenner
@@ -348,6 +388,7 @@ generous deed immortalized in the next stable release of Godot Engine.
tiansheng li
Tim
Tim Drumheller
+ Tim Gudex
Tom Larrow
Torsten Crass
Tryggve Sollid
@@ -355,10 +396,13 @@ generous deed immortalized in the next stable release of Godot Engine.
UltyX
Vaiktorg
Victor
+ Vigilant Watch
Viktor Ferenczi
waka nya
Wayne Haak
werner mendizabal
+ Wiley Thompson
+ Will
William Gervasio
William Hogben
Wout Standaert
diff --git a/SConstruct b/SConstruct
index 1271156a28..7b2d49e36f 100644
--- a/SConstruct
+++ b/SConstruct
@@ -5,7 +5,6 @@ EnsureSConsVersion(0, 98, 1)
# System
import glob
import os
-import string
import sys
# Local
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 67de156fc3..98d3e77f66 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -148,7 +148,7 @@ _ResourceLoader::_ResourceLoader() {
singleton = this;
}
-Error _ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error _ResourceSaver::save(const String &p_path, const RES &p_resource, SaverFlags p_flags) {
ERR_FAIL_COND_V(p_resource.is_null(), ERR_INVALID_PARAMETER);
return ResourceSaver::save(p_path, p_resource, p_flags);
@@ -1579,7 +1579,7 @@ _Geometry::_Geometry() {
///////////////////////// FILE
-Error _File::open_encrypted(const String &p_path, int p_mode_flags, const Vector<uint8_t> &p_key) {
+Error _File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
Error err = open(p_path, p_mode_flags);
if (err)
@@ -1596,7 +1596,7 @@ Error _File::open_encrypted(const String &p_path, int p_mode_flags, const Vector
return OK;
}
-Error _File::open_encrypted_pass(const String &p_path, int p_mode_flags, const String &p_pass) {
+Error _File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
Error err = open(p_path, p_mode_flags);
if (err)
@@ -1614,7 +1614,7 @@ Error _File::open_encrypted_pass(const String &p_path, int p_mode_flags, const S
return OK;
}
-Error _File::open_compressed(const String &p_path, int p_mode_flags, int p_compress_mode) {
+Error _File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
FileAccessCompressed *fac = memnew(FileAccessCompressed);
@@ -1631,7 +1631,7 @@ Error _File::open_compressed(const String &p_path, int p_mode_flags, int p_compr
return OK;
}
-Error _File::open(const String &p_path, int p_mode_flags) {
+Error _File::open(const String &p_path, ModeFlags p_mode_flags) {
close();
Error err;
@@ -2453,12 +2453,12 @@ void _Thread::_start_func(void *ud) {
}
}
-Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, int p_priority) {
+Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) {
ERR_FAIL_COND_V(active, ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER);
- ERR_FAIL_INDEX_V(p_priority, 3, ERR_INVALID_PARAMETER);
+ ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER);
ret = Variant();
target_method = p_method;
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 1c26d9b144..2906de4a4a 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -85,7 +85,7 @@ public:
static _ResourceSaver *get_singleton() { return singleton; }
- Error save(const String &p_path, const RES &p_resource, uint32_t p_flags);
+ Error save(const String &p_path, const RES &p_resource, SaverFlags p_flags);
PoolVector<String> get_recognized_extensions(const RES &p_resource);
_ResourceSaver();
@@ -436,11 +436,11 @@ public:
COMPRESSION_GZIP = Compression::MODE_GZIP
};
- Error open_encrypted(const String &p_path, int p_mode_flags, const Vector<uint8_t> &p_key);
- Error open_encrypted_pass(const String &p_path, int p_mode_flags, const String &p_pass);
- Error open_compressed(const String &p_path, int p_mode_flags, int p_compress_mode = 0);
+ Error open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
+ Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
+ Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
- Error open(const String &p_path, int p_mode_flags); ///< open a file
+ Error open(const String &p_path, ModeFlags p_mode_flags); ///< open a file
void close(); ///< close a file
bool is_open() const; ///< true when file is open
@@ -632,10 +632,11 @@ public:
PRIORITY_LOW,
PRIORITY_NORMAL,
- PRIORITY_HIGH
+ PRIORITY_HIGH,
+ PRIORITY_MAX
};
- Error start(Object *p_instance, const StringName &p_method, const Variant &p_userdata = Variant(), int p_priority = PRIORITY_NORMAL);
+ Error start(Object *p_instance, const StringName &p_method, const Variant &p_userdata = Variant(), Priority p_priority = PRIORITY_NORMAL);
String get_id() const;
bool is_active() const;
Variant wait_to_finish();
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 219bdbddd8..f7b446707d 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -249,6 +249,11 @@ void ClassDB::set_current_api(APIType p_api) {
current_api = p_api;
}
+ClassDB::APIType ClassDB::get_current_api() {
+
+ return current_api;
+}
+
HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes;
HashMap<StringName, StringName> ClassDB::resource_base_extensions;
HashMap<StringName, StringName> ClassDB::compat_classes;
diff --git a/core/class_db.h b/core/class_db.h
index 321682d76b..f18a7113d7 100644
--- a/core/class_db.h
+++ b/core/class_db.h
@@ -371,6 +371,7 @@ public:
static void init();
static void set_current_api(APIType p_api);
+ static APIType get_current_api();
static void cleanup();
};
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 6c3b84d49a..e1388ad2ac 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -55,6 +55,7 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
pt->weight_scale = p_weight_scale;
pt->prev_point = NULL;
pt->last_pass = 0;
+ pt->enabled = true;
points[p_id] = pt;
} else {
points[p_id]->pos = p_pos;
@@ -242,6 +243,9 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
pass++;
+ if (!end_point->enabled)
+ return false;
+
SelfList<Point>::List open_list;
bool found_route = false;
@@ -249,6 +253,10 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
for (Set<Point *>::Element *E = begin_point->neighbours.front(); E; E = E->next()) {
Point *n = E->get();
+
+ if (!n->enabled)
+ continue;
+
n->prev_point = begin_point;
n->distance = _compute_cost(begin_point->id, n->id) * n->weight_scale;
n->last_pass = pass;
@@ -290,6 +298,9 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
Point *e = E->get();
+ if (!e->enabled)
+ continue;
+
real_t distance = _compute_cost(p->id, e->id) * e->weight_scale + p->distance;
if (e->last_pass == pass) {
@@ -438,6 +449,14 @@ PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
return path;
}
+void AStar::set_point_disabled(int p_id, bool p_disabled) {
+ points[p_id]->enabled = !p_disabled;
+}
+
+bool AStar::is_point_disabled(int p_id) const {
+ return !points[p_id]->enabled;
+}
+
void AStar::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_available_point_id"), &AStar::get_available_point_id);
@@ -450,6 +469,9 @@ void AStar::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar::has_point);
ClassDB::bind_method(D_METHOD("get_points"), &AStar::get_points);
+ ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar::set_point_disabled, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar::is_point_disabled);
+
ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar::get_point_connections);
ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true));
diff --git a/core/math/a_star.h b/core/math/a_star.h
index d094bc4863..c63e1aa4dc 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -54,6 +54,7 @@ class AStar : public Reference {
Vector3 pos;
real_t weight_scale;
uint64_t last_pass;
+ bool enabled;
Set<Point *> neighbours;
@@ -114,6 +115,9 @@ public:
PoolVector<int> get_point_connections(int p_id);
Array get_points();
+ void set_point_disabled(int p_id, bool p_disabled = true);
+ bool is_point_disabled(int p_id) const;
+
void connect_points(int p_id, int p_with_id, bool bidirectional = true);
void disconnect_points(int p_id, int p_with_id);
bool are_points_connected(int p_id, int p_with_id) const;
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index f970c510e0..ebe0356c93 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -122,6 +122,12 @@ struct AudioFrame {
r = p_frame.r;
}
+ _ALWAYS_INLINE_ AudioFrame operator=(const AudioFrame &p_frame) {
+ l = p_frame.l;
+ r = p_frame.r;
+ return *this;
+ }
+
_ALWAYS_INLINE_ AudioFrame() {}
};
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 708054e4ab..05b49f0815 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -68,6 +68,7 @@ const char *Expression::func_name[Expression::FUNC_MAX] = {
"lerp",
"inverse_lerp",
"range_lerp",
+ "smoothstep",
"dectime",
"randomize",
"randi",
@@ -185,6 +186,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
return 2;
case MATH_LERP:
case MATH_INVERSE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME:
case MATH_WRAP:
case MATH_WRAPF:
@@ -392,6 +394,12 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(4);
*r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
} break;
+ case MATH_SMOOTHSTEP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case MATH_DECTIME: {
VALIDATE_ARG_NUM(0);
diff --git a/core/math/expression.h b/core/math/expression.h
index fa0878c93c..f9075cb689 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -66,6 +66,7 @@ public:
MATH_LERP,
MATH_INVERSE_LERP,
MATH_RANGE_LERP,
+ MATH_SMOOTHSTEP,
MATH_DECTIME,
MATH_RANDOMIZE,
MATH_RAND,
diff --git a/core/math/geometry.h b/core/math/geometry.h
index 4b478b6b16..7347cb742a 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -702,9 +702,11 @@ public:
/* if we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection) then the following can be skipped and we can just return the equivalent of res1 */
sqrtterm = Math::sqrt(sqrtterm);
real_t res1 = (-b - sqrtterm) / (2 * a);
- //real_t res2 = ( -b + sqrtterm ) / (2 * a);
+ real_t res2 = (-b + sqrtterm) / (2 * a);
- return (res1 >= 0 && res1 <= 1) ? res1 : -1;
+ if (res1 >= 0 && res1 <= 1) return res1;
+ if (res2 >= 0 && res2 <= 1) return res2;
+ return -1;
}
static inline Vector<Vector3> clip_polygon(const Vector<Vector3> &polygon, const Plane &p_plane) {
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 6ac6839827..0d209402dd 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -208,6 +208,17 @@ public:
static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_weight) {
+ if (is_equal_approx(p_from, p_to)) return p_from;
+ double x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
+ return x * x * (3.0 - 2.0 * x);
+ }
+ static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_weight) {
+ if (is_equal_approx(p_from, p_to)) return p_from;
+ float x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
+ return x * x * (3.0f - 2.0f * x);
+ }
+
static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
diff --git a/core/math/quat.h b/core/math/quat.h
index 7d71ec03e8..8ed2fa7cc2 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -131,6 +131,14 @@ public:
w(q.w) {
}
+ Quat operator=(const Quat &q) {
+ x = q.x;
+ y = q.y;
+ z = q.z;
+ w = q.w;
+ return *this;
+ }
+
Quat(const Vector3 &v0, const Vector3 &v1) // shortest arc
{
Vector3 c = v0.cross(v1);
diff --git a/core/math/random_number_generator.cpp b/core/math/random_number_generator.cpp
index fccc0f72fe..6add00c1d8 100644
--- a/core/math/random_number_generator.cpp
+++ b/core/math/random_number_generator.cpp
@@ -40,6 +40,7 @@ void RandomNumberGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("randi"), &RandomNumberGenerator::randi);
ClassDB::bind_method(D_METHOD("randf"), &RandomNumberGenerator::randf);
+ ClassDB::bind_method(D_METHOD("randfn", "mean", "deviation"), &RandomNumberGenerator::randfn, DEFVAL(0.0), DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("randf_range", "from", "to"), &RandomNumberGenerator::randf_range);
ClassDB::bind_method(D_METHOD("randi_range", "from", "to"), &RandomNumberGenerator::randi_range);
ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize);
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index 66c77b8ccf..6b6bcdd2cd 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -55,6 +55,8 @@ public:
_FORCE_INLINE_ real_t randf_range(real_t from, real_t to) { return randbase.random(from, to); }
+ _FORCE_INLINE_ real_t randfn(real_t mean = 0.0, real_t deviation = 1.0) { return randbase.randfn(mean, deviation); }
+
_FORCE_INLINE_ int randi_range(int from, int to) {
unsigned int ret = randbase.rand();
return ret % (to - from + 1) + from;
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index cd721ef4d1..0d1b311c0d 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -31,6 +31,8 @@
#ifndef RANDOM_PCG_H
#define RANDOM_PCG_H
+#include <math.h>
+
#include "core/math/math_defs.h"
#include "thirdparty/misc/pcg.h"
@@ -61,6 +63,13 @@ public:
_FORCE_INLINE_ double randd() { return (double)rand() / (double)RANDOM_MAX; }
_FORCE_INLINE_ float randf() { return (float)rand() / (float)RANDOM_MAX; }
+ _FORCE_INLINE_ double randfn(double p_mean, double p_deviation) {
+ return p_mean + p_deviation * (cos(Math_TAU * randd()) * sqrt(-2.0 * log(randd()))); // Box-Muller transform
+ }
+ _FORCE_INLINE_ float randfn(float p_mean, float p_deviation) {
+ return p_mean + p_deviation * (cos(Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform
+ }
+
double random(double p_from, double p_to);
float random(float p_from, float p_to);
real_t random(int p_from, int p_to) { return (real_t)random((real_t)p_from, (real_t)p_to); }
diff --git a/core/math/vector2.h b/core/math/vector2.h
index a20326f667..ae2d1ec660 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -65,6 +65,7 @@ struct Vector2 {
real_t distance_squared_to(const Vector2 &p_vector2) const;
real_t angle_to(const Vector2 &p_vector2) const;
real_t angle_to_point(const Vector2 &p_vector2) const;
+ _FORCE_INLINE_ Vector2 direction_to(const Vector2 &p_b) const;
real_t dot(const Vector2 &p_other) const;
real_t cross(const Vector2 &p_other) const;
@@ -236,6 +237,12 @@ Vector2 Vector2::slerp(const Vector2 &p_b, real_t p_t) const {
return rotated(theta * p_t);
}
+Vector2 Vector2::direction_to(const Vector2 &p_b) const {
+ Vector2 ret(p_b.x - x, p_b.y - y);
+ ret.normalize();
+ return ret;
+}
+
Vector2 Vector2::linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t) {
Vector2 res = p_a;
diff --git a/core/math/vector3.h b/core/math/vector3.h
index b11838d16e..e9074c5bd4 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -112,6 +112,7 @@ struct Vector3 {
_FORCE_INLINE_ Vector3 project(const Vector3 &p_b) const;
_FORCE_INLINE_ real_t angle_to(const Vector3 &p_b) const;
+ _FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_b) const;
_FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const;
_FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const;
@@ -244,6 +245,12 @@ real_t Vector3::angle_to(const Vector3 &p_b) const {
return Math::atan2(cross(p_b).length(), dot(p_b));
}
+Vector3 Vector3::direction_to(const Vector3 &p_b) const {
+ Vector3 ret(p_b.x - x, p_b.y - y, p_b.z - z);
+ ret.normalize();
+ return ret;
+}
+
/* Operators */
Vector3 &Vector3::operator+=(const Vector3 &p_v) {
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 8c9a3dbcd4..5752cdca2b 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -1004,6 +1004,8 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
+ GLOBAL_DEF("audio/default_bus_layout", "res://default_bus_layout.tres");
+ custom_prop_info["audio/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
action = Dictionary();
action["deadzone"] = Variant(0.5f);
diff --git a/core/ucaps.h b/core/ucaps.h
index 5dd81296dd..ae5729a53d 100644
--- a/core/ucaps.h
+++ b/core/ucaps.h
@@ -704,672 +704,672 @@ static const int caps_table[CAPS_LEN][2] = {
};
static const int reverse_caps_table[CAPS_LEN - 1][2] = {
- { 0x41, 0x61 },
- { 0x42, 0x62 },
- { 0x43, 0x63 },
- { 0x44, 0x64 },
- { 0x45, 0x65 },
- { 0x46, 0x66 },
- { 0x47, 0x67 },
- { 0x48, 0x68 },
- { 0x49, 0x69 },
- { 0x4a, 0x6a },
- { 0x4b, 0x6b },
- { 0x4c, 0x6c },
- { 0x4d, 0x6d },
- { 0x4e, 0x6e },
- { 0x4f, 0x6f },
- { 0x50, 0x70 },
- { 0x51, 0x71 },
- { 0x52, 0x72 },
- { 0x53, 0x73 },
- { 0x54, 0x74 },
- { 0x55, 0x75 },
- { 0x56, 0x76 },
- { 0x57, 0x77 },
- { 0x58, 0x78 },
- { 0x59, 0x79 },
- { 0x5a, 0x7a },
- { 0xc0, 0xe0 },
- { 0xc1, 0xe1 },
- { 0xc2, 0xe2 },
- { 0xc3, 0xe3 },
- { 0xc4, 0xe4 },
- { 0xc5, 0xe5 },
- { 0xc6, 0xe6 },
- { 0xc7, 0xe7 },
- { 0xc8, 0xe8 },
- { 0xc9, 0xe9 },
- { 0xca, 0xea },
- { 0xcb, 0xeb },
- { 0xcc, 0xec },
- { 0xcd, 0xed },
- { 0xce, 0xee },
- { 0xcf, 0xef },
- { 0xd0, 0xf0 },
- { 0xd1, 0xf1 },
- { 0xd2, 0xf2 },
- { 0xd3, 0xf3 },
- { 0xd4, 0xf4 },
- { 0xd5, 0xf5 },
- { 0xd6, 0xf6 },
- { 0xd8, 0xf8 },
- { 0xd9, 0xf9 },
- { 0xda, 0xfa },
- { 0xdb, 0xfb },
- { 0xdc, 0xfc },
- { 0xdd, 0xfd },
- { 0xde, 0xfe },
- { 0x178, 0xff },
- { 0x100, 0x101 },
- { 0x102, 0x103 },
- { 0x104, 0x105 },
- { 0x106, 0x107 },
- { 0x108, 0x109 },
- { 0x10a, 0x10b },
- { 0x10c, 0x10d },
- { 0x10e, 0x10f },
- { 0x110, 0x111 },
- { 0x112, 0x113 },
- { 0x114, 0x115 },
- { 0x116, 0x117 },
- { 0x118, 0x119 },
- { 0x11a, 0x11b },
- { 0x11c, 0x11d },
- { 0x11e, 0x11f },
- { 0x120, 0x121 },
- { 0x122, 0x123 },
- { 0x124, 0x125 },
- { 0x126, 0x127 },
- { 0x128, 0x129 },
- { 0x12a, 0x12b },
- { 0x12c, 0x12d },
- { 0x12e, 0x12f },
- //{0x49,0x131},
- { 0x132, 0x133 },
- { 0x134, 0x135 },
- { 0x136, 0x137 },
- { 0x139, 0x13a },
- { 0x13b, 0x13c },
- { 0x13d, 0x13e },
- { 0x13f, 0x140 },
- { 0x141, 0x142 },
- { 0x143, 0x144 },
- { 0x145, 0x146 },
- { 0x147, 0x148 },
- { 0x14a, 0x14b },
- { 0x14c, 0x14d },
- { 0x14e, 0x14f },
- { 0x150, 0x151 },
- { 0x152, 0x153 },
- { 0x154, 0x155 },
- { 0x156, 0x157 },
- { 0x158, 0x159 },
- { 0x15a, 0x15b },
- { 0x15c, 0x15d },
- { 0x15e, 0x15f },
- { 0x160, 0x161 },
- { 0x162, 0x163 },
- { 0x164, 0x165 },
- { 0x166, 0x167 },
- { 0x168, 0x169 },
- { 0x16a, 0x16b },
- { 0x16c, 0x16d },
- { 0x16e, 0x16f },
- { 0x170, 0x171 },
- { 0x172, 0x173 },
- { 0x174, 0x175 },
- { 0x176, 0x177 },
- { 0x179, 0x17a },
- { 0x17b, 0x17c },
- { 0x17d, 0x17e },
- { 0x182, 0x183 },
- { 0x184, 0x185 },
- { 0x187, 0x188 },
- { 0x18b, 0x18c },
- { 0x191, 0x192 },
- { 0x198, 0x199 },
- { 0x1a0, 0x1a1 },
- { 0x1a2, 0x1a3 },
- { 0x1a4, 0x1a5 },
- { 0x1a7, 0x1a8 },
- { 0x1ac, 0x1ad },
- { 0x1af, 0x1b0 },
- { 0x1b3, 0x1b4 },
- { 0x1b5, 0x1b6 },
- { 0x1b8, 0x1b9 },
- { 0x1bc, 0x1bd },
- { 0x1c4, 0x1c6 },
- { 0x1c7, 0x1c9 },
- { 0x1ca, 0x1cc },
- { 0x1cd, 0x1ce },
- { 0x1cf, 0x1d0 },
- { 0x1d1, 0x1d2 },
- { 0x1d3, 0x1d4 },
- { 0x1d5, 0x1d6 },
- { 0x1d7, 0x1d8 },
- { 0x1d9, 0x1da },
- { 0x1db, 0x1dc },
- { 0x1de, 0x1df },
- { 0x1e0, 0x1e1 },
- { 0x1e2, 0x1e3 },
- { 0x1e4, 0x1e5 },
- { 0x1e6, 0x1e7 },
- { 0x1e8, 0x1e9 },
- { 0x1ea, 0x1eb },
- { 0x1ec, 0x1ed },
- { 0x1ee, 0x1ef },
- { 0x1f1, 0x1f3 },
- { 0x1f4, 0x1f5 },
- { 0x1fa, 0x1fb },
- { 0x1fc, 0x1fd },
- { 0x1fe, 0x1ff },
- { 0x200, 0x201 },
- { 0x202, 0x203 },
- { 0x204, 0x205 },
- { 0x206, 0x207 },
- { 0x208, 0x209 },
- { 0x20a, 0x20b },
- { 0x20c, 0x20d },
- { 0x20e, 0x20f },
- { 0x210, 0x211 },
- { 0x212, 0x213 },
- { 0x214, 0x215 },
- { 0x216, 0x217 },
- { 0x181, 0x253 },
- { 0x186, 0x254 },
- { 0x18a, 0x257 },
- { 0x18e, 0x258 },
- { 0x18f, 0x259 },
- { 0x190, 0x25b },
- { 0x193, 0x260 },
- { 0x194, 0x263 },
- { 0x197, 0x268 },
- { 0x196, 0x269 },
- { 0x19c, 0x26f },
- { 0x19d, 0x272 },
- { 0x19f, 0x275 },
- { 0x1a9, 0x283 },
- { 0x1ae, 0x288 },
- { 0x1b1, 0x28a },
- { 0x1b2, 0x28b },
- { 0x1b7, 0x292 },
- { 0x386, 0x3ac },
- { 0x388, 0x3ad },
- { 0x389, 0x3ae },
- { 0x38a, 0x3af },
- { 0x391, 0x3b1 },
- { 0x392, 0x3b2 },
- { 0x393, 0x3b3 },
- { 0x394, 0x3b4 },
- { 0x395, 0x3b5 },
- { 0x396, 0x3b6 },
- { 0x397, 0x3b7 },
- { 0x398, 0x3b8 },
- { 0x399, 0x3b9 },
- { 0x39a, 0x3ba },
- { 0x39b, 0x3bb },
- { 0x39c, 0x3bc },
- { 0x39d, 0x3bd },
- { 0x39e, 0x3be },
- { 0x39f, 0x3bf },
- { 0x3a0, 0x3c0 },
- { 0x3a1, 0x3c1 },
- { 0x3a3, 0x3c3 },
- { 0x3a4, 0x3c4 },
- { 0x3a5, 0x3c5 },
- { 0x3a6, 0x3c6 },
- { 0x3a7, 0x3c7 },
- { 0x3a8, 0x3c8 },
- { 0x3a9, 0x3c9 },
- { 0x3aa, 0x3ca },
- { 0x3ab, 0x3cb },
- { 0x38c, 0x3cc },
- { 0x38e, 0x3cd },
- { 0x38f, 0x3ce },
- { 0x3e2, 0x3e3 },
- { 0x3e4, 0x3e5 },
- { 0x3e6, 0x3e7 },
- { 0x3e8, 0x3e9 },
- { 0x3ea, 0x3eb },
- { 0x3ec, 0x3ed },
- { 0x3ee, 0x3ef },
- { 0x410, 0x430 },
- { 0x411, 0x431 },
- { 0x412, 0x432 },
- { 0x413, 0x433 },
- { 0x414, 0x434 },
- { 0x415, 0x435 },
- { 0x416, 0x436 },
- { 0x417, 0x437 },
- { 0x418, 0x438 },
- { 0x419, 0x439 },
- { 0x41a, 0x43a },
- { 0x41b, 0x43b },
- { 0x41c, 0x43c },
- { 0x41d, 0x43d },
- { 0x41e, 0x43e },
- { 0x41f, 0x43f },
- { 0x420, 0x440 },
- { 0x421, 0x441 },
- { 0x422, 0x442 },
- { 0x423, 0x443 },
- { 0x424, 0x444 },
- { 0x425, 0x445 },
- { 0x426, 0x446 },
- { 0x427, 0x447 },
- { 0x428, 0x448 },
- { 0x429, 0x449 },
- { 0x42a, 0x44a },
- { 0x42b, 0x44b },
- { 0x42c, 0x44c },
- { 0x42d, 0x44d },
- { 0x42e, 0x44e },
- { 0x42f, 0x44f },
- { 0x401, 0x451 },
- { 0x402, 0x452 },
- { 0x403, 0x453 },
- { 0x404, 0x454 },
- { 0x405, 0x455 },
- { 0x406, 0x456 },
- { 0x407, 0x457 },
- { 0x408, 0x458 },
- { 0x409, 0x459 },
- { 0x40a, 0x45a },
- { 0x40b, 0x45b },
- { 0x40c, 0x45c },
- { 0x40e, 0x45e },
- { 0x40f, 0x45f },
- { 0x460, 0x461 },
- { 0x462, 0x463 },
- { 0x464, 0x465 },
- { 0x466, 0x467 },
- { 0x468, 0x469 },
- { 0x46a, 0x46b },
- { 0x46c, 0x46d },
- { 0x46e, 0x46f },
- { 0x470, 0x471 },
- { 0x472, 0x473 },
- { 0x474, 0x475 },
- { 0x476, 0x477 },
- { 0x478, 0x479 },
- { 0x47a, 0x47b },
- { 0x47c, 0x47d },
- { 0x47e, 0x47f },
- { 0x480, 0x481 },
- { 0x490, 0x491 },
- { 0x492, 0x493 },
- { 0x494, 0x495 },
- { 0x496, 0x497 },
- { 0x498, 0x499 },
- { 0x49a, 0x49b },
- { 0x49c, 0x49d },
- { 0x49e, 0x49f },
- { 0x4a0, 0x4a1 },
- { 0x4a2, 0x4a3 },
- { 0x4a4, 0x4a5 },
- { 0x4a6, 0x4a7 },
- { 0x4a8, 0x4a9 },
- { 0x4aa, 0x4ab },
- { 0x4ac, 0x4ad },
- { 0x4ae, 0x4af },
- { 0x4b0, 0x4b1 },
- { 0x4b2, 0x4b3 },
- { 0x4b4, 0x4b5 },
- { 0x4b6, 0x4b7 },
- { 0x4b8, 0x4b9 },
- { 0x4ba, 0x4bb },
- { 0x4bc, 0x4bd },
- { 0x4be, 0x4bf },
- { 0x4c1, 0x4c2 },
- { 0x4c3, 0x4c4 },
- { 0x4c7, 0x4c8 },
- { 0x4cb, 0x4cc },
- { 0x4d0, 0x4d1 },
- { 0x4d2, 0x4d3 },
- { 0x4d4, 0x4d5 },
- { 0x4d6, 0x4d7 },
- { 0x4d8, 0x4d9 },
- { 0x4da, 0x4db },
- { 0x4dc, 0x4dd },
- { 0x4de, 0x4df },
- { 0x4e0, 0x4e1 },
- { 0x4e2, 0x4e3 },
- { 0x4e4, 0x4e5 },
- { 0x4e6, 0x4e7 },
- { 0x4e8, 0x4e9 },
- { 0x4ea, 0x4eb },
- { 0x4ee, 0x4ef },
- { 0x4f0, 0x4f1 },
- { 0x4f2, 0x4f3 },
- { 0x4f4, 0x4f5 },
- { 0x4f8, 0x4f9 },
- { 0x531, 0x561 },
- { 0x532, 0x562 },
- { 0x533, 0x563 },
- { 0x534, 0x564 },
- { 0x535, 0x565 },
- { 0x536, 0x566 },
- { 0x537, 0x567 },
- { 0x538, 0x568 },
- { 0x539, 0x569 },
- { 0x53a, 0x56a },
- { 0x53b, 0x56b },
- { 0x53c, 0x56c },
- { 0x53d, 0x56d },
- { 0x53e, 0x56e },
- { 0x53f, 0x56f },
- { 0x540, 0x570 },
- { 0x541, 0x571 },
- { 0x542, 0x572 },
- { 0x543, 0x573 },
- { 0x544, 0x574 },
- { 0x545, 0x575 },
- { 0x546, 0x576 },
- { 0x547, 0x577 },
- { 0x548, 0x578 },
- { 0x549, 0x579 },
- { 0x54a, 0x57a },
- { 0x54b, 0x57b },
- { 0x54c, 0x57c },
- { 0x54d, 0x57d },
- { 0x54e, 0x57e },
- { 0x54f, 0x57f },
- { 0x550, 0x580 },
- { 0x551, 0x581 },
- { 0x552, 0x582 },
- { 0x553, 0x583 },
- { 0x554, 0x584 },
- { 0x555, 0x585 },
- { 0x556, 0x586 },
- { 0x10a0, 0x10d0 },
- { 0x10a1, 0x10d1 },
- { 0x10a2, 0x10d2 },
- { 0x10a3, 0x10d3 },
- { 0x10a4, 0x10d4 },
- { 0x10a5, 0x10d5 },
- { 0x10a6, 0x10d6 },
- { 0x10a7, 0x10d7 },
- { 0x10a8, 0x10d8 },
- { 0x10a9, 0x10d9 },
- { 0x10aa, 0x10da },
- { 0x10ab, 0x10db },
- { 0x10ac, 0x10dc },
- { 0x10ad, 0x10dd },
- { 0x10ae, 0x10de },
- { 0x10af, 0x10df },
- { 0x10b0, 0x10e0 },
- { 0x10b1, 0x10e1 },
- { 0x10b2, 0x10e2 },
- { 0x10b3, 0x10e3 },
- { 0x10b4, 0x10e4 },
- { 0x10b5, 0x10e5 },
- { 0x10b6, 0x10e6 },
- { 0x10b7, 0x10e7 },
- { 0x10b8, 0x10e8 },
- { 0x10b9, 0x10e9 },
- { 0x10ba, 0x10ea },
- { 0x10bb, 0x10eb },
- { 0x10bc, 0x10ec },
- { 0x10bd, 0x10ed },
- { 0x10be, 0x10ee },
- { 0x10bf, 0x10ef },
- { 0x10c0, 0x10f0 },
- { 0x10c1, 0x10f1 },
- { 0x10c2, 0x10f2 },
- { 0x10c3, 0x10f3 },
- { 0x10c4, 0x10f4 },
- { 0x10c5, 0x10f5 },
- { 0x1e00, 0x1e01 },
- { 0x1e02, 0x1e03 },
- { 0x1e04, 0x1e05 },
- { 0x1e06, 0x1e07 },
- { 0x1e08, 0x1e09 },
- { 0x1e0a, 0x1e0b },
- { 0x1e0c, 0x1e0d },
- { 0x1e0e, 0x1e0f },
- { 0x1e10, 0x1e11 },
- { 0x1e12, 0x1e13 },
- { 0x1e14, 0x1e15 },
- { 0x1e16, 0x1e17 },
- { 0x1e18, 0x1e19 },
- { 0x1e1a, 0x1e1b },
- { 0x1e1c, 0x1e1d },
- { 0x1e1e, 0x1e1f },
- { 0x1e20, 0x1e21 },
- { 0x1e22, 0x1e23 },
- { 0x1e24, 0x1e25 },
- { 0x1e26, 0x1e27 },
- { 0x1e28, 0x1e29 },
- { 0x1e2a, 0x1e2b },
- { 0x1e2c, 0x1e2d },
- { 0x1e2e, 0x1e2f },
- { 0x1e30, 0x1e31 },
- { 0x1e32, 0x1e33 },
- { 0x1e34, 0x1e35 },
- { 0x1e36, 0x1e37 },
- { 0x1e38, 0x1e39 },
- { 0x1e3a, 0x1e3b },
- { 0x1e3c, 0x1e3d },
- { 0x1e3e, 0x1e3f },
- { 0x1e40, 0x1e41 },
- { 0x1e42, 0x1e43 },
- { 0x1e44, 0x1e45 },
- { 0x1e46, 0x1e47 },
- { 0x1e48, 0x1e49 },
- { 0x1e4a, 0x1e4b },
- { 0x1e4c, 0x1e4d },
- { 0x1e4e, 0x1e4f },
- { 0x1e50, 0x1e51 },
- { 0x1e52, 0x1e53 },
- { 0x1e54, 0x1e55 },
- { 0x1e56, 0x1e57 },
- { 0x1e58, 0x1e59 },
- { 0x1e5a, 0x1e5b },
- { 0x1e5c, 0x1e5d },
- { 0x1e5e, 0x1e5f },
- { 0x1e60, 0x1e61 },
- { 0x1e62, 0x1e63 },
- { 0x1e64, 0x1e65 },
- { 0x1e66, 0x1e67 },
- { 0x1e68, 0x1e69 },
- { 0x1e6a, 0x1e6b },
- { 0x1e6c, 0x1e6d },
- { 0x1e6e, 0x1e6f },
- { 0x1e70, 0x1e71 },
- { 0x1e72, 0x1e73 },
- { 0x1e74, 0x1e75 },
- { 0x1e76, 0x1e77 },
- { 0x1e78, 0x1e79 },
- { 0x1e7a, 0x1e7b },
- { 0x1e7c, 0x1e7d },
- { 0x1e7e, 0x1e7f },
- { 0x1e80, 0x1e81 },
- { 0x1e82, 0x1e83 },
- { 0x1e84, 0x1e85 },
- { 0x1e86, 0x1e87 },
- { 0x1e88, 0x1e89 },
- { 0x1e8a, 0x1e8b },
- { 0x1e8c, 0x1e8d },
- { 0x1e8e, 0x1e8f },
- { 0x1e90, 0x1e91 },
- { 0x1e92, 0x1e93 },
- { 0x1e94, 0x1e95 },
- { 0x1ea0, 0x1ea1 },
- { 0x1ea2, 0x1ea3 },
- { 0x1ea4, 0x1ea5 },
- { 0x1ea6, 0x1ea7 },
- { 0x1ea8, 0x1ea9 },
- { 0x1eaa, 0x1eab },
- { 0x1eac, 0x1ead },
- { 0x1eae, 0x1eaf },
- { 0x1eb0, 0x1eb1 },
- { 0x1eb2, 0x1eb3 },
- { 0x1eb4, 0x1eb5 },
- { 0x1eb6, 0x1eb7 },
- { 0x1eb8, 0x1eb9 },
- { 0x1eba, 0x1ebb },
- { 0x1ebc, 0x1ebd },
- { 0x1ebe, 0x1ebf },
- { 0x1ec0, 0x1ec1 },
- { 0x1ec2, 0x1ec3 },
- { 0x1ec4, 0x1ec5 },
- { 0x1ec6, 0x1ec7 },
- { 0x1ec8, 0x1ec9 },
- { 0x1eca, 0x1ecb },
- { 0x1ecc, 0x1ecd },
- { 0x1ece, 0x1ecf },
- { 0x1ed0, 0x1ed1 },
- { 0x1ed2, 0x1ed3 },
- { 0x1ed4, 0x1ed5 },
- { 0x1ed6, 0x1ed7 },
- { 0x1ed8, 0x1ed9 },
- { 0x1eda, 0x1edb },
- { 0x1edc, 0x1edd },
- { 0x1ede, 0x1edf },
- { 0x1ee0, 0x1ee1 },
- { 0x1ee2, 0x1ee3 },
- { 0x1ee4, 0x1ee5 },
- { 0x1ee6, 0x1ee7 },
- { 0x1ee8, 0x1ee9 },
- { 0x1eea, 0x1eeb },
- { 0x1eec, 0x1eed },
- { 0x1eee, 0x1eef },
- { 0x1ef0, 0x1ef1 },
- { 0x1ef2, 0x1ef3 },
- { 0x1ef4, 0x1ef5 },
- { 0x1ef6, 0x1ef7 },
- { 0x1ef8, 0x1ef9 },
- { 0x1f08, 0x1f00 },
- { 0x1f09, 0x1f01 },
- { 0x1f0a, 0x1f02 },
- { 0x1f0b, 0x1f03 },
- { 0x1f0c, 0x1f04 },
- { 0x1f0d, 0x1f05 },
- { 0x1f0e, 0x1f06 },
- { 0x1f0f, 0x1f07 },
- { 0x1f18, 0x1f10 },
- { 0x1f19, 0x1f11 },
- { 0x1f1a, 0x1f12 },
- { 0x1f1b, 0x1f13 },
- { 0x1f1c, 0x1f14 },
- { 0x1f1d, 0x1f15 },
- { 0x1f28, 0x1f20 },
- { 0x1f29, 0x1f21 },
- { 0x1f2a, 0x1f22 },
- { 0x1f2b, 0x1f23 },
- { 0x1f2c, 0x1f24 },
- { 0x1f2d, 0x1f25 },
- { 0x1f2e, 0x1f26 },
- { 0x1f2f, 0x1f27 },
- { 0x1f38, 0x1f30 },
- { 0x1f39, 0x1f31 },
- { 0x1f3a, 0x1f32 },
- { 0x1f3b, 0x1f33 },
- { 0x1f3c, 0x1f34 },
- { 0x1f3d, 0x1f35 },
- { 0x1f3e, 0x1f36 },
- { 0x1f3f, 0x1f37 },
- { 0x1f48, 0x1f40 },
- { 0x1f49, 0x1f41 },
- { 0x1f4a, 0x1f42 },
- { 0x1f4b, 0x1f43 },
- { 0x1f4c, 0x1f44 },
- { 0x1f4d, 0x1f45 },
- { 0x1f59, 0x1f51 },
- { 0x1f5b, 0x1f53 },
- { 0x1f5d, 0x1f55 },
- { 0x1f5f, 0x1f57 },
- { 0x1f68, 0x1f60 },
- { 0x1f69, 0x1f61 },
- { 0x1f6a, 0x1f62 },
- { 0x1f6b, 0x1f63 },
- { 0x1f6c, 0x1f64 },
- { 0x1f6d, 0x1f65 },
- { 0x1f6e, 0x1f66 },
- { 0x1f6f, 0x1f67 },
- { 0x1f88, 0x1f80 },
- { 0x1f89, 0x1f81 },
- { 0x1f8a, 0x1f82 },
- { 0x1f8b, 0x1f83 },
- { 0x1f8c, 0x1f84 },
- { 0x1f8d, 0x1f85 },
- { 0x1f8e, 0x1f86 },
- { 0x1f8f, 0x1f87 },
- { 0x1f98, 0x1f90 },
- { 0x1f99, 0x1f91 },
- { 0x1f9a, 0x1f92 },
- { 0x1f9b, 0x1f93 },
- { 0x1f9c, 0x1f94 },
- { 0x1f9d, 0x1f95 },
- { 0x1f9e, 0x1f96 },
- { 0x1f9f, 0x1f97 },
- { 0x1fa8, 0x1fa0 },
- { 0x1fa9, 0x1fa1 },
- { 0x1faa, 0x1fa2 },
- { 0x1fab, 0x1fa3 },
- { 0x1fac, 0x1fa4 },
- { 0x1fad, 0x1fa5 },
- { 0x1fae, 0x1fa6 },
- { 0x1faf, 0x1fa7 },
- { 0x1fb8, 0x1fb0 },
- { 0x1fb9, 0x1fb1 },
- { 0x1fd8, 0x1fd0 },
- { 0x1fd9, 0x1fd1 },
- { 0x1fe8, 0x1fe0 },
- { 0x1fe9, 0x1fe1 },
- { 0x24b6, 0x24d0 },
- { 0x24b7, 0x24d1 },
- { 0x24b8, 0x24d2 },
- { 0x24b9, 0x24d3 },
- { 0x24ba, 0x24d4 },
- { 0x24bb, 0x24d5 },
- { 0x24bc, 0x24d6 },
- { 0x24bd, 0x24d7 },
- { 0x24be, 0x24d8 },
- { 0x24bf, 0x24d9 },
- { 0x24c0, 0x24da },
- { 0x24c1, 0x24db },
- { 0x24c2, 0x24dc },
- { 0x24c3, 0x24dd },
- { 0x24c4, 0x24de },
- { 0x24c5, 0x24df },
- { 0x24c6, 0x24e0 },
- { 0x24c7, 0x24e1 },
- { 0x24c8, 0x24e2 },
- { 0x24c9, 0x24e3 },
- { 0x24ca, 0x24e4 },
- { 0x24cb, 0x24e5 },
- { 0x24cc, 0x24e6 },
- { 0x24cd, 0x24e7 },
- { 0x24ce, 0x24e8 },
- { 0x24cf, 0x24e9 },
- { 0xff21, 0xff41 },
- { 0xff22, 0xff42 },
- { 0xff23, 0xff43 },
- { 0xff24, 0xff44 },
- { 0xff25, 0xff45 },
- { 0xff26, 0xff46 },
- { 0xff27, 0xff47 },
- { 0xff28, 0xff48 },
- { 0xff29, 0xff49 },
- { 0xff2a, 0xff4a },
- { 0xff2b, 0xff4b },
- { 0xff2c, 0xff4c },
- { 0xff2d, 0xff4d },
- { 0xff2e, 0xff4e },
- { 0xff2f, 0xff4f },
- { 0xff30, 0xff50 },
- { 0xff31, 0xff51 },
- { 0xff32, 0xff52 },
- { 0xff33, 0xff53 },
- { 0xff34, 0xff54 },
- { 0xff35, 0xff55 },
- { 0xff36, 0xff56 },
- { 0xff37, 0xff57 },
- { 0xff38, 0xff58 },
- { 0xff39, 0xff59 },
- { 0xff3a, 0xff5a }
+ { 0x0041, 0x0061 },
+ { 0x0042, 0x0062 },
+ { 0x0043, 0x0063 },
+ { 0x0044, 0x0064 },
+ { 0x0045, 0x0065 },
+ { 0x0046, 0x0066 },
+ { 0x0047, 0x0067 },
+ { 0x0048, 0x0068 },
+ { 0x0049, 0x0069 },
+ // { 0x0049, 0x0131 }, // dotless I
+ { 0x004A, 0x006A },
+ { 0x004B, 0x006B },
+ { 0x004C, 0x006C },
+ { 0x004D, 0x006D },
+ { 0x004E, 0x006E },
+ { 0x004F, 0x006F },
+ { 0x0050, 0x0070 },
+ { 0x0051, 0x0071 },
+ { 0x0052, 0x0072 },
+ { 0x0053, 0x0073 },
+ { 0x0054, 0x0074 },
+ { 0x0055, 0x0075 },
+ { 0x0056, 0x0076 },
+ { 0x0057, 0x0077 },
+ { 0x0058, 0x0078 },
+ { 0x0059, 0x0079 },
+ { 0x005A, 0x007A },
+ { 0x00C0, 0x00E0 },
+ { 0x00C1, 0x00E1 },
+ { 0x00C2, 0x00E2 },
+ { 0x00C3, 0x00E3 },
+ { 0x00C4, 0x00E4 },
+ { 0x00C5, 0x00E5 },
+ { 0x00C6, 0x00E6 },
+ { 0x00C7, 0x00E7 },
+ { 0x00C8, 0x00E8 },
+ { 0x00C9, 0x00E9 },
+ { 0x00CA, 0x00EA },
+ { 0x00CB, 0x00EB },
+ { 0x00CC, 0x00EC },
+ { 0x00CD, 0x00ED },
+ { 0x00CE, 0x00EE },
+ { 0x00CF, 0x00EF },
+ { 0x00D0, 0x00F0 },
+ { 0x00D1, 0x00F1 },
+ { 0x00D2, 0x00F2 },
+ { 0x00D3, 0x00F3 },
+ { 0x00D4, 0x00F4 },
+ { 0x00D5, 0x00F5 },
+ { 0x00D6, 0x00F6 },
+ { 0x00D8, 0x00F8 },
+ { 0x00D9, 0x00F9 },
+ { 0x00DA, 0x00FA },
+ { 0x00DB, 0x00FB },
+ { 0x00DC, 0x00FC },
+ { 0x00DD, 0x00FD },
+ { 0x00DE, 0x00FE },
+ { 0x0100, 0x0101 },
+ { 0x0102, 0x0103 },
+ { 0x0104, 0x0105 },
+ { 0x0106, 0x0107 },
+ { 0x0108, 0x0109 },
+ { 0x010A, 0x010B },
+ { 0x010C, 0x010D },
+ { 0x010E, 0x010F },
+ { 0x0110, 0x0111 },
+ { 0x0112, 0x0113 },
+ { 0x0114, 0x0115 },
+ { 0x0116, 0x0117 },
+ { 0x0118, 0x0119 },
+ { 0x011A, 0x011B },
+ { 0x011C, 0x011D },
+ { 0x011E, 0x011F },
+ { 0x0120, 0x0121 },
+ { 0x0122, 0x0123 },
+ { 0x0124, 0x0125 },
+ { 0x0126, 0x0127 },
+ { 0x0128, 0x0129 },
+ { 0x012A, 0x012B },
+ { 0x012C, 0x012D },
+ { 0x012E, 0x012F },
+ { 0x0132, 0x0133 },
+ { 0x0134, 0x0135 },
+ { 0x0136, 0x0137 },
+ { 0x0139, 0x013A },
+ { 0x013B, 0x013C },
+ { 0x013D, 0x013E },
+ { 0x013F, 0x0140 },
+ { 0x0141, 0x0142 },
+ { 0x0143, 0x0144 },
+ { 0x0145, 0x0146 },
+ { 0x0147, 0x0148 },
+ { 0x014A, 0x014B },
+ { 0x014C, 0x014D },
+ { 0x014E, 0x014F },
+ { 0x0150, 0x0151 },
+ { 0x0152, 0x0153 },
+ { 0x0154, 0x0155 },
+ { 0x0156, 0x0157 },
+ { 0x0158, 0x0159 },
+ { 0x015A, 0x015B },
+ { 0x015C, 0x015D },
+ { 0x015E, 0x015F },
+ { 0x0160, 0x0161 },
+ { 0x0162, 0x0163 },
+ { 0x0164, 0x0165 },
+ { 0x0166, 0x0167 },
+ { 0x0168, 0x0169 },
+ { 0x016A, 0x016B },
+ { 0x016C, 0x016D },
+ { 0x016E, 0x016F },
+ { 0x0170, 0x0171 },
+ { 0x0172, 0x0173 },
+ { 0x0174, 0x0175 },
+ { 0x0176, 0x0177 },
+ { 0x0178, 0x00FF },
+ { 0x0179, 0x017A },
+ { 0x017B, 0x017C },
+ { 0x017D, 0x017E },
+ { 0x0181, 0x0253 },
+ { 0x0182, 0x0183 },
+ { 0x0184, 0x0185 },
+ { 0x0186, 0x0254 },
+ { 0x0187, 0x0188 },
+ { 0x018A, 0x0257 },
+ { 0x018B, 0x018C },
+ { 0x018E, 0x0258 },
+ { 0x018F, 0x0259 },
+ { 0x0190, 0x025B },
+ { 0x0191, 0x0192 },
+ { 0x0193, 0x0260 },
+ { 0x0194, 0x0263 },
+ { 0x0196, 0x0269 },
+ { 0x0197, 0x0268 },
+ { 0x0198, 0x0199 },
+ { 0x019C, 0x026F },
+ { 0x019D, 0x0272 },
+ { 0x019F, 0x0275 },
+ { 0x01A0, 0x01A1 },
+ { 0x01A2, 0x01A3 },
+ { 0x01A4, 0x01A5 },
+ { 0x01A7, 0x01A8 },
+ { 0x01A9, 0x0283 },
+ { 0x01AC, 0x01AD },
+ { 0x01AE, 0x0288 },
+ { 0x01AF, 0x01B0 },
+ { 0x01B1, 0x028A },
+ { 0x01B2, 0x028B },
+ { 0x01B3, 0x01B4 },
+ { 0x01B5, 0x01B6 },
+ { 0x01B7, 0x0292 },
+ { 0x01B8, 0x01B9 },
+ { 0x01BC, 0x01BD },
+ { 0x01C4, 0x01C6 },
+ { 0x01C7, 0x01C9 },
+ { 0x01CA, 0x01CC },
+ { 0x01CD, 0x01CE },
+ { 0x01CF, 0x01D0 },
+ { 0x01D1, 0x01D2 },
+ { 0x01D3, 0x01D4 },
+ { 0x01D5, 0x01D6 },
+ { 0x01D7, 0x01D8 },
+ { 0x01D9, 0x01DA },
+ { 0x01DB, 0x01DC },
+ { 0x01DE, 0x01DF },
+ { 0x01E0, 0x01E1 },
+ { 0x01E2, 0x01E3 },
+ { 0x01E4, 0x01E5 },
+ { 0x01E6, 0x01E7 },
+ { 0x01E8, 0x01E9 },
+ { 0x01EA, 0x01EB },
+ { 0x01EC, 0x01ED },
+ { 0x01EE, 0x01EF },
+ { 0x01F1, 0x01F3 },
+ { 0x01F4, 0x01F5 },
+ { 0x01FA, 0x01FB },
+ { 0x01FC, 0x01FD },
+ { 0x01FE, 0x01FF },
+ { 0x0200, 0x0201 },
+ { 0x0202, 0x0203 },
+ { 0x0204, 0x0205 },
+ { 0x0206, 0x0207 },
+ { 0x0208, 0x0209 },
+ { 0x020A, 0x020B },
+ { 0x020C, 0x020D },
+ { 0x020E, 0x020F },
+ { 0x0210, 0x0211 },
+ { 0x0212, 0x0213 },
+ { 0x0214, 0x0215 },
+ { 0x0216, 0x0217 },
+ { 0x0386, 0x03AC },
+ { 0x0388, 0x03AD },
+ { 0x0389, 0x03AE },
+ { 0x038A, 0x03AF },
+ { 0x038C, 0x03CC },
+ { 0x038E, 0x03CD },
+ { 0x038F, 0x03CE },
+ { 0x0391, 0x03B1 },
+ { 0x0392, 0x03B2 },
+ { 0x0393, 0x03B3 },
+ { 0x0394, 0x03B4 },
+ { 0x0395, 0x03B5 },
+ { 0x0396, 0x03B6 },
+ { 0x0397, 0x03B7 },
+ { 0x0398, 0x03B8 },
+ { 0x0399, 0x03B9 },
+ { 0x039A, 0x03BA },
+ { 0x039B, 0x03BB },
+ { 0x039C, 0x03BC },
+ { 0x039D, 0x03BD },
+ { 0x039E, 0x03BE },
+ { 0x039F, 0x03BF },
+ { 0x03A0, 0x03C0 },
+ { 0x03A1, 0x03C1 },
+ { 0x03A3, 0x03C3 },
+ { 0x03A4, 0x03C4 },
+ { 0x03A5, 0x03C5 },
+ { 0x03A6, 0x03C6 },
+ { 0x03A7, 0x03C7 },
+ { 0x03A8, 0x03C8 },
+ { 0x03A9, 0x03C9 },
+ { 0x03AA, 0x03CA },
+ { 0x03AB, 0x03CB },
+ { 0x03E2, 0x03E3 },
+ { 0x03E4, 0x03E5 },
+ { 0x03E6, 0x03E7 },
+ { 0x03E8, 0x03E9 },
+ { 0x03EA, 0x03EB },
+ { 0x03EC, 0x03ED },
+ { 0x03EE, 0x03EF },
+ { 0x0401, 0x0451 },
+ { 0x0402, 0x0452 },
+ { 0x0403, 0x0453 },
+ { 0x0404, 0x0454 },
+ { 0x0405, 0x0455 },
+ { 0x0406, 0x0456 },
+ { 0x0407, 0x0457 },
+ { 0x0408, 0x0458 },
+ { 0x0409, 0x0459 },
+ { 0x040A, 0x045A },
+ { 0x040B, 0x045B },
+ { 0x040C, 0x045C },
+ { 0x040E, 0x045E },
+ { 0x040F, 0x045F },
+ { 0x0410, 0x0430 },
+ { 0x0411, 0x0431 },
+ { 0x0412, 0x0432 },
+ { 0x0413, 0x0433 },
+ { 0x0414, 0x0434 },
+ { 0x0415, 0x0435 },
+ { 0x0416, 0x0436 },
+ { 0x0417, 0x0437 },
+ { 0x0418, 0x0438 },
+ { 0x0419, 0x0439 },
+ { 0x041A, 0x043A },
+ { 0x041B, 0x043B },
+ { 0x041C, 0x043C },
+ { 0x041D, 0x043D },
+ { 0x041E, 0x043E },
+ { 0x041F, 0x043F },
+ { 0x0420, 0x0440 },
+ { 0x0421, 0x0441 },
+ { 0x0422, 0x0442 },
+ { 0x0423, 0x0443 },
+ { 0x0424, 0x0444 },
+ { 0x0425, 0x0445 },
+ { 0x0426, 0x0446 },
+ { 0x0427, 0x0447 },
+ { 0x0428, 0x0448 },
+ { 0x0429, 0x0449 },
+ { 0x042A, 0x044A },
+ { 0x042B, 0x044B },
+ { 0x042C, 0x044C },
+ { 0x042D, 0x044D },
+ { 0x042E, 0x044E },
+ { 0x042F, 0x044F },
+ { 0x0460, 0x0461 },
+ { 0x0462, 0x0463 },
+ { 0x0464, 0x0465 },
+ { 0x0466, 0x0467 },
+ { 0x0468, 0x0469 },
+ { 0x046A, 0x046B },
+ { 0x046C, 0x046D },
+ { 0x046E, 0x046F },
+ { 0x0470, 0x0471 },
+ { 0x0472, 0x0473 },
+ { 0x0474, 0x0475 },
+ { 0x0476, 0x0477 },
+ { 0x0478, 0x0479 },
+ { 0x047A, 0x047B },
+ { 0x047C, 0x047D },
+ { 0x047E, 0x047F },
+ { 0x0480, 0x0481 },
+ { 0x0490, 0x0491 },
+ { 0x0492, 0x0493 },
+ { 0x0494, 0x0495 },
+ { 0x0496, 0x0497 },
+ { 0x0498, 0x0499 },
+ { 0x049A, 0x049B },
+ { 0x049C, 0x049D },
+ { 0x049E, 0x049F },
+ { 0x04A0, 0x04A1 },
+ { 0x04A2, 0x04A3 },
+ { 0x04A4, 0x04A5 },
+ { 0x04A6, 0x04A7 },
+ { 0x04A8, 0x04A9 },
+ { 0x04AA, 0x04AB },
+ { 0x04AC, 0x04AD },
+ { 0x04AE, 0x04AF },
+ { 0x04B0, 0x04B1 },
+ { 0x04B2, 0x04B3 },
+ { 0x04B4, 0x04B5 },
+ { 0x04B6, 0x04B7 },
+ { 0x04B8, 0x04B9 },
+ { 0x04BA, 0x04BB },
+ { 0x04BC, 0x04BD },
+ { 0x04BE, 0x04BF },
+ { 0x04C1, 0x04C2 },
+ { 0x04C3, 0x04C4 },
+ { 0x04C7, 0x04C8 },
+ { 0x04CB, 0x04CC },
+ { 0x04D0, 0x04D1 },
+ { 0x04D2, 0x04D3 },
+ { 0x04D4, 0x04D5 },
+ { 0x04D6, 0x04D7 },
+ { 0x04D8, 0x04D9 },
+ { 0x04DA, 0x04DB },
+ { 0x04DC, 0x04DD },
+ { 0x04DE, 0x04DF },
+ { 0x04E0, 0x04E1 },
+ { 0x04E2, 0x04E3 },
+ { 0x04E4, 0x04E5 },
+ { 0x04E6, 0x04E7 },
+ { 0x04E8, 0x04E9 },
+ { 0x04EA, 0x04EB },
+ { 0x04EE, 0x04EF },
+ { 0x04F0, 0x04F1 },
+ { 0x04F2, 0x04F3 },
+ { 0x04F4, 0x04F5 },
+ { 0x04F8, 0x04F9 },
+ { 0x0531, 0x0561 },
+ { 0x0532, 0x0562 },
+ { 0x0533, 0x0563 },
+ { 0x0534, 0x0564 },
+ { 0x0535, 0x0565 },
+ { 0x0536, 0x0566 },
+ { 0x0537, 0x0567 },
+ { 0x0538, 0x0568 },
+ { 0x0539, 0x0569 },
+ { 0x053A, 0x056A },
+ { 0x053B, 0x056B },
+ { 0x053C, 0x056C },
+ { 0x053D, 0x056D },
+ { 0x053E, 0x056E },
+ { 0x053F, 0x056F },
+ { 0x0540, 0x0570 },
+ { 0x0541, 0x0571 },
+ { 0x0542, 0x0572 },
+ { 0x0543, 0x0573 },
+ { 0x0544, 0x0574 },
+ { 0x0545, 0x0575 },
+ { 0x0546, 0x0576 },
+ { 0x0547, 0x0577 },
+ { 0x0548, 0x0578 },
+ { 0x0549, 0x0579 },
+ { 0x054A, 0x057A },
+ { 0x054B, 0x057B },
+ { 0x054C, 0x057C },
+ { 0x054D, 0x057D },
+ { 0x054E, 0x057E },
+ { 0x054F, 0x057F },
+ { 0x0550, 0x0580 },
+ { 0x0551, 0x0581 },
+ { 0x0552, 0x0582 },
+ { 0x0553, 0x0583 },
+ { 0x0554, 0x0584 },
+ { 0x0555, 0x0585 },
+ { 0x0556, 0x0586 },
+ { 0x10A0, 0x10D0 },
+ { 0x10A1, 0x10D1 },
+ { 0x10A2, 0x10D2 },
+ { 0x10A3, 0x10D3 },
+ { 0x10A4, 0x10D4 },
+ { 0x10A5, 0x10D5 },
+ { 0x10A6, 0x10D6 },
+ { 0x10A7, 0x10D7 },
+ { 0x10A8, 0x10D8 },
+ { 0x10A9, 0x10D9 },
+ { 0x10AA, 0x10DA },
+ { 0x10AB, 0x10DB },
+ { 0x10AC, 0x10DC },
+ { 0x10AD, 0x10DD },
+ { 0x10AE, 0x10DE },
+ { 0x10AF, 0x10DF },
+ { 0x10B0, 0x10E0 },
+ { 0x10B1, 0x10E1 },
+ { 0x10B2, 0x10E2 },
+ { 0x10B3, 0x10E3 },
+ { 0x10B4, 0x10E4 },
+ { 0x10B5, 0x10E5 },
+ { 0x10B6, 0x10E6 },
+ { 0x10B7, 0x10E7 },
+ { 0x10B8, 0x10E8 },
+ { 0x10B9, 0x10E9 },
+ { 0x10BA, 0x10EA },
+ { 0x10BB, 0x10EB },
+ { 0x10BC, 0x10EC },
+ { 0x10BD, 0x10ED },
+ { 0x10BE, 0x10EE },
+ { 0x10BF, 0x10EF },
+ { 0x10C0, 0x10F0 },
+ { 0x10C1, 0x10F1 },
+ { 0x10C2, 0x10F2 },
+ { 0x10C3, 0x10F3 },
+ { 0x10C4, 0x10F4 },
+ { 0x10C5, 0x10F5 },
+ { 0x1E00, 0x1E01 },
+ { 0x1E02, 0x1E03 },
+ { 0x1E04, 0x1E05 },
+ { 0x1E06, 0x1E07 },
+ { 0x1E08, 0x1E09 },
+ { 0x1E0A, 0x1E0B },
+ { 0x1E0C, 0x1E0D },
+ { 0x1E0E, 0x1E0F },
+ { 0x1E10, 0x1E11 },
+ { 0x1E12, 0x1E13 },
+ { 0x1E14, 0x1E15 },
+ { 0x1E16, 0x1E17 },
+ { 0x1E18, 0x1E19 },
+ { 0x1E1A, 0x1E1B },
+ { 0x1E1C, 0x1E1D },
+ { 0x1E1E, 0x1E1F },
+ { 0x1E20, 0x1E21 },
+ { 0x1E22, 0x1E23 },
+ { 0x1E24, 0x1E25 },
+ { 0x1E26, 0x1E27 },
+ { 0x1E28, 0x1E29 },
+ { 0x1E2A, 0x1E2B },
+ { 0x1E2C, 0x1E2D },
+ { 0x1E2E, 0x1E2F },
+ { 0x1E30, 0x1E31 },
+ { 0x1E32, 0x1E33 },
+ { 0x1E34, 0x1E35 },
+ { 0x1E36, 0x1E37 },
+ { 0x1E38, 0x1E39 },
+ { 0x1E3A, 0x1E3B },
+ { 0x1E3C, 0x1E3D },
+ { 0x1E3E, 0x1E3F },
+ { 0x1E40, 0x1E41 },
+ { 0x1E42, 0x1E43 },
+ { 0x1E44, 0x1E45 },
+ { 0x1E46, 0x1E47 },
+ { 0x1E48, 0x1E49 },
+ { 0x1E4A, 0x1E4B },
+ { 0x1E4C, 0x1E4D },
+ { 0x1E4E, 0x1E4F },
+ { 0x1E50, 0x1E51 },
+ { 0x1E52, 0x1E53 },
+ { 0x1E54, 0x1E55 },
+ { 0x1E56, 0x1E57 },
+ { 0x1E58, 0x1E59 },
+ { 0x1E5A, 0x1E5B },
+ { 0x1E5C, 0x1E5D },
+ { 0x1E5E, 0x1E5F },
+ { 0x1E60, 0x1E61 },
+ { 0x1E62, 0x1E63 },
+ { 0x1E64, 0x1E65 },
+ { 0x1E66, 0x1E67 },
+ { 0x1E68, 0x1E69 },
+ { 0x1E6A, 0x1E6B },
+ { 0x1E6C, 0x1E6D },
+ { 0x1E6E, 0x1E6F },
+ { 0x1E70, 0x1E71 },
+ { 0x1E72, 0x1E73 },
+ { 0x1E74, 0x1E75 },
+ { 0x1E76, 0x1E77 },
+ { 0x1E78, 0x1E79 },
+ { 0x1E7A, 0x1E7B },
+ { 0x1E7C, 0x1E7D },
+ { 0x1E7E, 0x1E7F },
+ { 0x1E80, 0x1E81 },
+ { 0x1E82, 0x1E83 },
+ { 0x1E84, 0x1E85 },
+ { 0x1E86, 0x1E87 },
+ { 0x1E88, 0x1E89 },
+ { 0x1E8A, 0x1E8B },
+ { 0x1E8C, 0x1E8D },
+ { 0x1E8E, 0x1E8F },
+ { 0x1E90, 0x1E91 },
+ { 0x1E92, 0x1E93 },
+ { 0x1E94, 0x1E95 },
+ { 0x1EA0, 0x1EA1 },
+ { 0x1EA2, 0x1EA3 },
+ { 0x1EA4, 0x1EA5 },
+ { 0x1EA6, 0x1EA7 },
+ { 0x1EA8, 0x1EA9 },
+ { 0x1EAA, 0x1EAB },
+ { 0x1EAC, 0x1EAD },
+ { 0x1EAE, 0x1EAF },
+ { 0x1EB0, 0x1EB1 },
+ { 0x1EB2, 0x1EB3 },
+ { 0x1EB4, 0x1EB5 },
+ { 0x1EB6, 0x1EB7 },
+ { 0x1EB8, 0x1EB9 },
+ { 0x1EBA, 0x1EBB },
+ { 0x1EBC, 0x1EBD },
+ { 0x1EBE, 0x1EBF },
+ { 0x1EC0, 0x1EC1 },
+ { 0x1EC2, 0x1EC3 },
+ { 0x1EC4, 0x1EC5 },
+ { 0x1EC6, 0x1EC7 },
+ { 0x1EC8, 0x1EC9 },
+ { 0x1ECA, 0x1ECB },
+ { 0x1ECC, 0x1ECD },
+ { 0x1ECE, 0x1ECF },
+ { 0x1ED0, 0x1ED1 },
+ { 0x1ED2, 0x1ED3 },
+ { 0x1ED4, 0x1ED5 },
+ { 0x1ED6, 0x1ED7 },
+ { 0x1ED8, 0x1ED9 },
+ { 0x1EDA, 0x1EDB },
+ { 0x1EDC, 0x1EDD },
+ { 0x1EDE, 0x1EDF },
+ { 0x1EE0, 0x1EE1 },
+ { 0x1EE2, 0x1EE3 },
+ { 0x1EE4, 0x1EE5 },
+ { 0x1EE6, 0x1EE7 },
+ { 0x1EE8, 0x1EE9 },
+ { 0x1EEA, 0x1EEB },
+ { 0x1EEC, 0x1EED },
+ { 0x1EEE, 0x1EEF },
+ { 0x1EF0, 0x1EF1 },
+ { 0x1EF2, 0x1EF3 },
+ { 0x1EF4, 0x1EF5 },
+ { 0x1EF6, 0x1EF7 },
+ { 0x1EF8, 0x1EF9 },
+ { 0x1F08, 0x1F00 },
+ { 0x1F09, 0x1F01 },
+ { 0x1F0A, 0x1F02 },
+ { 0x1F0B, 0x1F03 },
+ { 0x1F0C, 0x1F04 },
+ { 0x1F0D, 0x1F05 },
+ { 0x1F0E, 0x1F06 },
+ { 0x1F0F, 0x1F07 },
+ { 0x1F18, 0x1F10 },
+ { 0x1F19, 0x1F11 },
+ { 0x1F1A, 0x1F12 },
+ { 0x1F1B, 0x1F13 },
+ { 0x1F1C, 0x1F14 },
+ { 0x1F1D, 0x1F15 },
+ { 0x1F28, 0x1F20 },
+ { 0x1F29, 0x1F21 },
+ { 0x1F2A, 0x1F22 },
+ { 0x1F2B, 0x1F23 },
+ { 0x1F2C, 0x1F24 },
+ { 0x1F2D, 0x1F25 },
+ { 0x1F2E, 0x1F26 },
+ { 0x1F2F, 0x1F27 },
+ { 0x1F38, 0x1F30 },
+ { 0x1F39, 0x1F31 },
+ { 0x1F3A, 0x1F32 },
+ { 0x1F3B, 0x1F33 },
+ { 0x1F3C, 0x1F34 },
+ { 0x1F3D, 0x1F35 },
+ { 0x1F3E, 0x1F36 },
+ { 0x1F3F, 0x1F37 },
+ { 0x1F48, 0x1F40 },
+ { 0x1F49, 0x1F41 },
+ { 0x1F4A, 0x1F42 },
+ { 0x1F4B, 0x1F43 },
+ { 0x1F4C, 0x1F44 },
+ { 0x1F4D, 0x1F45 },
+ { 0x1F59, 0x1F51 },
+ { 0x1F5B, 0x1F53 },
+ { 0x1F5D, 0x1F55 },
+ { 0x1F5F, 0x1F57 },
+ { 0x1F68, 0x1F60 },
+ { 0x1F69, 0x1F61 },
+ { 0x1F6A, 0x1F62 },
+ { 0x1F6B, 0x1F63 },
+ { 0x1F6C, 0x1F64 },
+ { 0x1F6D, 0x1F65 },
+ { 0x1F6E, 0x1F66 },
+ { 0x1F6F, 0x1F67 },
+ { 0x1F88, 0x1F80 },
+ { 0x1F89, 0x1F81 },
+ { 0x1F8A, 0x1F82 },
+ { 0x1F8B, 0x1F83 },
+ { 0x1F8C, 0x1F84 },
+ { 0x1F8D, 0x1F85 },
+ { 0x1F8E, 0x1F86 },
+ { 0x1F8F, 0x1F87 },
+ { 0x1F98, 0x1F90 },
+ { 0x1F99, 0x1F91 },
+ { 0x1F9A, 0x1F92 },
+ { 0x1F9B, 0x1F93 },
+ { 0x1F9C, 0x1F94 },
+ { 0x1F9D, 0x1F95 },
+ { 0x1F9E, 0x1F96 },
+ { 0x1F9F, 0x1F97 },
+ { 0x1FA8, 0x1FA0 },
+ { 0x1FA9, 0x1FA1 },
+ { 0x1FAA, 0x1FA2 },
+ { 0x1FAB, 0x1FA3 },
+ { 0x1FAC, 0x1FA4 },
+ { 0x1FAD, 0x1FA5 },
+ { 0x1FAE, 0x1FA6 },
+ { 0x1FAF, 0x1FA7 },
+ { 0x1FB8, 0x1FB0 },
+ { 0x1FB9, 0x1FB1 },
+ { 0x1FD8, 0x1FD0 },
+ { 0x1FD9, 0x1FD1 },
+ { 0x1FE8, 0x1FE0 },
+ { 0x1FE9, 0x1FE1 },
+ { 0x24B6, 0x24D0 },
+ { 0x24B7, 0x24D1 },
+ { 0x24B8, 0x24D2 },
+ { 0x24B9, 0x24D3 },
+ { 0x24BA, 0x24D4 },
+ { 0x24BB, 0x24D5 },
+ { 0x24BC, 0x24D6 },
+ { 0x24BD, 0x24D7 },
+ { 0x24BE, 0x24D8 },
+ { 0x24BF, 0x24D9 },
+ { 0x24C0, 0x24DA },
+ { 0x24C1, 0x24DB },
+ { 0x24C2, 0x24DC },
+ { 0x24C3, 0x24DD },
+ { 0x24C4, 0x24DE },
+ { 0x24C5, 0x24DF },
+ { 0x24C6, 0x24E0 },
+ { 0x24C7, 0x24E1 },
+ { 0x24C8, 0x24E2 },
+ { 0x24C9, 0x24E3 },
+ { 0x24CA, 0x24E4 },
+ { 0x24CB, 0x24E5 },
+ { 0x24CC, 0x24E6 },
+ { 0x24CD, 0x24E7 },
+ { 0x24CE, 0x24E8 },
+ { 0x24CF, 0x24E9 },
+ { 0xFF21, 0xFF41 },
+ { 0xFF22, 0xFF42 },
+ { 0xFF23, 0xFF43 },
+ { 0xFF24, 0xFF44 },
+ { 0xFF25, 0xFF45 },
+ { 0xFF26, 0xFF46 },
+ { 0xFF27, 0xFF47 },
+ { 0xFF28, 0xFF48 },
+ { 0xFF29, 0xFF49 },
+ { 0xFF2A, 0xFF4A },
+ { 0xFF2B, 0xFF4B },
+ { 0xFF2C, 0xFF4C },
+ { 0xFF2D, 0xFF4D },
+ { 0xFF2E, 0xFF4E },
+ { 0xFF2F, 0xFF4F },
+ { 0xFF30, 0xFF50 },
+ { 0xFF31, 0xFF51 },
+ { 0xFF32, 0xFF52 },
+ { 0xFF33, 0xFF53 },
+ { 0xFF34, 0xFF54 },
+ { 0xFF35, 0xFF55 },
+ { 0xFF36, 0xFF56 },
+ { 0xFF37, 0xFF57 },
+ { 0xFF38, 0xFF58 },
+ { 0xFF39, 0xFF59 },
+ { 0xFF3A, 0xFF5A },
};
static int _find_upper(int ch) {
diff --git a/core/ustring.h b/core/ustring.h
index cb3d87378a..9288c1526e 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -97,6 +97,10 @@ public:
_FORCE_INLINE_ CharString() {}
_FORCE_INLINE_ CharString(const CharString &p_str) { _cowdata._ref(p_str._cowdata); }
+ _FORCE_INLINE_ CharString operator=(const CharString &p_str) {
+ _cowdata._ref(p_str._cowdata);
+ return *this;
+ }
bool operator<(const CharString &p_right) const;
CharString &operator+=(char p_char);
@@ -339,6 +343,10 @@ public:
_FORCE_INLINE_ String() {}
_FORCE_INLINE_ String(const String &p_str) { _cowdata._ref(p_str._cowdata); }
+ String operator=(const String &p_str) {
+ _cowdata._ref(p_str._cowdata);
+ return *this;
+ }
String(const char *p_str);
String(const CharType *p_str, int p_clip_to_len = -1);
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 3812592639..cbe24d4a63 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -341,6 +341,7 @@ struct _VariantCall {
VCALL_LOCALMEM1R(Vector2, project);
VCALL_LOCALMEM1R(Vector2, angle_to);
VCALL_LOCALMEM1R(Vector2, angle_to_point);
+ VCALL_LOCALMEM1R(Vector2, direction_to);
VCALL_LOCALMEM2R(Vector2, linear_interpolate);
VCALL_LOCALMEM2R(Vector2, slerp);
VCALL_LOCALMEM4R(Vector2, cubic_interpolate);
@@ -397,6 +398,7 @@ struct _VariantCall {
VCALL_LOCALMEM1R(Vector3, distance_squared_to);
VCALL_LOCALMEM1R(Vector3, project);
VCALL_LOCALMEM1R(Vector3, angle_to);
+ VCALL_LOCALMEM1R(Vector3, direction_to);
VCALL_LOCALMEM1R(Vector3, slide);
VCALL_LOCALMEM1R(Vector3, bounce);
VCALL_LOCALMEM1R(Vector3, reflect);
@@ -1556,6 +1558,7 @@ void register_variant_methods() {
ADDFUNC0R(VECTOR2, REAL, Vector2, angle, varray());
ADDFUNC0R(VECTOR2, REAL, Vector2, length_squared, varray());
ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray());
+ ADDFUNC1R(VECTOR2, VECTOR2, Vector2, direction_to, VECTOR2, "b", varray());
ADDFUNC1R(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray());
ADDFUNC1R(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray());
ADDFUNC1R(VECTOR2, VECTOR2, Vector2, project, VECTOR2, "b", varray());
@@ -1604,6 +1607,7 @@ void register_variant_methods() {
ADDFUNC2R(VECTOR3, VECTOR3, Vector3, linear_interpolate, VECTOR3, "b", REAL, "t", varray());
ADDFUNC2R(VECTOR3, VECTOR3, Vector3, slerp, VECTOR3, "b", REAL, "t", varray());
ADDFUNC4R(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", REAL, "t", varray());
+ ADDFUNC1R(VECTOR3, VECTOR3, Vector3, direction_to, VECTOR3, "b", varray());
ADDFUNC1R(VECTOR3, REAL, Vector3, dot, VECTOR3, "b", varray());
ADDFUNC1R(VECTOR3, VECTOR3, Vector3, cross, VECTOR3, "b", varray());
ADDFUNC1R(VECTOR3, BASIS, Vector3, outer, VECTOR3, "b", varray());
@@ -1927,9 +1931,9 @@ void register_variant_methods() {
_VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform);
transform_x.set(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
_VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", transform_x);
- transform_x.set(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
+ transform_y.set(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
_VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", transform_y);
- transform_x.set(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
+ transform_z.set(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
_VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", transform_z);
_VariantCall::add_variant_constant(Variant::PLANE, "PLANE_YZ", Plane(Vector3(1, 0, 0), 0));
diff --git a/core/vmap.h b/core/vmap.h
index f46ed70a0f..fde9723d71 100644
--- a/core/vmap.h
+++ b/core/vmap.h
@@ -65,7 +65,7 @@ private:
const Pair *a = _cowdata.ptr();
int middle = 0;
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
if (low > high)
ERR_PRINT("low > high, this may be a bug");
#endif
diff --git a/core/vset.h b/core/vset.h
index 678ec507ba..5f087a5a03 100644
--- a/core/vset.h
+++ b/core/vset.h
@@ -50,7 +50,7 @@ class VSet {
const T *a = &_data[0];
int middle = 0;
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
if (low > high)
ERR_PRINT("low > high, this may be a bug");
#endif
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index df52f8503a..e3eca57f2d 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -975,6 +975,24 @@
[/codeblock]
</description>
</method>
+ <method name="smoothstep">
+ <return type="float">
+ </return>
+ <argument index="0" name="from" type="float">
+ </argument>
+ <argument index="1" name="to" type="float">
+ </argument>
+ <argument index="2" name="weight" type="float">
+ </argument>
+ <description>
+ Returns a number smoothly interpolated between the [code]from[/code] and [code]to[/code], based on the [code]weight[/code]. Similar to [method lerp], but interpolates faster at the beginning and slower at the end.
+ [codeblock]
+ smoothstep(0, 2, 0.5) # returns 0.15
+ smoothstep(0, 2, 1.0) # returns 0.5
+ smoothstep(0, 2, 2.0) # returns 1.0
+ [/codeblock]
+ </description>
+ </method>
<method name="sqrt">
<return type="float">
</return>
diff --git a/doc/classes/ARVRAnchor.xml b/doc/classes/ARVRAnchor.xml
index 5197c1c651..57ca74fdd3 100644
--- a/doc/classes/ARVRAnchor.xml
+++ b/doc/classes/ARVRAnchor.xml
@@ -27,6 +27,13 @@
Returns true if the anchor is being tracked and false if no anchor with this id is currently known.
</description>
</method>
+ <method name="get_mesh" qualifiers="const">
+ <return type="Mesh">
+ </return>
+ <description>
+ If provided by the ARVR Interface this returns a mesh object for the anchor. For an anchor this can be a shape related to the object being tracked or it can be a mesh that provides topology related to the anchor and can be used to create shadows/reflections on surfaces or for generating collision shapes.
+ </description>
+ </method>
<method name="get_plane" qualifiers="const">
<return type="Plane">
</return>
@@ -47,6 +54,15 @@
The anchor's id. You can set this before the anchor itself exists. The first anchor gets an id of [code]1[/code], the second an id of [code]2[/code], etc. When anchors get removed, the engine can then assign the corresponding id to new anchors. The most common situation where anchors 'disappear' is when the AR server identifies that two anchors represent different parts of the same plane and merges them.
</member>
</members>
+ <signals>
+ <signal name="mesh_updated">
+ <argument index="0" name="mesh" type="Mesh">
+ </argument>
+ <description>
+ Emitted when the mesh associated with the anchor changes or when one becomes available. This is especially important for topology that is constantly being mesh_updated.
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
diff --git a/doc/classes/ARVRController.xml b/doc/classes/ARVRController.xml
index 1264f89f64..08e071ea1e 100644
--- a/doc/classes/ARVRController.xml
+++ b/doc/classes/ARVRController.xml
@@ -50,6 +50,13 @@
Returns the ID of the joystick object bound to this. Every controller tracked by the ARVR Server that has buttons and axis will also be registered as a joystick within Godot. This means that all the normal joystick tracking and input mapping will work for buttons and axis found on the AR/VR controllers. This ID is purely offered as information so you can link up the controller with its joystick entry.
</description>
</method>
+ <method name="get_mesh" qualifiers="const">
+ <return type="Mesh">
+ </return>
+ <description>
+ If provided by the ARVR Interface this returns a mesh associated with the controller. This can be used to visualise the controller.
+ </description>
+ </method>
<method name="is_button_pressed" qualifiers="const">
<return type="int">
</return>
@@ -86,6 +93,13 @@
Emitted when a button on this controller is released.
</description>
</signal>
+ <signal name="mesh_updated">
+ <argument index="0" name="mesh" type="Mesh">
+ </argument>
+ <description>
+ Emitted when the mesh associated with the controller changes or when one becomes available. Generally speaking this will be a static mesh after becoming available.
+ </description>
+ </signal>
</signals>
<constants>
</constants>
diff --git a/doc/classes/ARVRPositionalTracker.xml b/doc/classes/ARVRPositionalTracker.xml
index c1be8d2356..c2e48b878b 100644
--- a/doc/classes/ARVRPositionalTracker.xml
+++ b/doc/classes/ARVRPositionalTracker.xml
@@ -27,6 +27,13 @@
If this is a controller that is being tracked the controller will also be represented by a joystick entry with this id.
</description>
</method>
+ <method name="get_mesh" qualifiers="const">
+ <return type="Mesh">
+ </return>
+ <description>
+ Returns the mesh related to a controller or anchor point if one is available.
+ </description>
+ </method>
<method name="get_name" qualifiers="const">
<return type="String">
</return>
diff --git a/doc/classes/AStar.xml b/doc/classes/AStar.xml
index 5a62c69a67..3e478467ff 100644
--- a/doc/classes/AStar.xml
+++ b/doc/classes/AStar.xml
@@ -226,6 +226,15 @@
Returns whether a point associated with the given id exists.
</description>
</method>
+ <method name="is_point_disabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ Returns whether a point is disabled or not for pathfinding. By default, all points are enabled.
+ </description>
+ </method>
<method name="remove_point">
<return type="void">
</return>
@@ -235,6 +244,17 @@
Removes the point associated with the given id from the points pool.
</description>
</method>
+ <method name="set_point_disabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="disabled" type="bool" default="true">
+ </argument>
+ <description>
+ Disables or enables the specified point for pathfinding. Useful for making a temporary obstacle.
+ </description>
+ </method>
<method name="set_point_position">
<return type="void">
</return>
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index 533a6d6399..8a785ab263 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -84,6 +84,7 @@
</return>
<description>
Returns the whole file as a [String].
+ Text is interpreted as being UTF-8 encoded.
</description>
</method>
<method name="get_buffer" qualifiers="const">
@@ -102,6 +103,7 @@
</argument>
<description>
Returns the next value of the file in CSV (Comma Separated Values) format. You can pass a different delimiter to use other than the default "," (comma), it should be one character long.
+ Text is interpreted as being UTF-8 encoded.
</description>
</method>
<method name="get_double" qualifiers="const">
@@ -137,6 +139,7 @@
</return>
<description>
Returns the next line of the file as a [String].
+ Text is interpreted as being UTF-8 encoded.
</description>
</method>
<method name="get_md5" qualifiers="const">
@@ -162,6 +165,7 @@
</return>
<description>
Returns a [String] saved in Pascal format from the file.
+ Text is interpreted as being UTF-8 encoded.
</description>
</method>
<method name="get_path" qualifiers="const">
@@ -340,6 +344,7 @@
</argument>
<description>
Store the given [PoolStringArray] in the file as a line formatted in the CSV (Comma Separated Values) format. You can pass a different delimiter to use other than the default "," (comma), it should be one character long.
+ Text will be encoded as UTF-8.
</description>
</method>
<method name="store_double">
@@ -367,6 +372,7 @@
</argument>
<description>
Stores the given [String] as a line in the file.
+ Text will be encoded as UTF-8.
</description>
</method>
<method name="store_pascal_string">
@@ -376,6 +382,7 @@
</argument>
<description>
Stores the given [String] as a line in the file in Pascal format (i.e. also store the length of the string).
+ Text will be encoded as UTF-8.
</description>
</method>
<method name="store_real">
@@ -394,6 +401,7 @@
</argument>
<description>
Stores the given [String] in the file.
+ Text will be encoded as UTF-8.
</description>
</method>
<method name="store_var">
diff --git a/doc/classes/HeightMapShape.xml b/doc/classes/HeightMapShape.xml
new file mode 100644
index 0000000000..ec2e18bd7d
--- /dev/null
+++ b/doc/classes/HeightMapShape.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="HeightMapShape" inherits="Shape" category="Core" version="3.2">
+ <brief_description>
+ Height map shape for 3D physics (bullet only)
+ </brief_description>
+ <description>
+ Height map shape resource, which can be added to a [PhysicsBody] or [Area].
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ </methods>
+ <members>
+ <member name="map_data" type="PoolRealArray" setter="set_map_data" getter="get_map_data">
+ Height map data, pool array must be of [member map_width] * [member map_depth] size.
+ </member>
+ <member name="map_depth" type="int" setter="set_map_depth" getter="get_map_depth">
+ Depth of the height map data. Changing this will resize the [member map_data].
+ </member>
+ <member name="map_width" type="int" setter="set_map_width" getter="get_map_width">
+ Width of the height map data. Changing this will resize the [member map_data].
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml
index 6fa2d44fd0..07c9f2a74b 100644
--- a/doc/classes/RandomNumberGenerator.xml
+++ b/doc/classes/RandomNumberGenerator.xml
@@ -28,6 +28,17 @@
Generates pseudo-random float between [code]from[/code] and [code]to[/code].
</description>
</method>
+ <method name="randfn">
+ <return type="float">
+ </return>
+ <argument index="0" name="mean" type="float" default="0.0">
+ </argument>
+ <argument index="1" name="deviation" type="float" default="1.0">
+ </argument>
+ <description>
+ Generates normally(gaussian) distributed pseudo-random number, using Box-Muller transform with the specified [code]mean[/code] and a standard [code]deviation[/code].
+ </description>
+ </method>
<method name="randi">
<return type="int">
</return>
diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml
index 448b635886..d74f481f55 100644
--- a/doc/classes/StyleBoxFlat.xml
+++ b/doc/classes/StyleBoxFlat.xml
@@ -151,6 +151,9 @@
<member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size">
The shadow size in pixels.
</member>
+ <member name="shadow_offset" type="Vector2" setter="set_shadow_offset" getter="get_shadow_offset">
+ The shadow offset in pixels. Adjusts the position of the shadow relatively to the stylebox.
+ </member>
</members>
<constants>
</constants>
diff --git a/doc/classes/TextureRect.xml b/doc/classes/TextureRect.xml
index 13fd762908..7f26fe18e5 100644
--- a/doc/classes/TextureRect.xml
+++ b/doc/classes/TextureRect.xml
@@ -22,6 +22,12 @@
<member name="texture" type="Texture" setter="set_texture" getter="get_texture">
The node's [Texture] resource.
</member>
+ <member name="flip_h" type="bool" setter="set_flip_h" getter="is_flipped_h">
+ If [code]true[/code], texture is flipped horizontally. Default value: [code]false[/code].
+ </member>
+ <member name="flip_v" type="bool" setter="set_flip_v" getter="is_flipped_v">
+ If [code]true[/code], texture is flipped vertically. Default value: [code]false[/code].
+ </member>
</members>
<constants>
<constant name="STRETCH_SCALE_ON_EXPAND" value="0" enum="StretchMode">
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index fe917acaae..3c047487e0 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -165,6 +165,13 @@
Optionally, the tile can also be flipped, transposed, or given autotile coordinates.
Note that data such as navigation polygons and collision shapes are not immediately updated for performance reasons.
If you need these to be immediately updated, you can call [method update_dirty_quadrants].
+ Overriding this method also overrides it internally, allowing custom logic to be implemented when tiles are placed/removed:
+ [codeblock]
+ func set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)
+ # Write your custom logic here.
+ # To call the default method:
+ .set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)
+ [/codeblock]
</description>
</method>
<method name="set_cellv">
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index f1fd0173fe..2f4d3fe3dc 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -112,6 +112,15 @@
Cubicly interpolates between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]t[/code]. [code]t[/code] is in the range of [code]0.0 - 1.0[/code], representing the amount of interpolation.
</description>
</method>
+ <method name="direction_to">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="b" type="Vector2">
+ </argument>
+ <description>
+ Returns the normalized vector pointing from this vector to [code]b[/code].
+ </description>
+ </method>
<method name="distance_squared_to">
<return type="float">
</return>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 7b0d1c5a97..f1363f4fad 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -81,6 +81,15 @@
Performs a cubic interpolation between vectors [code]pre_a[/code], [code]a[/code], [code]b[/code], [code]post_b[/code] ([code]a[/code] is current), by the given amount [code]t[/code]. [code]t[/code] is in the range of [code]0.0 - 1.0[/code], representing the amount of interpolation.
</description>
</method>
+ <method name="direction_to">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="b" type="Vector3">
+ </argument>
+ <description>
+ Returns the normalized vector pointing from this vector to [code]b[/code].
+ </description>
+ </method>
<method name="distance_squared_to">
<return type="float">
</return>
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index dc6d270c08..e81b4db13e 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -1,11 +1,10 @@
#!/usr/bin/env python3
import argparse
-import sys
import os
import re
import xml.etree.ElementTree as ET
-from collections import defaultdict, OrderedDict
+from collections import OrderedDict
# Uncomment to do type checks. I have it commented out so it works below Python 3.5
#from typing import List, Dict, TextIO, Tuple, Iterable, Optional, DefaultDict, Any, Union
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index ddf4d1d85c..c0e07e0b8d 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -692,6 +692,7 @@ public:
RID render_target_create() { return RID(); }
void render_target_set_size(RID p_render_target, int p_width, int p_height) {}
RID render_target_get_texture(RID p_render_target) const { return RID(); }
+ void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {}
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {}
bool render_target_was_used(RID p_render_target) { return false; }
void render_target_clear_used(RID p_render_target) {}
@@ -781,7 +782,7 @@ public:
void initialize() {}
void begin_frame(double frame_step) {}
void set_current_render_target(RID p_render_target) {}
- void restore_render_target() {}
+ void restore_render_target(bool p_3d_was_drawn) {}
void clear_render_target(const Color &p_color) {}
void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) {}
void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {}
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 71b826d689..d3c6b041a8 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -32,7 +32,6 @@
#include "core/os/os.h"
#include "core/project_settings.h"
-#include "drivers/gl_context/context_gl.h"
#define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
#define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
@@ -321,7 +320,7 @@ void RasterizerGLES2::set_current_render_target(RID p_render_target) {
}
}
-void RasterizerGLES2::restore_render_target() {
+void RasterizerGLES2::restore_render_target(bool p_3d_was_drawn) {
ERR_FAIL_COND(storage->frame.current_rt == NULL);
RasterizerStorageGLES2::RenderTarget *rt = storage->frame.current_rt;
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
@@ -410,7 +409,11 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
glDisable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
- glBindTexture(GL_TEXTURE_2D, rt->color);
+ if (rt->external.fbo != 0) {
+ glBindTexture(GL_TEXTURE_2D, rt->external.color);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+ }
// TODO normals
diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h
index ed4eeb84d2..eeed86e263 100644
--- a/drivers/gles2/rasterizer_gles2.h
+++ b/drivers/gles2/rasterizer_gles2.h
@@ -56,7 +56,7 @@ public:
virtual void initialize();
virtual void begin_frame(double frame_step);
virtual void set_current_render_target(RID p_render_target);
- virtual void restore_render_target();
+ virtual void restore_render_target(bool p_3d_was_drawn);
virtual void clear_render_target(const Color &p_color);
virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0);
virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 3c8822175d..c996078ba6 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -2681,7 +2681,11 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
} else {
state.render_no_shadows = false;
- current_fb = storage->frame.current_rt->fbo;
+ if (storage->frame.current_rt->external.fbo != 0) {
+ current_fb = storage->frame.current_rt->external.fbo;
+ } else {
+ current_fb = storage->frame.current_rt->fbo;
+ }
env = environment_owner.getornull(p_environment);
viewport_width = storage->frame.current_rt->width;
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 01d5e35e56..b051c7d811 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -4664,6 +4664,23 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) {
rt->fbo = 0;
}
+ if (rt->external.fbo != 0) {
+ // free this
+ glDeleteFramebuffers(1, &rt->external.fbo);
+
+ // clean up our texture
+ Texture *t = texture_owner.get(rt->external.texture);
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->width = 0;
+ t->height = 0;
+ t->active = false;
+ texture_owner.free(rt->external.texture);
+ memdelete(t);
+
+ rt->external.fbo = 0;
+ }
+
if (rt->depth) {
if (config.support_depth_texture) {
glDeleteTextures(1, &rt->depth);
@@ -4742,7 +4759,108 @@ RID RasterizerStorageGLES2::render_target_get_texture(RID p_render_target) const
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
- return rt->texture;
+ if (rt->external.fbo == 0) {
+ return rt->texture;
+ } else {
+ return rt->external.texture;
+ }
+}
+
+void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ if (p_texture_id == 0) {
+ if (rt->external.fbo != 0) {
+ // free this
+ glDeleteFramebuffers(1, &rt->external.fbo);
+
+ // clean up our texture
+ Texture *t = texture_owner.get(rt->external.texture);
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->width = 0;
+ t->height = 0;
+ t->active = false;
+ texture_owner.free(rt->external.texture);
+ memdelete(t);
+
+ rt->external.fbo = 0;
+ rt->external.color = 0;
+ }
+ } else {
+ Texture *t;
+
+ if (rt->external.fbo == 0) {
+ // create our fbo
+ glGenFramebuffers(1, &rt->external.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+
+ // allocate a texture
+ t = memnew(Texture);
+
+ t->type = VS::TEXTURE_TYPE_2D;
+ t->flags = 0;
+ t->width = 0;
+ t->height = 0;
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->format = Image::FORMAT_RGBA8;
+ t->target = GL_TEXTURE_2D;
+ t->gl_format_cache = 0;
+ t->gl_internal_format_cache = 0;
+ t->gl_type_cache = 0;
+ t->data_size = 0;
+ t->compressed = false;
+ t->srgb = false;
+ t->total_data_size = 0;
+ t->ignore_mipmaps = false;
+ t->mipmaps = 1;
+ t->active = true;
+ t->tex_id = 0;
+ t->render_target = rt;
+
+ rt->external.texture = texture_owner.make_rid(t);
+ } else {
+ // bind our frame buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+
+ // find our texture
+ t = texture_owner.get(rt->external.texture);
+ }
+
+ // set our texture
+ t->tex_id = p_texture_id;
+ rt->external.color = p_texture_id;
+
+ // size shouldn't be different
+ t->width = rt->width;
+ t->height = rt->height;
+ t->alloc_height = rt->width;
+ t->alloc_width = rt->height;
+
+ // is there a point to setting the internal formats? we don't know them..
+
+ // set our texture as the destination for our framebuffer
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0);
+
+ // seeing we're rendering into this directly, better also use our depth buffer, just use our existing one :)
+ if (config.support_depth_texture) {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
+ } else {
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
+ }
+
+ // check status and unbind
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("framebuffer fail, status: %x\n", status);
+ }
+
+ ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
+ }
}
void RasterizerStorageGLES2::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index 361f304a17..2ac68fa47a 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -1156,6 +1156,16 @@ public:
Effect copy_screen_effect;
+ struct External {
+ GLuint fbo;
+ GLuint color;
+ RID texture;
+
+ External() :
+ fbo(0) {
+ }
+ } external;
+
int width, height;
bool flags[RENDER_TARGET_FLAG_MAX];
@@ -1176,6 +1186,7 @@ public:
for (int i = 0; i < RENDER_TARGET_FLAG_MAX; ++i) {
flags[i] = false;
}
+ external.fbo = 0;
}
};
@@ -1187,6 +1198,7 @@ public:
virtual RID render_target_create();
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height);
virtual RID render_target_get_texture(RID p_render_target) const;
+ virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
virtual bool render_target_was_used(RID p_render_target);
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index ec8202d92c..b0f1be47a1 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -2043,7 +2043,7 @@ void RasterizerCanvasGLES3::initialize() {
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(2));
+ glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8));
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index a4e042ae0e..bdffb1ecdc 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -32,7 +32,6 @@
#include "core/os/os.h"
#include "core/project_settings.h"
-#include "drivers/gl_context/context_gl.h"
RasterizerStorage *RasterizerGLES3::get_storage() {
@@ -253,11 +252,16 @@ void RasterizerGLES3::set_current_render_target(RID p_render_target) {
}
}
-void RasterizerGLES3::restore_render_target() {
+void RasterizerGLES3::restore_render_target(bool p_3d_was_drawn) {
ERR_FAIL_COND(storage->frame.current_rt == NULL);
RasterizerStorageGLES3::RenderTarget *rt = storage->frame.current_rt;
- glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
+ if (p_3d_was_drawn && rt->external.fbo != 0) {
+ // our external render buffer is now leading, render 2d into that.
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
+ }
glViewport(0, 0, rt->width, rt->height);
}
@@ -339,7 +343,11 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re
#if 1
Size2 win_size = OS::get_singleton()->get_window_size();
- glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
+ if (rt->external.fbo != 0) {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
+ } else {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
+ }
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
glBlitFramebuffer(0, 0, rt->width, rt->height, p_screen_rect.position.x, win_size.height - p_screen_rect.position.y - p_screen_rect.size.height, p_screen_rect.position.x + p_screen_rect.size.width, win_size.height - p_screen_rect.position.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index 7541c55c82..ad0d004c9d 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -56,7 +56,7 @@ public:
virtual void initialize();
virtual void begin_frame(double frame_step);
virtual void set_current_render_target(RID p_render_target);
- virtual void restore_render_target();
+ virtual void restore_render_target(bool p_3d_was_drawn);
virtual void clear_render_target(const Color &p_color);
virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0);
virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index df8bd9feb0..d1b704e09a 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -3660,10 +3660,14 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] || storage->frame.current_rt->width < 4 || storage->frame.current_rt->height < 4) { //no post process on small render targets
//no environment or transparent render, simply return and convert to SRGB
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ if (storage->frame.current_rt->external.fbo != 0) {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ }
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, true);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]);
storage->shaders.copy.set_conditional(CopyShaderGLES3::V_FLIP, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]);
storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]);
storage->shaders.copy.bind();
@@ -4003,7 +4007,11 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
}
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ if (storage->frame.current_rt->external.fbo != 0) {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ }
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, composite_from);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index c2e8cc5307..6169790163 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -6080,7 +6080,7 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount)
for (int j = 0; j < 6; j++) {
glEnableVertexAttribArray(j);
- glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, CAST_INT_TO_UCHAR_PTR((j * 16)));
+ glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, CAST_INT_TO_UCHAR_PTR(j * 16));
}
}
@@ -6794,6 +6794,24 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) {
glDeleteTextures(1, &rt->exposure.color);
rt->exposure.fbo = 0;
}
+
+ if (rt->external.fbo != 0) {
+ // free this
+ glDeleteFramebuffers(1, &rt->external.fbo);
+
+ // clean up our texture
+ Texture *t = texture_owner.get(rt->external.texture);
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->width = 0;
+ t->height = 0;
+ t->active = false;
+ texture_owner.free(rt->external.texture);
+ memdelete(t);
+
+ rt->external.fbo = 0;
+ }
+
Texture *tex = texture_owner.get(rt->texture);
tex->alloc_height = 0;
tex->alloc_width = 0;
@@ -7249,7 +7267,99 @@ RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) const
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
- return rt->texture;
+ if (rt->external.fbo == 0) {
+ return rt->texture;
+ } else {
+ return rt->external.texture;
+ }
+}
+
+void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ if (p_texture_id == 0) {
+ if (rt->external.fbo != 0) {
+ // free this
+ glDeleteFramebuffers(1, &rt->external.fbo);
+
+ // clean up our texture
+ Texture *t = texture_owner.get(rt->external.texture);
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->width = 0;
+ t->height = 0;
+ t->active = false;
+ texture_owner.free(rt->external.texture);
+ memdelete(t);
+
+ rt->external.fbo = 0;
+ }
+ } else {
+ Texture *t;
+
+ if (rt->external.fbo == 0) {
+ // create our fbo
+ glGenFramebuffers(1, &rt->external.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+
+ // allocate a texture
+ t = memnew(Texture);
+
+ t->type = VS::TEXTURE_TYPE_2D;
+ t->flags = 0;
+ t->width = 0;
+ t->height = 0;
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->format = Image::FORMAT_RGBA8;
+ t->target = GL_TEXTURE_2D;
+ t->gl_format_cache = 0;
+ t->gl_internal_format_cache = 0;
+ t->gl_type_cache = 0;
+ t->data_size = 0;
+ t->compressed = false;
+ t->srgb = false;
+ t->total_data_size = 0;
+ t->ignore_mipmaps = false;
+ t->mipmaps = 1;
+ t->active = true;
+ t->tex_id = 0;
+ t->render_target = rt;
+
+ rt->external.texture = texture_owner.make_rid(t);
+ } else {
+ // bind our frame buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+
+ // find our texture
+ t = texture_owner.get(rt->external.texture);
+ }
+
+ // set our texture
+ t->tex_id = p_texture_id;
+
+ // size shouldn't be different
+ t->width = rt->width;
+ t->height = rt->height;
+ t->alloc_height = rt->width;
+ t->alloc_width = rt->height;
+
+ // is there a point to setting the internal formats? we don't know them..
+
+ // set our texture as the destination for our framebuffer
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0);
+
+ // check status and unbind
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("framebuffer fail, status: %x\n", status);
+ }
+
+ ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
+ }
}
void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 330139e179..92916ed808 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -1345,6 +1345,15 @@ public:
fbo(0) {}
} exposure;
+ // External FBO to render our final result to (mostly used for ARVR)
+ struct External {
+ GLuint fbo;
+ RID texture;
+
+ External() :
+ fbo(0) {}
+ } external;
+
uint64_t last_exposure_tick;
int width, height;
@@ -1366,6 +1375,7 @@ public:
msaa(VS::VIEWPORT_MSAA_DISABLED) {
exposure.fbo = 0;
buffers.fbo = 0;
+ external.fbo = 0;
for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
flags[i] = false;
}
@@ -1383,6 +1393,7 @@ public:
virtual RID render_target_create();
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height);
virtual RID render_target_get_texture(RID p_render_target) const;
+ virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
virtual bool render_target_was_used(RID p_render_target);
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index babb393dcb..c4c5e0d709 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -197,12 +197,14 @@ void FileAccessWindows::seek(size_t p_position) {
last_error = OK;
if (fseek(f, p_position, SEEK_SET))
check_errors();
+ prev_op = 0;
}
void FileAccessWindows::seek_end(int64_t p_position) {
ERR_FAIL_COND(!f);
if (fseek(f, p_position, SEEK_END))
check_errors();
+ prev_op = 0;
}
size_t FileAccessWindows::get_position() const {
@@ -234,6 +236,12 @@ bool FileAccessWindows::eof_reached() const {
uint8_t FileAccessWindows::get_8() const {
ERR_FAIL_COND_V(!f, 0);
+ if (flags == READ_WRITE || flags == WRITE_READ) {
+ if (prev_op == WRITE) {
+ fflush(f);
+ }
+ prev_op = READ;
+ }
uint8_t b;
if (fread(&b, 1, 1, f) == 0) {
check_errors();
@@ -246,6 +254,12 @@ uint8_t FileAccessWindows::get_8() const {
int FileAccessWindows::get_buffer(uint8_t *p_dst, int p_length) const {
ERR_FAIL_COND_V(!f, -1);
+ if (flags == READ_WRITE || flags == WRITE_READ) {
+ if (prev_op == WRITE) {
+ fflush(f);
+ }
+ prev_op = READ;
+ }
int read = fread(p_dst, 1, p_length, f);
check_errors();
return read;
@@ -260,16 +274,34 @@ void FileAccessWindows::flush() {
ERR_FAIL_COND(!f);
fflush(f);
+ if (prev_op == WRITE)
+ prev_op = 0;
}
void FileAccessWindows::store_8(uint8_t p_dest) {
ERR_FAIL_COND(!f);
+ if (flags == READ_WRITE || flags == WRITE_READ) {
+ if (prev_op == READ) {
+ if (last_error != ERR_FILE_EOF) {
+ fseek(f, 0, SEEK_CUR);
+ }
+ }
+ prev_op = WRITE;
+ }
fwrite(&p_dest, 1, 1, f);
}
void FileAccessWindows::store_buffer(const uint8_t *p_src, int p_length) {
ERR_FAIL_COND(!f);
+ if (flags == READ_WRITE || flags == WRITE_READ) {
+ if (prev_op == READ) {
+ if (last_error != ERR_FILE_EOF) {
+ fseek(f, 0, SEEK_CUR);
+ }
+ }
+ prev_op = WRITE;
+ }
ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length);
}
@@ -310,6 +342,7 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
FileAccessWindows::FileAccessWindows() :
f(NULL),
flags(0),
+ prev_op(0),
last_error(OK) {
}
FileAccessWindows::~FileAccessWindows() {
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index c105eb5265..35b1f0b2d8 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -47,6 +47,7 @@ class FileAccessWindows : public FileAccess {
FILE *f;
int flags;
void check_errors() const;
+ mutable int prev_op;
mutable Error last_error;
String path;
String path_src;
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index d1f63f4866..8674d24af6 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -45,12 +45,12 @@ Error AudioDriverXAudio2::init() {
pcm_open = false;
samples_in = NULL;
- mix_rate = 48000;
+ mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
// FIXME: speaker_mode seems unused in the Xaudio2 driver so far
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
- int latency = GLOBAL_DEF_RST("audio/output_latency", 25);
+ int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
buffer_size = closest_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_size * channels);
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 5c35a91fea..5df2b687cc 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -496,7 +496,8 @@ void DependencyRemoveDialog::ok_pressed() {
res->set_path("");
}
- // If the file we are deleting for e.g. the main scene or default environment, we must clear its definition in Project Settings.
+ // If the file we are deleting for e.g. the main scene, default environment,
+ // or audio bus layout, we must clear its definition in Project Settings.
if (files_to_delete[i] == ProjectSettings::get_singleton()->get("application/config/icon")) {
ProjectSettings::get_singleton()->set("application/config/icon", "");
}
@@ -518,6 +519,9 @@ void DependencyRemoveDialog::ok_pressed() {
if (files_to_delete[i] == ProjectSettings::get_singleton()->get("gui/theme/custom_font")) {
ProjectSettings::get_singleton()->set("gui/theme/custom_font", "");
}
+ if (files_to_delete[i] == ProjectSettings::get_singleton()->get("audio/default_bus_layout")) {
+ ProjectSettings::get_singleton()->set("audio/default_bus_layout", "");
+ }
String path = OS::get_singleton()->get_resource_dir() + files_to_delete[i].replace_first("res://", "/");
print_verbose("Moving to trash: " + path);
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 29e9cd01c5..49d40e6d90 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -34,6 +34,7 @@
#include "core/os/keyboard.h"
#include "editor_node.h"
#include "filesystem_dock.h"
+#include "scene/resources/font.h"
#include "servers/audio_server.h"
void EditorAudioBus::_update_visible_channels() {
@@ -71,7 +72,6 @@ void EditorAudioBus::_notification(int p_what) {
channel[i].vu_r->set_progress_texture(get_icon("BusVuFull", "EditorIcons"));
channel[i].prev_active = true;
}
- scale->set_texture(get_icon("BusVuDb", "EditorIcons"));
disabled_vu = get_icon("BusVuFrozen", "EditorIcons");
@@ -167,7 +167,6 @@ void EditorAudioBus::_notification(int p_what) {
channel[i].vu_r->set_progress_texture(get_icon("BusVuFull", "EditorIcons"));
channel[i].prev_active = true;
}
- scale->set_texture(get_icon("BusVuDb", "EditorIcons"));
disabled_vu = get_icon("BusVuFrozen", "EditorIcons");
@@ -211,7 +210,8 @@ void EditorAudioBus::update_bus() {
int index = get_index();
- slider->set_value(AudioServer::get_singleton()->get_bus_volume_db(index));
+ float db_value = AudioServer::get_singleton()->get_bus_volume_db(index);
+ slider->set_value(_scaled_db_to_normalized_volume(db_value));
track_name->set_text(AudioServer::get_singleton()->get_bus_name(index));
if (is_master)
track_name->set_editable(false);
@@ -300,13 +300,15 @@ void EditorAudioBus::_name_changed(const String &p_new_name) {
track_name->release_focus();
}
-void EditorAudioBus::_volume_db_changed(float p_db) {
+void EditorAudioBus::_volume_changed(float p_normalized) {
if (updating_bus)
return;
updating_bus = true;
+ float p_db = this->_normalized_volume_to_scaled_db(p_normalized);
+
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db);
@@ -317,6 +319,69 @@ void EditorAudioBus::_volume_db_changed(float p_db) {
updating_bus = false;
}
+
+float EditorAudioBus::_normalized_volume_to_scaled_db(float normalized) {
+ /* There are three different formulas for the conversion from normalized
+ * values to relative decibal values.
+ * One formula is an exponential graph which intends to counteract
+ * the logorithmic nature of human hearing. This is an approximation
+ * of the behaviour of a 'logarithmic potentiometer' found on most
+ * musical instruments and also emulated in popular software.
+ * The other two equations are hand-tuned linear tapers that intend to
+ * try to ease the exponential equation in areas where it makes sense.*/
+
+ if (normalized > 0.6f) {
+ return 22.22f * normalized - 16.2f;
+ } else if (normalized < 0.05f) {
+ return 830.72 * normalized - 80.0f;
+ } else {
+ return 45.0f * Math::pow(normalized - 1.0, 3);
+ }
+}
+
+float EditorAudioBus::_scaled_db_to_normalized_volume(float db) {
+ /* Inversion of equations found in _normalized_volume_to_scaled_db.
+ * IMPORTANT: If one function changes, the other much change to reflect it. */
+ if (db > -2.88) {
+ return (db + 16.2f) / 22.22f;
+ } else if (db < -38.602f) {
+ return (db + 80.00f) / 830.72f;
+ } else {
+ if (db < 0.0) {
+ /* To acommodate for NaN on negative numbers for root, we will mirror the
+ * results of the postive db range in order to get the desired numerical
+ * value on the negative side. */
+ float positive_x = Math::pow(Math::abs(db) / 45.0f, 1.0f / 3.0f) + 1.0f;
+ Vector2 translation = Vector2(1.0f, 0.0f) - Vector2(positive_x, Math::abs(db));
+ Vector2 reflected_position = Vector2(1.0, 0.0f) + translation;
+ return reflected_position.x;
+ } else {
+ return Math::pow(db / 45.0f, 1.0f / 3.0f) + 1.0f;
+ }
+ }
+}
+
+void EditorAudioBus::_show_value(float slider_value) {
+ String text = vformat("%10.1f dB", _normalized_volume_to_scaled_db(slider_value));
+
+ audio_value_preview_label->set_text(text);
+ Vector2 slider_size = slider->get_size();
+ Vector2 slider_position = slider->get_global_position();
+ float left_padding = 5.0f;
+ float vert_padding = 10.0f;
+ Vector2 box_position = Vector2(slider_size.x + left_padding, (slider_size.y - vert_padding) * (1.0f - slider_value) - vert_padding);
+ audio_value_preview_box->set_position(slider_position + box_position);
+ audio_value_preview_box->set_size(audio_value_preview_label->get_size());
+ if (slider->has_focus() && !audio_value_preview_box->is_visible()) {
+ audio_value_preview_box->show();
+ }
+ preview_timer->start();
+}
+
+void EditorAudioBus::_hide_value_preview() {
+ audio_value_preview_box->hide();
+}
+
void EditorAudioBus::_solo_toggled() {
updating_bus = true;
@@ -653,7 +718,9 @@ void EditorAudioBus::_bind_methods() {
ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus);
ClassDB::bind_method("update_send", &EditorAudioBus::update_send);
ClassDB::bind_method("_name_changed", &EditorAudioBus::_name_changed);
- ClassDB::bind_method("_volume_db_changed", &EditorAudioBus::_volume_db_changed);
+ ClassDB::bind_method("_volume_changed", &EditorAudioBus::_volume_changed);
+ ClassDB::bind_method("_show_value", &EditorAudioBus::_show_value);
+ ClassDB::bind_method("_hide_value_preview", &EditorAudioBus::_hide_value_preview);
ClassDB::bind_method("_solo_toggled", &EditorAudioBus::_solo_toggled);
ClassDB::bind_method("_mute_toggled", &EditorAudioBus::_mute_toggled);
ClassDB::bind_method("_bypass_toggled", &EditorAudioBus::_bypass_toggled);
@@ -738,11 +805,42 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
HBoxContainer *hb = memnew(HBoxContainer);
vb->add_child(hb);
slider = memnew(VSlider);
- slider->set_min(-80);
- slider->set_max(24);
- slider->set_step(0.1);
-
- slider->connect("value_changed", this, "_volume_db_changed");
+ slider->set_min(0.0);
+ slider->set_max(1.0);
+ slider->set_step(0.0001);
+ slider->set_clip_contents(false);
+
+ audio_value_preview_box = memnew(Panel);
+ {
+ HBoxContainer *audioprev_hbc = memnew(HBoxContainer);
+ audioprev_hbc->set_v_size_flags(SIZE_EXPAND_FILL);
+ audioprev_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
+ audioprev_hbc->set_mouse_filter(MOUSE_FILTER_PASS);
+ audio_value_preview_box->add_child(audioprev_hbc);
+
+ audio_value_preview_label = memnew(Label);
+ audio_value_preview_label->set_v_size_flags(SIZE_EXPAND_FILL);
+ audio_value_preview_label->set_h_size_flags(SIZE_EXPAND_FILL);
+ audio_value_preview_label->set_mouse_filter(MOUSE_FILTER_PASS);
+
+ audioprev_hbc->add_child(audio_value_preview_label);
+ }
+ slider->add_child(audio_value_preview_box);
+ audio_value_preview_box->set_as_toplevel(true);
+ Ref<StyleBoxFlat> panel_style = memnew(StyleBoxFlat);
+ panel_style->set_bg_color(Color(0.0f, 0.0f, 0.0f, 0.8f));
+ audio_value_preview_box->add_style_override("panel", panel_style);
+ audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS);
+ audio_value_preview_box->hide();
+
+ preview_timer = memnew(Timer);
+ preview_timer->set_wait_time(0.8f);
+ preview_timer->set_one_shot(true);
+ add_child(preview_timer);
+
+ slider->connect("value_changed", this, "_volume_changed");
+ slider->connect("value_changed", this, "_show_value");
+ preview_timer->connect("timeout", this, "_hide_value_preview");
hb->add_child(slider);
cc = 0;
@@ -765,7 +863,12 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
channel[i].peak_r = 0.0f;
}
- scale = memnew(TextureRect);
+ scale = memnew(EditorAudioMeterNotches);
+
+ for (float db = 6.0f; db >= -80.0f; db -= 6.0f) {
+ bool renderNotch = (db >= -6.0f || db == -24.0f || db == -72.0f);
+ scale->add_notch(_scaled_db_to_normalized_volume(db), db, renderNotch);
+ }
hb->add_child(scale);
effects = memnew(Tree);
@@ -1077,14 +1180,16 @@ void EditorAudioBuses::_load_layout() {
void EditorAudioBuses::_load_default_layout() {
- Ref<AudioBusLayout> state = ResourceLoader::load("res://default_bus_layout.tres");
+ String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout");
+
+ Ref<AudioBusLayout> state = ResourceLoader::load(layout_path);
if (state.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("There is no 'res://default_bus_layout.tres' file."));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("There is no '%s' file."), layout_path));
return;
}
- edited_path = "res://default_bus_layout.tres";
- file->set_text(edited_path.get_file());
+ edited_path = layout_path;
+ file->set_text(layout_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
EditorNode::get_singleton()->get_undo_redo()->clear_history();
@@ -1213,7 +1318,7 @@ EditorAudioBuses::EditorAudioBuses() {
set_v_size_flags(SIZE_EXPAND_FILL);
- edited_path = "res://default_bus_layout.tres";
+ edited_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout");
file_dialog = memnew(EditorFileDialog);
List<String> ext;
@@ -1226,6 +1331,7 @@ EditorAudioBuses::EditorAudioBuses() {
set_process(true);
}
+
void EditorAudioBuses::open_layout(const String &p_path) {
EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
@@ -1270,3 +1376,50 @@ AudioBusesEditorPlugin::AudioBusesEditorPlugin(EditorAudioBuses *p_node) {
AudioBusesEditorPlugin::~AudioBusesEditorPlugin() {
}
+
+void EditorAudioMeterNotches::add_notch(float normalized_offset, float db_value, bool render_value) {
+ notches.push_back(AudioNotch(normalized_offset, db_value, render_value));
+}
+
+void EditorAudioMeterNotches::_bind_methods() {
+ ClassDB::bind_method("add_notch", &EditorAudioMeterNotches::add_notch);
+ ClassDB::bind_method("_draw_audio_notches", &EditorAudioMeterNotches::_draw_audio_notches);
+}
+
+void EditorAudioMeterNotches::_notification(int p_what) {
+ if (p_what == NOTIFICATION_DRAW) {
+ notch_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1.0f, 1.0f, 1.0f, 0.8f) : Color(0.0f, 0.0f, 0.0f, 0.8f);
+ _draw_audio_notches();
+ }
+}
+
+void EditorAudioMeterNotches::_draw_audio_notches() {
+ Ref<Font> font = get_font("source", "EditorFonts");
+ float font_height = font->get_height();
+
+ for (uint8_t i = 0; i < notches.size(); i++) {
+ AudioNotch n = notches[i];
+ draw_line(Vector2(0.0f, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),
+ Vector2(line_length, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),
+ notch_color,
+ 1.0f);
+
+ if (n.render_db_value) {
+ draw_string(font,
+ Vector2(line_length + label_space,
+ (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + (font_height / 4) + top_padding),
+ String("{0}dB").format(varray(Math::abs(n.db_value))),
+ notch_color);
+ }
+ }
+}
+
+EditorAudioMeterNotches::EditorAudioMeterNotches() :
+ line_length(5.0f),
+ label_space(2.0f),
+ btm_padding(9.0f),
+ top_padding(5.0f) {
+ this->set_v_size_flags(SIZE_EXPAND_FILL);
+ this->set_h_size_flags(SIZE_EXPAND_FILL);
+ notch_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1.0f, 1.0f, 1.0f, 0.8f) : Color(0.0f, 0.0f, 0.0f, 0.8f);
+}
diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h
index 37ff9b28dc..50f2101fd8 100644
--- a/editor/editor_audio_buses.h
+++ b/editor/editor_audio_buses.h
@@ -35,6 +35,7 @@
#include "editor_plugin.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
+#include "scene/gui/control.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/option_button.h"
@@ -71,13 +72,17 @@ class EditorAudioBus : public PanelContainer {
TextureProgress *vu_r;
} channel[CHANNELS_MAX];
- TextureRect *scale;
+ class EditorAudioMeterNotches *scale;
OptionButton *send;
PopupMenu *effect_options;
PopupMenu *bus_popup;
PopupMenu *delete_effect_popup;
+ Panel *audio_value_preview_box;
+ Label *audio_value_preview_label;
+ Timer *preview_timer;
+
Button *solo;
Button *mute;
Button *bypass;
@@ -93,7 +98,11 @@ class EditorAudioBus : public PanelContainer {
void _name_changed(const String &p_new_name);
void _name_focus_exit() { _name_changed(track_name->get_text()); }
- void _volume_db_changed(float p_db);
+ void _volume_changed(float p_normalized);
+ float _normalized_volume_to_scaled_db(float normalized);
+ float _scaled_db_to_normalized_volume(float db);
+ void _show_value(float slider_value);
+ void _hide_value_preview();
void _solo_toggled();
void _mute_toggled();
void _bypass_toggled();
@@ -200,6 +209,50 @@ public:
EditorAudioBuses();
};
+class EditorAudioMeterNotches : public Control {
+ GDCLASS(EditorAudioMeterNotches, Control);
+
+private:
+ struct AudioNotch {
+ float relative_position;
+ float db_value;
+ bool render_db_value;
+
+ _FORCE_INLINE_ AudioNotch(float r_pos, float db_v, bool rndr_val) {
+ relative_position = r_pos;
+ db_value = db_v;
+ render_db_value = rndr_val;
+ }
+
+ _FORCE_INLINE_ AudioNotch(const AudioNotch &n) {
+ relative_position = n.relative_position;
+ db_value = n.db_value;
+ render_db_value = n.render_db_value;
+ }
+
+ _FORCE_INLINE_ AudioNotch() {}
+ };
+
+ List<AudioNotch> notches;
+
+public:
+ float line_length;
+ float label_space;
+ float btm_padding;
+ float top_padding;
+ Color notch_color;
+
+ void add_notch(float normalized_offset, float db_value, bool render_value = false);
+
+private:
+ static void _bind_methods();
+ void _notification(int p_what);
+ void _draw_audio_notches();
+
+public:
+ EditorAudioMeterNotches();
+};
+
class AudioBusesEditorPlugin : public EditorPlugin {
GDCLASS(AudioBusesEditorPlugin, EditorPlugin);
diff --git a/editor/editor_builders.py b/editor/editor_builders.py
index 9e9fe752b4..19c5e0b924 100644
--- a/editor/editor_builders.py
+++ b/editor/editor_builders.py
@@ -6,7 +6,7 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
import os
import os.path
from platform_methods import subprocess_main
-from compat import encode_utf8, byte_to_str, open_utf8, escape_string
+from compat import encode_utf8, byte_to_str, open_utf8
def make_doc_header(target, source, env):
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 4c9f58f312..e6a6d9e6a6 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -1499,7 +1499,7 @@ EditorFileDialog::EditorFileDialog() {
dir_next = memnew(ToolButton);
dir_next->set_tooltip(TTR("Next Folder"));
dir_up = memnew(ToolButton);
- dir_up->set_tooltip(TTR("Go to parent folder"));
+ dir_up->set_tooltip(TTR("Go to parent folder."));
pathhb->add_child(dir_prev);
pathhb->add_child(dir_next);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 6c629c1869..91e104667e 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -5438,7 +5438,7 @@ EditorNode::EditorNode() {
p->add_shortcut(ED_SHORTCUT("editor/undo", TTR("Undo"), KEY_MASK_CMD + KEY_Z), EDIT_UNDO, true);
p->add_shortcut(ED_SHORTCUT("editor/redo", TTR("Redo"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_Z), EDIT_REDO, true);
p->add_separator();
- p->add_item(TTR("Revert Scene"), EDIT_REVERT);
+ p->add_shortcut(ED_SHORTCUT("editor/revert_scene", TTR("Revert Scene")), EDIT_REVERT);
recent_scenes = memnew(PopupMenu);
recent_scenes->set_name("RecentScenes");
@@ -5458,10 +5458,10 @@ EditorNode::EditorNode() {
p = project_menu->get_popup();
p->set_hide_on_window_lose_focus(true);
- p->add_item(TTR("Project Settings"), RUN_SETTINGS);
+ p->add_shortcut(ED_SHORTCUT("editor/project_settings", TTR("Project Settings")), RUN_SETTINGS);
p->add_separator();
p->connect("id_pressed", this, "_menu_option");
- p->add_item(TTR("Export"), FILE_EXPORT_PROJECT);
+ p->add_shortcut(ED_SHORTCUT("editor/export", TTR("Export")), FILE_EXPORT_PROJECT);
plugin_config_dialog = memnew(PluginConfigDialog);
plugin_config_dialog->connect("plugin_ready", this, "_on_plugin_ready");
@@ -5472,10 +5472,10 @@ EditorNode::EditorNode() {
tool_menu->connect("index_pressed", this, "_tool_menu_option");
p->add_child(tool_menu);
p->add_submenu_item(TTR("Tools"), "Tools");
- tool_menu->add_item(TTR("Orphan Resource Explorer"), TOOLS_ORPHAN_RESOURCES);
+ tool_menu->add_shortcut(ED_SHORTCUT("editor/orphan_resource_explorer", TTR("Orphan Resource Explorer")), TOOLS_ORPHAN_RESOURCES);
p->add_separator();
- p->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER);
+ p->add_shortcut(ED_SHORTCUT("editor/open_project_data_folder", TTR("Open Project Data Folder")), RUN_PROJECT_DATA_FOLDER);
p->add_separator();
#ifdef OSX_ENABLED
@@ -5499,21 +5499,21 @@ EditorNode::EditorNode() {
p = debug_menu->get_popup();
p->set_hide_on_window_lose_focus(true);
p->set_hide_on_item_selection(false);
- p->add_check_item(TTR("Deploy with Remote Debug"), RUN_DEPLOY_REMOTE_DEBUG);
+ p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When exporting or deploying, the resulting executable will attempt to connect to the IP of this computer in order to be debugged."));
- p->add_check_item(TTR("Small Deploy with Network FS"), RUN_FILE_SERVER);
+ p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network FS")), RUN_FILE_SERVER);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is enabled, export or deploy will produce a minimal executable.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploy will use the USB cable for faster performance. This option speeds up testing for games with a large footprint."));
p->add_separator();
- p->add_check_item(TTR("Visible Collision Shapes"), RUN_DEBUG_COLLISONS);
+ p->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS);
p->set_item_tooltip(p->get_item_count() - 1, TTR("Collision shapes and raycast nodes (for 2D and 3D) will be visible on the running game if this option is turned on."));
- p->add_check_item(TTR("Visible Navigation"), RUN_DEBUG_NAVIGATION);
+ p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
p->set_item_tooltip(p->get_item_count() - 1, TTR("Navigation meshes and polygons will be visible on the running game if this option is turned on."));
p->add_separator();
//those are now on by default, since they are harmless
- p->add_check_item(TTR("Sync Scene Changes"), RUN_LIVE_DEBUG);
+ p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Sync Scene Changes")), RUN_LIVE_DEBUG);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any changes made to the scene in the editor will be replicated in the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
p->set_item_checked(p->get_item_count() - 1, true);
- p->add_check_item(TTR("Sync Script Changes"), RUN_RELOAD_SCRIPTS);
+ p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Sync Script Changes")), RUN_RELOAD_SCRIPTS);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any script that is saved will be reloaded on the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
p->set_item_checked(p->get_item_count() - 1, true);
p->connect("id_pressed", this, "_menu_option");
@@ -5529,7 +5529,7 @@ EditorNode::EditorNode() {
p = settings_menu->get_popup();
p->set_hide_on_window_lose_focus(true);
- p->add_item(TTR("Editor Settings"), SETTINGS_PREFERENCES);
+ p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings")), SETTINGS_PREFERENCES);
p->add_separator();
editor_layouts = memnew(PopupMenu);
@@ -5567,14 +5567,14 @@ EditorNode::EditorNode() {
p = help_menu->get_popup();
p->set_hide_on_window_lose_focus(true);
p->connect("id_pressed", this, "_menu_option");
- p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_F4), HELP_SEARCH);
+ p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_MASK_SHIFT | KEY_F1), HELP_SEARCH);
p->add_separator();
- p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS);
- p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Q&A"), HELP_QA);
- p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Issue Tracker"), HELP_ISSUES);
- p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Community"), HELP_COMMUNITY);
+ p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Docs")), HELP_DOCS);
+ p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Q&A")), HELP_QA);
+ p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/issue_tracker", TTR("Issue Tracker")), HELP_ISSUES);
+ p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/community", TTR("Community")), HELP_COMMUNITY);
p->add_separator();
- p->add_icon_item(gui_base->get_icon("Godot", "EditorIcons"), TTR("About"), HELP_ABOUT);
+ p->add_icon_shortcut(gui_base->get_icon("Godot", "EditorIcons"), ED_SHORTCUT("editor/about", TTR("About")), HELP_ABOUT);
HBoxContainer *play_hb = memnew(HBoxContainer);
menu_hb->add_child(play_hb);
diff --git a/editor/editor_profiler.cpp b/editor/editor_profiler.cpp
index dee589ad3f..f73cd0beb5 100644
--- a/editor/editor_profiler.cpp
+++ b/editor/editor_profiler.cpp
@@ -625,6 +625,63 @@ bool EditorProfiler::is_profiling() {
return activate->is_pressed();
}
+Vector<Vector<String> > EditorProfiler::get_data_as_csv() const {
+ Vector<Vector<String> > res;
+
+ if (frame_metrics.empty()) {
+ return res;
+ }
+
+ // signatures
+ Vector<String> signatures;
+ const Vector<EditorProfiler::Metric::Category> &categories = frame_metrics[0].categories;
+
+ for (int j = 0; j < categories.size(); j++) {
+
+ const EditorProfiler::Metric::Category &c = categories[j];
+ signatures.push_back(c.signature);
+
+ for (int k = 0; k < c.items.size(); k++) {
+ signatures.push_back(c.items[k].signature);
+ }
+ }
+ res.push_back(signatures);
+
+ // values
+ Vector<String> values;
+ values.resize(signatures.size());
+
+ int index = last_metric;
+
+ for (int i = 0; i < frame_metrics.size(); i++) {
+
+ ++index;
+
+ if (index >= frame_metrics.size()) {
+ index = 0;
+ }
+
+ if (!frame_metrics[index].valid) {
+ continue;
+ }
+ int it = 0;
+ const Vector<EditorProfiler::Metric::Category> &frame_cat = frame_metrics[index].categories;
+
+ for (int j = 0; j < frame_cat.size(); j++) {
+
+ const EditorProfiler::Metric::Category &c = frame_cat[j];
+ values.write[it++] = String::num_real(c.total_time);
+
+ for (int k = 0; k < c.items.size(); k++) {
+ values.write[it++] = String::num_real(c.items[k].total);
+ }
+ }
+ res.push_back(values);
+ }
+
+ return res;
+}
+
EditorProfiler::EditorProfiler() {
HBoxContainer *hb = memnew(HBoxContainer);
diff --git a/editor/editor_profiler.h b/editor/editor_profiler.h
index 8fa09f8494..e62213887d 100644
--- a/editor/editor_profiler.h
+++ b/editor/editor_profiler.h
@@ -169,6 +169,8 @@ public:
void clear();
+ Vector<Vector<String> > get_data_as_csv() const;
+
EditorProfiler();
};
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index c13a4a5a5e..0e8cd955b5 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2289,6 +2289,16 @@ void EditorPropertyResource::_update_menu_items() {
E = E->next();
}
+ List<StringName> global_classes;
+ ScriptServer::get_global_class_list(&global_classes);
+ E = global_classes.front();
+ while (E) {
+ if (EditorNode::get_editor_data().script_class_is_parent(E->get(), base_type)) {
+ valid_inheritors.insert(E->get());
+ }
+ E = E->next();
+ }
+
for (Set<String>::Element *F = valid_inheritors.front(); F; F = F->next()) {
String t = F->get();
@@ -2305,7 +2315,7 @@ void EditorPropertyResource::_update_menu_items() {
}
}
- if (!is_custom_resource && !ClassDB::can_instance(t))
+ if (!is_custom_resource && !(ScriptServer::is_global_class(t) || ClassDB::can_instance(t)))
continue;
inheritors_array.push_back(t);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 5c257b86db..b9ed63c1b6 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -675,14 +675,14 @@ bool EditorSettings::_save_text_editor_theme(String p_file) {
static Dictionary _get_builtin_script_templates() {
Dictionary templates;
- //No Comments
+ // No Comments
templates["no_comments.gd"] =
"extends %BASE%\n"
"\n"
- "func _ready():\n"
+ "func _ready()%VOID_RETURN%:\n"
"%TS%pass\n";
- //Empty
+ // Empty
templates["empty.gd"] =
"extends %BASE%"
"\n"
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index c930824b98..335e3fcd29 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -403,7 +403,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// this is the most commonly used stylebox, variations should be made as duplicate of this
Ref<StyleBoxFlat> style_default = make_flat_stylebox(base_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size);
style_default->set_border_width_all(border_width);
- style_default->set_border_color_all(base_color);
+ style_default->set_border_color(base_color);
style_default->set_draw_center(true);
// Button and widgets
@@ -415,20 +415,20 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_widget->set_default_margin(MARGIN_RIGHT, (extra_spacing + 6) * EDSCALE);
style_widget->set_default_margin(MARGIN_BOTTOM, (extra_spacing + default_margin_size) * EDSCALE);
style_widget->set_bg_color(dark_color_1);
- style_widget->set_border_color_all(dark_color_2);
+ style_widget->set_border_color(dark_color_2);
Ref<StyleBoxFlat> style_widget_disabled = style_widget->duplicate();
- style_widget_disabled->set_border_color_all(color_disabled);
+ style_widget_disabled->set_border_color(color_disabled);
style_widget_disabled->set_bg_color(color_disabled_bg);
Ref<StyleBoxFlat> style_widget_focus = style_widget->duplicate();
- style_widget_focus->set_border_color_all(accent_color);
+ style_widget_focus->set_border_color(accent_color);
Ref<StyleBoxFlat> style_widget_pressed = style_widget->duplicate();
- style_widget_pressed->set_border_color_all(accent_color);
+ style_widget_pressed->set_border_color(accent_color);
Ref<StyleBoxFlat> style_widget_hover = style_widget->duplicate();
- style_widget_hover->set_border_color_all(contrast_color_1);
+ style_widget_hover->set_border_color(contrast_color_1);
// style for windows, popups, etc..
Ref<StyleBoxFlat> style_popup = style_default->duplicate();
@@ -437,7 +437,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_popup->set_default_margin(MARGIN_TOP, popup_margin_size);
style_popup->set_default_margin(MARGIN_RIGHT, popup_margin_size);
style_popup->set_default_margin(MARGIN_BOTTOM, popup_margin_size);
- style_popup->set_border_color_all(contrast_color_1);
+ style_popup->set_border_color(contrast_color_1);
style_popup->set_border_width_all(MAX(EDSCALE, border_width));
const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1);
style_popup->set_shadow_color(shadow_color);
@@ -470,7 +470,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tab_selected->set_border_width_all(border_width);
style_tab_selected->set_border_width(MARGIN_BOTTOM, 0);
- style_tab_selected->set_border_color_all(dark_color_3);
+ style_tab_selected->set_border_color(dark_color_3);
style_tab_selected->set_expand_margin_size(MARGIN_BOTTOM, border_width);
style_tab_selected->set_default_margin(MARGIN_LEFT, tab_default_margin_side);
style_tab_selected->set_default_margin(MARGIN_RIGHT, tab_default_margin_side);
@@ -480,11 +480,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_tab_unselected = style_tab_selected->duplicate();
style_tab_unselected->set_bg_color(dark_color_1);
- style_tab_unselected->set_border_color_all(dark_color_2);
+ style_tab_unselected->set_border_color(dark_color_2);
Ref<StyleBoxFlat> style_tab_disabled = style_tab_selected->duplicate();
style_tab_disabled->set_bg_color(color_disabled_bg);
- style_tab_disabled->set_border_color_all(color_disabled);
+ style_tab_disabled->set_border_color(color_disabled);
// Editor background
theme->set_stylebox("Background", "EditorStyles", make_flat_stylebox(background_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size));
@@ -492,7 +492,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Focus
Ref<StyleBoxFlat> style_focus = style_default->duplicate();
style_focus->set_draw_center(false);
- style_focus->set_border_color_all(contrast_color_2);
+ style_focus->set_border_color(contrast_color_2);
theme->set_stylebox("Focus", "EditorStyles", style_focus);
// Menu
@@ -514,7 +514,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_menu_hover_border->set_draw_center(false);
style_menu_hover_border->set_border_width_all(0);
style_menu_hover_border->set_border_width(MARGIN_BOTTOM, border_width);
- style_menu_hover_border->set_border_color_all(accent_color);
+ style_menu_hover_border->set_border_color(accent_color);
Ref<StyleBoxFlat> style_menu_hover_bg = style_widget->duplicate();
style_menu_hover_bg->set_border_width_all(0);
@@ -644,11 +644,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> sub_inspector_bg = make_flat_stylebox(dark_color_1.linear_interpolate(accent_color, 0.08), 2, 0, 2, 2);
sub_inspector_bg->set_border_width(MARGIN_LEFT, 2);
- sub_inspector_bg->set_border_color(MARGIN_LEFT, accent_color * Color(1, 1, 1, 0.3));
sub_inspector_bg->set_border_width(MARGIN_RIGHT, 2);
- sub_inspector_bg->set_border_color(MARGIN_RIGHT, accent_color * Color(1, 1, 1, 0.3));
sub_inspector_bg->set_border_width(MARGIN_BOTTOM, 2);
- sub_inspector_bg->set_border_color(MARGIN_BOTTOM, accent_color * Color(1, 1, 1, 0.3));
+ sub_inspector_bg->set_border_color(accent_color * Color(1, 1, 1, 0.3));
sub_inspector_bg->set_draw_center(true);
theme->set_stylebox("sub_inspector_bg", "Editor", sub_inspector_bg);
@@ -657,7 +655,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Tree & ItemList background
Ref<StyleBoxFlat> style_tree_bg = style_default->duplicate();
style_tree_bg->set_bg_color(dark_color_1);
- style_tree_bg->set_border_color_all(dark_color_3);
+ style_tree_bg->set_border_color(dark_color_3);
theme->set_stylebox("bg", "Tree", style_tree_bg);
const Color guide_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.05);
@@ -708,7 +706,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_tree_cursor = style_default->duplicate();
style_tree_cursor->set_draw_center(false);
style_tree_cursor->set_border_width_all(border_width);
- style_tree_cursor->set_border_color_all(contrast_color_1);
+ style_tree_cursor->set_border_color(contrast_color_1);
Ref<StyleBoxFlat> style_tree_title = style_default->duplicate();
style_tree_title->set_bg_color(dark_color_3);
@@ -731,12 +729,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_itemlist_bg = style_default->duplicate();
style_itemlist_bg->set_bg_color(dark_color_1);
style_itemlist_bg->set_border_width_all(border_width);
- style_itemlist_bg->set_border_color_all(dark_color_3);
+ style_itemlist_bg->set_border_color(dark_color_3);
Ref<StyleBoxFlat> style_itemlist_cursor = style_default->duplicate();
style_itemlist_cursor->set_draw_center(false);
style_itemlist_cursor->set_border_width_all(border_width);
- style_itemlist_cursor->set_border_color_all(highlight_color);
+ style_itemlist_cursor->set_border_color(highlight_color);
theme->set_stylebox("cursor", "ItemList", style_itemlist_cursor);
theme->set_stylebox("cursor_unfocused", "ItemList", style_itemlist_cursor);
theme->set_stylebox("selected_focus", "ItemList", style_tree_focus);
@@ -781,7 +779,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Content of each tab
Ref<StyleBoxFlat> style_content_panel = style_default->duplicate();
- style_content_panel->set_border_color_all(dark_color_3);
+ style_content_panel->set_border_color(dark_color_3);
style_content_panel->set_border_width_all(border_width);
// compensate the border
style_content_panel->set_default_margin(MARGIN_TOP, margin_size_extra * EDSCALE);
@@ -834,7 +832,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons"));
theme->set_color("font_color", "TextEdit", font_color);
- theme->set_color("caret_color", "TextEdit", highlight_color);
+ theme->set_color("caret_color", "TextEdit", font_color);
theme->set_color("selection_color", "TextEdit", font_color_selection);
// H/VSplitContainer
@@ -860,7 +858,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// WindowDialog
Ref<StyleBoxFlat> style_window = style_popup->duplicate();
- style_window->set_border_color_all(tab_color);
+ style_window->set_border_color(tab_color);
style_window->set_border_width(MARGIN_TOP, 24 * EDSCALE);
style_window->set_expand_margin_size(MARGIN_TOP, 24 * EDSCALE);
theme->set_stylebox("panel", "WindowDialog", style_window);
@@ -875,7 +873,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// complex window, for now only Editor settings and Project settings
Ref<StyleBoxFlat> style_complex_window = style_window->duplicate();
style_complex_window->set_bg_color(dark_color_2);
- style_complex_window->set_border_color_all(highlight_tabs ? tab_color : dark_color_2);
+ style_complex_window->set_border_color(highlight_tabs ? tab_color : dark_color_2);
theme->set_stylebox("panel", "EditorSettingsDialog", style_complex_window);
theme->set_stylebox("panel", "ProjectSettingsEditor", style_complex_window);
theme->set_stylebox("panel", "EditorAbout", style_complex_window);
@@ -954,7 +952,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tooltip->set_default_margin(MARGIN_BOTTOM, v);
style_tooltip->set_bg_color(Color(mono_color.r, mono_color.g, mono_color.b, 0.9));
style_tooltip->set_border_width_all(border_width);
- style_tooltip->set_border_color_all(mono_color);
+ style_tooltip->set_border_color(mono_color);
theme->set_color("font_color", "TooltipLabel", font_color.inverted());
theme->set_color("font_color_shadow", "TooltipLabel", mono_color.inverted() * Color(1, 1, 1, 0.1));
theme->set_stylebox("panel", "TooltipPanel", style_tooltip);
@@ -989,32 +987,32 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const int gn_margin_side = 28;
Ref<StyleBoxFlat> graphsb = make_flat_stylebox(Color(mv, mv, mv, 0.7), gn_margin_side, 24, gn_margin_side, 5);
graphsb->set_border_width_all(border_width);
- graphsb->set_border_color_all(Color(mv2, mv2, mv2, 0.9));
+ graphsb->set_border_color(Color(mv2, mv2, mv2, 0.9));
Ref<StyleBoxFlat> graphsbselected = make_flat_stylebox(Color(mv, mv, mv, 0.9), gn_margin_side, 24, gn_margin_side, 5);
graphsbselected->set_border_width_all(border_width);
- graphsbselected->set_border_color_all(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
+ graphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
graphsbselected->set_shadow_size(8 * EDSCALE);
graphsbselected->set_shadow_color(shadow_color);
Ref<StyleBoxFlat> graphsbcomment = make_flat_stylebox(Color(mv, mv, mv, 0.3), gn_margin_side, 24, gn_margin_side, 5);
graphsbcomment->set_border_width_all(border_width);
- graphsbcomment->set_border_color_all(Color(mv2, mv2, mv2, 0.9));
+ graphsbcomment->set_border_color(Color(mv2, mv2, mv2, 0.9));
Ref<StyleBoxFlat> graphsbcommentselected = make_flat_stylebox(Color(mv, mv, mv, 0.4), gn_margin_side, 24, gn_margin_side, 5);
graphsbcommentselected->set_border_width_all(border_width);
- graphsbcommentselected->set_border_color_all(Color(mv2, mv2, mv2, 0.9));
+ graphsbcommentselected->set_border_color(Color(mv2, mv2, mv2, 0.9));
Ref<StyleBoxFlat> graphsbbreakpoint = graphsbselected->duplicate();
graphsbbreakpoint->set_draw_center(false);
- graphsbbreakpoint->set_border_color_all(warning_color);
+ graphsbbreakpoint->set_border_color(warning_color);
graphsbbreakpoint->set_shadow_color(warning_color * Color(1.0, 1.0, 1.0, 0.1));
Ref<StyleBoxFlat> graphsbposition = graphsbselected->duplicate();
graphsbposition->set_draw_center(false);
- graphsbposition->set_border_color_all(error_color);
+ graphsbposition->set_border_color(error_color);
graphsbposition->set_shadow_color(error_color * Color(1.0, 1.0, 1.0, 0.2));
Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(Color(mv, mv, mv, 0.7), gn_margin_side, 24, gn_margin_side, 5);
smgraphsb->set_border_width_all(border_width);
- smgraphsb->set_border_color_all(Color(mv2, mv2, mv2, 0.9));
+ smgraphsb->set_border_color(Color(mv2, mv2, mv2, 0.9));
Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(Color(mv, mv, mv, 0.9), gn_margin_side, 24, gn_margin_side, 5);
smgraphsbselected->set_border_width_all(border_width);
- smgraphsbselected->set_border_color_all(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
+ smgraphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
smgraphsbselected->set_shadow_size(8 * EDSCALE);
smgraphsbselected->set_shadow_color(shadow_color);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index c99786bb07..b637148f2d 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1429,6 +1429,10 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> p_selected)
case FILE_SHOW_IN_EXPLORER: {
// Show the file / folder in the OS explorer
String fpath = path;
+ if (path == "Favorites") {
+ fpath = p_selected[0];
+ }
+
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
@@ -2023,10 +2027,10 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
if (p_paths.size() >= 1) {
if (!all_favorites) {
- p_popup->add_item(TTR("Add to favorites"), FILE_ADD_FAVORITE);
+ p_popup->add_item(TTR("Add to Favorites"), FILE_ADD_FAVORITE);
}
if (!all_not_favorites) {
- p_popup->add_item(TTR("Remove from favorites"), FILE_REMOVE_FAVORITE);
+ p_popup->add_item(TTR("Remove from Favorites"), FILE_REMOVE_FAVORITE);
}
p_popup->add_separator();
}
@@ -2336,13 +2340,13 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
button_hist_prev = memnew(ToolButton);
button_hist_prev->set_disabled(true);
button_hist_prev->set_focus_mode(FOCUS_NONE);
- button_hist_prev->set_tooltip(TTR("Previous Directory"));
+ button_hist_prev->set_tooltip(TTR("Previous Folder/File"));
toolbar_hbc->add_child(button_hist_prev);
button_hist_next = memnew(ToolButton);
button_hist_next->set_disabled(true);
button_hist_next->set_focus_mode(FOCUS_NONE);
- button_hist_next->set_tooltip(TTR("Next Directory"));
+ button_hist_next->set_tooltip(TTR("Next Folder/File"));
toolbar_hbc->add_child(button_hist_next);
current_path = memnew(LineEdit);
@@ -2363,7 +2367,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
button_toggle_display_mode->set_toggle_mode(true);
button_toggle_display_mode->connect("toggled", this, "_toggle_split_mode");
button_toggle_display_mode->set_focus_mode(FOCUS_NONE);
- button_toggle_display_mode->set_tooltip(TTR("Toggle split mode"));
+ button_toggle_display_mode->set_tooltip(TTR("Toggle Split Mode"));
toolbar_hbc->add_child(button_toggle_display_mode);
HBoxContainer *toolbar2_hbc = memnew(HBoxContainer);
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index 857d8992fd..52dec47343 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -35,6 +35,9 @@
#include "core/os/file_access.h"
#include "scene/resources/audio_stream_sample.h"
+const float TRIM_DB_LIMIT = -50;
+const int TRIM_FADE_OUT_FRAMES = 500;
+
String ResourceImporterWAV::get_importer_name() const {
return "wav";
@@ -393,31 +396,42 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
if (trim && !loop && format_channels > 0) {
int first = 0;
- int last = (frames * format_channels) - 1;
+ int last = (frames / format_channels) - 1;
bool found = false;
- float limit = Math::db2linear((float)-30);
- for (int i = 0; i < data.size(); i++) {
- float amp = Math::abs(data[i]);
+ float limit = Math::db2linear(TRIM_DB_LIMIT);
+
+ for (int i = 0; i < data.size() / format_channels; i++) {
+ float ampChannelSum = 0;
+ for (int j = 0; j < format_channels; j++) {
+ ampChannelSum += Math::abs(data[(i * format_channels) + j]);
+ }
+
+ float amp = Math::abs(ampChannelSum / (float)format_channels);
if (!found && amp > limit) {
- first = i;
+ first = i / format_channels;
found = true;
}
if (found && amp > limit) {
- last = i;
+ last = i / format_channels;
}
}
- first /= format_channels;
- last /= format_channels;
-
if (first < last) {
-
Vector<float> new_data;
- new_data.resize((last - first + 1) * format_channels);
- for (int i = first * format_channels; i < (last + 1) * format_channels; i++) {
- new_data.write[i - first * format_channels] = data[i];
+ new_data.resize((last - first) * format_channels);
+ for (int i = first; i < last; i++) {
+
+ float fadeOutMult = 1;
+
+ if (last - i < TRIM_FADE_OUT_FRAMES) {
+ fadeOutMult = ((float)(last - i - 1) / (float)TRIM_FADE_OUT_FRAMES);
+ }
+
+ for (int j = 0; j < format_channels; j++) {
+ new_data.write[((i - first) * format_channels) + j] = data[(i * format_channels) + j] * fadeOutMult;
+ }
}
data = new_data;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index afe2573898..f13c2170ea 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -80,6 +80,7 @@ void AnimationNodeBlendTreeEditor::_update_options_menu() {
}
add_node->get_popup()->add_separator();
add_node->get_popup()->add_item(TTR("Load..."), MENU_LOAD_FILE);
+ use_popup_menu_position = false;
}
Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
@@ -240,7 +241,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode");
- Color c = sb->get_border_color(MARGIN_TOP);
+ Color c = sb->get_border_color();
Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
mono_color.a = 0.85;
c = mono_color;
@@ -317,7 +318,15 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
EditorNode::get_singleton()->show_warning(TTR("Output node can't be added to the blend tree."));
return;
}
- Point2 instance_pos = graph->get_scroll_ofs() + graph->get_size() * 0.5;
+
+ Point2 instance_pos = graph->get_scroll_ofs();
+ if (use_popup_menu_position) {
+ instance_pos += popup_menu_position;
+ } else {
+ instance_pos += graph->get_size() * 0.5;
+ }
+
+ instance_pos /= graph->get_zoom();
int base = 1;
String name = base_name;
@@ -412,6 +421,40 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
undo_redo->commit_action();
}
+void AnimationNodeBlendTreeEditor::_delete_nodes_request() {
+
+ List<StringName> to_erase;
+
+ for (int i = 0; i < graph->get_child_count(); i++) {
+ GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
+ if (gn) {
+ if (gn->is_selected() && gn->is_close_button_visible()) {
+ to_erase.push_back(gn->get_name());
+ }
+ }
+ }
+
+ if (to_erase.empty())
+ return;
+
+ undo_redo->create_action(TTR("Delete Node(s)"));
+
+ for (List<StringName>::Element *F = to_erase.front(); F; F = F->next()) {
+ _delete_request(F->get());
+ }
+
+ undo_redo->commit_action();
+}
+
+void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+
+ _update_options_menu();
+ use_popup_menu_position = true;
+ popup_menu_position = graph->get_local_mouse_position();
+ add_node->get_popup()->set_position(p_position);
+ add_node->get_popup()->popup();
+}
+
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
@@ -730,6 +773,8 @@ void AnimationNodeBlendTreeEditor::_bind_methods() {
ClassDB::bind_method("_open_in_editor", &AnimationNodeBlendTreeEditor::_open_in_editor);
ClassDB::bind_method("_scroll_changed", &AnimationNodeBlendTreeEditor::_scroll_changed);
ClassDB::bind_method("_delete_request", &AnimationNodeBlendTreeEditor::_delete_request);
+ ClassDB::bind_method("_delete_nodes_request", &AnimationNodeBlendTreeEditor::_delete_nodes_request);
+ ClassDB::bind_method("_popup_request", &AnimationNodeBlendTreeEditor::_popup_request);
ClassDB::bind_method("_edit_filters", &AnimationNodeBlendTreeEditor::_edit_filters);
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited);
@@ -850,6 +895,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
singleton = this;
updating = false;
+ use_popup_menu_position = false;
graph = memnew(GraphEdit);
add_child(graph);
@@ -860,6 +906,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->connect("disconnection_request", this, "_disconnection_request", varray(), CONNECT_DEFERRED);
graph->connect("node_selected", this, "_node_selected");
graph->connect("scroll_offset_changed", this, "_scroll_changed");
+ graph->connect("delete_nodes_request", this, "_delete_nodes_request");
+ graph->connect("popup_request", this, "_popup_request");
VSeparator *vs = memnew(VSeparator);
graph->get_zoom_hbox()->add_child(vs);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index f2a77cecb4..cb40159a40 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -51,6 +51,8 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeBlendTree> blend_tree;
GraphEdit *graph;
MenuButton *add_node;
+ Vector2 popup_menu_position;
+ bool use_popup_menu_position;
PanelContainer *error_panel;
Label *error_label;
@@ -97,6 +99,8 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _open_in_editor(const String &p_which);
void _anim_selected(int p_index, Array p_options, const String &p_node);
void _delete_request(const String &p_which);
+ void _delete_nodes_request();
+ void _popup_request(const Vector2 &p_position);
bool _update_filters(const Ref<AnimationNode> &anode);
void _edit_filters(const String &p_which);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 11eec528c7..c3cac582ad 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1072,36 +1072,36 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
}
}
- if (drag_type == DRAG_NONE) {
+ if (!panning) {
if (b->is_pressed() &&
(b->get_button_index() == BUTTON_MIDDLE ||
(b->get_button_index() == BUTTON_LEFT && tool == TOOL_PAN) ||
(b->get_button_index() == BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
// Pan the viewport
- drag_type = DRAG_PAN;
+ panning = true;
}
}
- if (drag_type == DRAG_PAN) {
+ if (panning) {
if (!b->is_pressed()) {
// Stop panning the viewport (for any mouse button press)
- drag_type = DRAG_NONE;
+ panning = false;
}
}
}
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
- if (k->get_scancode() == KEY_SPACE && EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning")) {
- if (drag_type == DRAG_NONE) {
+ if (k->get_scancode() == KEY_SPACE && (EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") || drag_type != DRAG_NONE)) {
+ if (!panning) {
if (k->is_pressed() && !k->is_echo()) {
//Pan the viewport
- drag_type = DRAG_PAN;
+ panning = true;
}
- } else if (drag_type == DRAG_PAN) {
+ } else if (panning) {
if (!k->is_pressed()) {
// Stop panning the viewport (for any mouse button press)
- drag_type = DRAG_NONE;
+ panning = false;
}
}
}
@@ -1109,7 +1109,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> m = p_event;
if (m.is_valid()) {
- if (drag_type == DRAG_PAN) {
+ if (panning) {
// Pan the viewport
Point2i relative;
if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) {
@@ -2190,32 +2190,34 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
bool accepted = false;
- if ((accepted = _gui_input_rulers_and_guides(p_event))) {
- //printf("Rulers and guides\n");
- } else if ((accepted = editor->get_editor_plugins_over()->forward_gui_input(p_event))) {
- //printf("Plugin\n");
- } else if ((accepted = _gui_input_open_scene_on_double_click(p_event))) {
- //printf("Open scene on double click\n");
- } else if ((accepted = _gui_input_anchors(p_event))) {
- //printf("Anchors\n");
- } else if ((accepted = _gui_input_scale(p_event))) {
- //printf("Set scale\n");
- } else if ((accepted = _gui_input_pivot(p_event))) {
- //printf("Set pivot\n");
- } else if ((accepted = _gui_input_resize(p_event))) {
- //printf("Resize\n");
- } else if ((accepted = _gui_input_rotate(p_event))) {
- //printf("Rotate\n");
- } else if ((accepted = _gui_input_move(p_event))) {
- //printf("Move\n");
- } else if ((accepted = _gui_input_zoom_or_pan(p_event))) {
- //printf("Zoom or pan\n");
- } else if ((accepted = _gui_input_select(p_event))) {
- //printf("Selection\n");
- } else {
- //printf("Not accepted\n");
+ if (EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") || !Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
+ if ((accepted = _gui_input_rulers_and_guides(p_event))) {
+ //printf("Rulers and guides\n");
+ } else if ((accepted = editor->get_editor_plugins_over()->forward_gui_input(p_event))) {
+ //printf("Plugin\n");
+ } else if ((accepted = _gui_input_open_scene_on_double_click(p_event))) {
+ //printf("Open scene on double click\n");
+ } else if ((accepted = _gui_input_anchors(p_event))) {
+ //printf("Anchors\n");
+ } else if ((accepted = _gui_input_scale(p_event))) {
+ //printf("Set scale\n");
+ } else if ((accepted = _gui_input_pivot(p_event))) {
+ //printf("Set pivot\n");
+ } else if ((accepted = _gui_input_resize(p_event))) {
+ //printf("Resize\n");
+ } else if ((accepted = _gui_input_rotate(p_event))) {
+ //printf("Rotate\n");
+ } else if ((accepted = _gui_input_move(p_event))) {
+ //printf("Move\n");
+ } else if ((accepted = _gui_input_select(p_event))) {
+ //printf("Selection\n");
+ } else {
+ //printf("Not accepted\n");
+ }
}
+ accepted = (_gui_input_zoom_or_pan(p_event) || accepted);
+
if (accepted)
accept_event();
@@ -2259,9 +2261,6 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
case DRAG_MOVE:
c = CURSOR_MOVE;
break;
- case DRAG_PAN:
- c = CURSOR_DRAG;
- break;
default:
break;
}
@@ -4591,6 +4590,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
drag_to = Vector2();
dragged_guide_pos = Point2();
dragged_guide_index = -1;
+ panning = false;
bone_last_frame = 0;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 4d8c0282fd..9173c55ae0 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -205,8 +205,7 @@ private:
DRAG_V_GUIDE,
DRAG_H_GUIDE,
DRAG_DOUBLE_GUIDE,
- DRAG_KEY_MOVE,
- DRAG_PAN
+ DRAG_KEY_MOVE
};
EditorSelection *editor_selection;
@@ -262,6 +261,7 @@ private:
bool key_pos;
bool key_rot;
bool key_scale;
+ bool panning;
MenuOption last_option;
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 10023d88bf..c8561d22a4 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -93,7 +93,7 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const {
case RECTANGLE_SHAPE: {
Ref<RectangleShape2D> rect = node->get_shape();
- if (idx < 2) {
+ if (idx < 3) {
return rect->get_extents().abs();
}
@@ -175,12 +175,15 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
} break;
case RECTANGLE_SHAPE: {
- if (idx < 2) {
+ if (idx < 3) {
Ref<RectangleShape2D> rect = node->get_shape();
Vector2 extents = rect->get_extents();
- extents[idx] = p_point[idx];
-
+ if (idx == 2) {
+ extents = p_point;
+ } else {
+ extents[idx] = p_point[idx];
+ }
rect->set_extents(extents.abs());
canvas_item_editor->update_viewport();
@@ -496,13 +499,15 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
case RECTANGLE_SHAPE: {
Ref<RectangleShape2D> shape = node->get_shape();
- handles.resize(2);
+ handles.resize(3);
Vector2 ext = shape->get_extents();
handles.write[0] = Point2(ext.x, 0);
handles.write[1] = Point2(0, -ext.y);
+ handles.write[2] = Point2(ext.x, -ext.y);
p_overlay->draw_texture(h, gt.xform(handles[0]) - size);
p_overlay->draw_texture(h, gt.xform(handles[1]) - size);
+ p_overlay->draw_texture(h, gt.xform(handles[2]) - size);
} break;
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 3a61277f36..42aba78e96 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -3083,13 +3083,13 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
site_search->set_text(TTR("Online Docs"));
site_search->connect("pressed", this, "_menu_option", varray(SEARCH_WEBSITE));
menu_hb->add_child(site_search);
- site_search->set_tooltip(TTR("Open Godot online documentation"));
+ site_search->set_tooltip(TTR("Open Godot online documentation."));
request_docs = memnew(ToolButton);
request_docs->set_text(TTR("Request Docs"));
request_docs->connect("pressed", this, "_menu_option", varray(REQUEST_DOCS));
menu_hb->add_child(request_docs);
- request_docs->set_tooltip(TTR("Help improve the Godot documentation by giving feedback"));
+ request_docs->set_tooltip(TTR("Help improve the Godot documentation by giving feedback."));
help_search = memnew(ToolButton);
help_search->set_text(TTR("Search Help"));
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 0a59fc69e3..f741040fa8 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -205,10 +205,10 @@ void TextureRegionEditor::_region_draw() {
margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT);
}
Vector2 pos[4] = {
- mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y),
- -mtx.basis_xform(Vector2(0, margins[1])) + Vector2(0, endpoints[2].y - draw_ofs.y),
- mtx.basis_xform(Vector2(margins[2], 0)) + Vector2(endpoints[0].x - draw_ofs.x, 0),
- -mtx.basis_xform(Vector2(margins[3], 0)) + Vector2(endpoints[2].x - draw_ofs.x, 0)
+ mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y * draw_zoom),
+ -mtx.basis_xform(Vector2(0, margins[1])) + Vector2(0, endpoints[2].y - draw_ofs.y * draw_zoom),
+ mtx.basis_xform(Vector2(margins[2], 0)) + Vector2(endpoints[0].x - draw_ofs.x * draw_zoom, 0),
+ -mtx.basis_xform(Vector2(margins[3], 0)) + Vector2(endpoints[2].x - draw_ofs.x * draw_zoom, 0)
};
draw_margin_line(edit_draw, pos[0], pos[0] + Vector2(edit_draw->get_size().x, 0));
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 8a18af7ae8..33e4bb2336 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -481,10 +481,10 @@ void TileMapEditor::_update_palette() {
if (sel_tile != TileMap::INVALID_CELL) {
if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE) {
- const Map<Vector2, uint16_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile);
+ const Map<Vector2, uint32_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile);
Vector<Vector2> entries2;
- for (const Map<Vector2, uint16_t>::Element *E = tiles2.front(); E; E = E->next()) {
+ for (const Map<Vector2, uint32_t>::Element *E = tiles2.front(); E; E = E->next()) {
entries2.push_back(E->key());
}
entries2.sort();
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 8fc080c819..5bc1067718 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -734,7 +734,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
tools[SHAPE_KEEP_INSIDE_TILE]->hide();
tools[TOOL_SELECT]->set_pressed(true);
- tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nClick on another Tile to edit it."));
+ tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nShift+LMB: Set wildcard bit.\nClick on another Tile to edit it."));
spin_priority->hide();
} break;
case EDITMODE_Z_INDEX:
@@ -818,52 +818,92 @@ void TileSetEditor::_on_workspace_draw() {
} break;
case EDITMODE_BITMASK: {
Color c(1, 0, 0, 0.5);
+ Color ci(0.3, 0.6, 1, 0.5);
for (float x = 0; x < region.size.x / (spacing + size.x); x++) {
for (float y = 0; y < region.size.y / (spacing + size.y); y++) {
Vector2 coord(x, y);
Point2 anchor(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
anchor += WORKSPACE_MARGIN;
anchor += region.position;
- uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
- if (mask & TileSet::BIND_TOPLEFT) {
+ if (mask & TileSet::BIND_IGNORE_TOPLEFT) {
+ workspace->draw_rect(Rect2(anchor, size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + size / 4, size / 4), ci);
+ } else if (mask & TileSet::BIND_TOPLEFT) {
workspace->draw_rect(Rect2(anchor, size / 2), c);
}
- if (mask & TileSet::BIND_TOPRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_TOPRIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 3 / 4, size.y / 4), size / 4), ci);
+ } else if (mask & TileSet::BIND_TOPRIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 2), c);
}
- if (mask & TileSet::BIND_BOTTOMLEFT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 4, size.y * 3 / 4), size / 4), ci);
+ } else if (mask & TileSet::BIND_BOTTOMLEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 2), c);
}
- if (mask & TileSet::BIND_BOTTOMRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) {
+ workspace->draw_rect(Rect2(anchor + size / 2, size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + size * 3 / 4, size / 4), ci);
+ } else if (mask & TileSet::BIND_BOTTOMRIGHT) {
workspace->draw_rect(Rect2(anchor + size / 2, size / 2), c);
}
} else {
- if (mask & TileSet::BIND_TOPLEFT) {
+ if (mask & TileSet::BIND_IGNORE_TOPLEFT) {
+ workspace->draw_rect(Rect2(anchor, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size / 6, size / 6), ci);
+ } else if (mask & TileSet::BIND_TOPLEFT) {
workspace->draw_rect(Rect2(anchor, size / 3), c);
}
- if (mask & TileSet::BIND_TOP) {
+ if (mask & TileSet::BIND_IGNORE_TOP) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_TOP) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 3), c);
}
- if (mask & TileSet::BIND_TOPRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_TOPRIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, 0), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_TOPRIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, 0), size / 3), c);
}
- if (mask & TileSet::BIND_LEFT) {
+ if (mask & TileSet::BIND_IGNORE_LEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y / 2), size / 6), ci);
+ } else if (mask & TileSet::BIND_LEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_CENTER) {
+ if (mask & TileSet::BIND_IGNORE_CENTER) {
+ workspace->draw_rect(Rect2(anchor + size / 3, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size / 2, size / 6), ci);
+ } else if (mask & TileSet::BIND_CENTER) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_RIGHT) {
+ if (mask & TileSet::BIND_IGNORE_RIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, size.y / 3), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 2), size / 6), ci);
+ } else if (mask & TileSet::BIND_RIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOMLEFT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y * 4 / 6), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y * 5 / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOMLEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, (size.y / 3) * 2), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOM) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOM) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y * 4 / 6), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y * 5 / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOM) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, (size.y / 3) * 2), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOMRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) {
+ workspace->draw_rect(Rect2(anchor + size * 4 / 6, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size * 5 / 6, size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOMRIGHT) {
workspace->draw_rect(Rect2(anchor + (size / 3) * 2, size / 3), c);
}
}
@@ -882,10 +922,10 @@ void TileSetEditor::_on_workspace_draw() {
} break;
case EDITMODE_PRIORITY: {
spin_priority->set_value(tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord));
- uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord);
+ uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord);
Vector<Vector2> queue_others;
int total = 0;
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
if (E->value() == mask) {
total += tileset->autotile_get_subtile_priority(get_current_tile(), E->key());
if (E->key() != edited_shape_coord) {
@@ -1037,6 +1077,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
static bool dragging;
static bool erasing;
+ static bool alternative;
draw_edited_region = false;
Rect2 current_tile_region = Rect2();
@@ -1220,10 +1261,11 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
dragging = true;
erasing = (mb->get_button_index() == BUTTON_RIGHT);
+ alternative = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
pos = mb->get_position() - (pos + current_tile_region.position);
- uint16_t bit = 0;
+ uint32_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
if (pos.y < size.y / 2) {
@@ -1266,13 +1308,19 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
- uint16_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- uint16_t new_mask = old_mask;
- if (erasing) {
+ uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t new_mask = old_mask;
+ if (alternative) {
new_mask &= ~bit;
+ new_mask |= (bit << 16);
+ } else if (erasing) {
+ new_mask &= ~bit;
+ new_mask &= ~(bit << 16);
} else {
new_mask |= bit;
+ new_mask &= ~(bit << 16);
}
+
if (old_mask != new_mask) {
undo_redo->create_action(TTR("Edit Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, new_mask);
@@ -1286,6 +1334,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) {
dragging = false;
erasing = false;
+ alternative = false;
}
}
}
@@ -1294,7 +1343,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
Vector2 coord((int)((mm->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mm->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
pos = mm->get_position() - (pos + current_tile_region.position);
- uint16_t bit = 0;
+ uint32_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
if (pos.y < size.y / 2) {
@@ -1337,12 +1386,17 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
- uint16_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- uint16_t new_mask = old_mask;
- if (erasing) {
+ uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t new_mask = old_mask;
+ if (alternative) {
new_mask &= ~bit;
+ new_mask |= (bit << 16);
+ } else if (erasing) {
+ new_mask &= ~bit;
+ new_mask &= ~(bit << 16);
} else {
new_mask |= bit;
+ new_mask &= ~(bit << 16);
}
if (old_mask != new_mask) {
undo_redo->create_action(TTR("Edit Tile Bitmask"));
@@ -1529,10 +1583,10 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
undo_redo->create_action(TTR("Paste Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
undo_redo->add_undo_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- for (Map<Vector2, uint16_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) {
undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
undo_redo->add_do_method(workspace, "update");
@@ -1541,7 +1595,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
} else if (p_tool == BITMASK_CLEAR) {
undo_redo->create_action(TTR("Clear Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
undo_redo->add_do_method(workspace, "update");
@@ -2139,8 +2193,8 @@ void TileSetEditor::_undo_tile_removal(int p_id) {
for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = navigation_map.front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", p_id, E->value(), E->key());
}
- Map<Vector2, uint16_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id);
- for (Map<Vector2, uint16_t>::Element *E = bitmask_map.front(); E; E = E->next()) {
+ Map<Vector2, uint32_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id);
+ for (Map<Vector2, uint32_t>::Element *E = bitmask_map.front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", p_id, E->key(), E->value());
}
Map<Vector2, int> priority_map = tileset->autotile_get_priority_map(p_id);
@@ -2417,11 +2471,11 @@ void TileSetEditor::draw_polygon_shapes() {
colors.push_back(c_bg);
}
}
- if (polygon.size() == 0)
+
+ if (polygon.size() < 3)
continue;
- if (polygon.size() > 2) {
- workspace->draw_polygon(polygon, colors);
- }
+
+ workspace->draw_polygon(polygon, colors);
if (coord == edited_shape_coord || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
if (!creating_shape) {
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 2827964592..1176e1bb92 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -126,7 +126,7 @@ class TileSetEditor : public HSplitContainer {
Vector2 edited_shape_coord;
PoolVector2Array current_shape;
Map<Vector2i, SubtileData> current_tile_data;
- Map<Vector2, uint16_t> bitmask_map_copy;
+ Map<Vector2, uint32_t> bitmask_map_copy;
Vector2 snap_step;
Vector2 snap_offset;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 7bd26de092..f71ff84bbe 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -39,6 +39,7 @@
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
+#include "scene/resources/visual_shader_nodes.h"
Control *VisualShaderNodePlugin::create_editor(const Ref<VisualShaderNode> &p_node) {
@@ -107,16 +108,174 @@ void VisualShaderEditor::remove_custom_type(const Ref<Script> &p_script) {
_update_options_menu();
}
+bool VisualShaderEditor::_is_available(int p_mode) {
+
+ int current_mode = edit_type->get_selected();
+
+ if (p_mode != -1) {
+
+ switch (current_mode) {
+ case VisualShader::TYPE_VERTEX:
+ current_mode = 1;
+ break;
+ case VisualShader::TYPE_FRAGMENT:
+ current_mode = 2;
+ break;
+ case VisualShader::TYPE_LIGHT:
+ current_mode = 4;
+ break;
+ default:
+ break;
+ }
+
+ int temp_mode = 0;
+
+ if (p_mode & VisualShader::TYPE_FRAGMENT) {
+ temp_mode |= 2;
+ }
+
+ if (p_mode & VisualShader::TYPE_LIGHT) {
+ temp_mode |= 4;
+ }
+
+ if (temp_mode == 0) {
+ temp_mode |= 1;
+ }
+
+ p_mode = temp_mode;
+ }
+
+ if (p_mode != -1 && ((p_mode & current_mode) == 0)) {
+ return false;
+ }
+ return true;
+}
+
void VisualShaderEditor::_update_options_menu() {
+ node_desc->set_text("");
+ members_dialog->get_ok()->set_disabled(true);
+
String prev_category;
- add_node->get_popup()->clear();
- for (int i = 0; i < add_options.size(); i++) {
- if (prev_category != add_options[i].category) {
- add_node->get_popup()->add_separator(add_options[i].category);
+ String prev_sub_category;
+
+ members->clear();
+ TreeItem *root = members->create_item();
+ TreeItem *category = NULL;
+ TreeItem *sub_category = NULL;
+
+ String filter = node_filter->get_text().strip_edges();
+ bool use_filter = !filter.empty();
+
+ Vector<String> categories;
+ Vector<String> sub_categories;
+
+ int item_count = 0;
+ int item_count2 = 0;
+
+ for (int i = 0; i < add_options.size() + 1; i++) {
+
+ if (i == add_options.size()) {
+ if (sub_category != NULL && item_count2 == 0) {
+ memdelete(sub_category);
+ --item_count;
+ }
+ if (category != NULL && item_count == 0) {
+ memdelete(category);
+ }
+ break;
+ }
+
+ if (!use_filter || add_options[i].name.findn(filter) != -1) {
+
+ if (prev_category != add_options[i].category) {
+ if (category != NULL && item_count == 0) {
+ memdelete(category);
+ }
+
+ item_count = 0;
+ prev_sub_category = "";
+ category = members->create_item(root);
+ category->set_text(0, add_options[i].category);
+ if (!use_filter)
+ category->set_collapsed(true);
+ }
+
+ if (add_options[i].sub_category != "") {
+ if (prev_sub_category != add_options[i].sub_category) {
+ if (category != NULL) {
+ if (sub_category != NULL && item_count2 == 0) {
+ memdelete(sub_category);
+ --item_count;
+ }
+ ++item_count;
+ item_count2 = 0;
+ sub_category = members->create_item(category);
+ sub_category->set_text(0, add_options[i].sub_category);
+ if (!use_filter)
+ sub_category->set_collapsed(true);
+ }
+ }
+ if (sub_category != NULL) {
+ if (_is_available(add_options[i].mode)) {
+ ++item_count2;
+ TreeItem *item = members->create_item(sub_category);
+ item->set_text(0, add_options[i].name);
+ switch (add_options[i].return_type) {
+ case VisualShaderNode::PORT_TYPE_SCALAR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_BOOLEAN:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_TRANSFORM:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_COLOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Color", "EditorIcons"));
+ break;
+ default:
+ break;
+ }
+ item->set_meta("id", i);
+ }
+ }
+ } else {
+ if (category != NULL) {
+ if (_is_available(add_options[i].mode)) {
+ ++item_count;
+ TreeItem *item = members->create_item(category);
+ item->set_text(0, add_options[i].name);
+ switch (add_options[i].return_type) {
+ case VisualShaderNode::PORT_TYPE_SCALAR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_BOOLEAN:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_TRANSFORM:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_COLOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Color", "EditorIcons"));
+ break;
+ default:
+ break;
+ }
+ item->set_meta("id", i);
+ }
+ }
+ }
+
+ prev_sub_category = add_options[i].sub_category;
+ prev_category = add_options[i].category;
}
- add_node->get_popup()->add_item(add_options[i].name, i);
- prev_category = add_options[i].category;
}
}
@@ -165,10 +324,11 @@ void VisualShaderEditor::_update_graph() {
}
}
- static const Color type_color[3] = {
- Color::html("#61daf4"),
- Color::html("#d67dee"),
- Color::html("#f6a86e")
+ static const Color type_color[4] = {
+ Color::html("#61daf4"), // scalar
+ Color::html("#d67dee"), // vector
+ Color::html("#8da6f0"), // boolean
+ Color::html("#f6a86e") // transform
};
List<VisualShader::Connection> connections;
@@ -344,7 +504,7 @@ void VisualShaderEditor::_update_graph() {
if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode");
- Color c = sb->get_border_color(MARGIN_TOP);
+ Color c = sb->get_border_color();
Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
mono_color.a = 0.85;
c = mono_color;
@@ -462,7 +622,7 @@ void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node,
editing_port = p_port;
}
-void VisualShaderEditor::_add_node(int p_idx) {
+void VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
ERR_FAIL_INDEX(p_idx, add_options.size());
@@ -471,6 +631,70 @@ void VisualShaderEditor::_add_node(int p_idx) {
if (add_options[p_idx].type != String()) {
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type));
ERR_FAIL_COND(!vsn);
+
+ if (p_op_idx != -1) {
+
+ VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsn);
+
+ if (input) {
+ input->set_input_name(add_options[p_idx].sub_func_str);
+ }
+
+ VisualShaderNodeColorOp *colorOp = Object::cast_to<VisualShaderNodeColorOp>(vsn);
+
+ if (colorOp) {
+ colorOp->set_operator((VisualShaderNodeColorOp::Operator)p_op_idx);
+ }
+
+ VisualShaderNodeColorFunc *colorFunc = Object::cast_to<VisualShaderNodeColorFunc>(vsn);
+
+ if (colorFunc) {
+ colorFunc->set_function((VisualShaderNodeColorFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeScalarOp *scalarOp = Object::cast_to<VisualShaderNodeScalarOp>(vsn);
+
+ if (scalarOp) {
+ scalarOp->set_operator((VisualShaderNodeScalarOp::Operator)p_op_idx);
+ }
+
+ VisualShaderNodeScalarFunc *scalarFunc = Object::cast_to<VisualShaderNodeScalarFunc>(vsn);
+
+ if (scalarFunc) {
+ scalarFunc->set_function((VisualShaderNodeScalarFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeVectorOp *vecOp = Object::cast_to<VisualShaderNodeVectorOp>(vsn);
+
+ if (vecOp) {
+ vecOp->set_operator((VisualShaderNodeVectorOp::Operator)p_op_idx);
+ }
+
+ VisualShaderNodeVectorFunc *vecFunc = Object::cast_to<VisualShaderNodeVectorFunc>(vsn);
+
+ if (vecFunc) {
+ vecFunc->set_function((VisualShaderNodeVectorFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeTransformFunc *matFunc = Object::cast_to<VisualShaderNodeTransformFunc>(vsn);
+
+ if (matFunc) {
+ matFunc->set_function((VisualShaderNodeTransformFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeScalarDerivativeFunc *sderFunc = Object::cast_to<VisualShaderNodeScalarDerivativeFunc>(vsn);
+
+ if (sderFunc) {
+ sderFunc->set_function((VisualShaderNodeScalarDerivativeFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeVectorDerivativeFunc *vderFunc = Object::cast_to<VisualShaderNodeVectorDerivativeFunc>(vsn);
+
+ if (vderFunc) {
+ vderFunc->set_function((VisualShaderNodeVectorDerivativeFunc::Function)p_op_idx);
+ }
+ }
+
vsnode = Ref<VisualShaderNode>(vsn);
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
@@ -481,7 +705,15 @@ void VisualShaderEditor::_add_node(int p_idx) {
vsnode->set_script(add_options[p_idx].script.get_ref_ptr());
}
- Point2 position = (graph->get_scroll_ofs() + graph->get_size() * 0.5) / EDSCALE;
+ Point2 position = graph->get_scroll_ofs();
+
+ if (saved_node_pos_dirty) {
+ position += saved_node_pos;
+ } else {
+ position += graph->get_size() * 0.5;
+ position /= EDSCALE;
+ }
+ saved_node_pos_dirty = false;
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
@@ -600,29 +832,82 @@ void VisualShaderEditor::_node_selected(Object *p_node) {
//EditorNode::get_singleton()->push_item(vsnode.ptr(), "", true);
}
+void VisualShaderEditor::_member_gui_input(const Ref<InputEvent> p_event) {
+ Ref<InputEventMouseButton> mb = p_event;
+ Ref<InputEventKey> key = p_event;
+
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mb->is_doubleclick()) {
+ _member_create();
+ }
+ } else if (key.is_valid()) {
+ if (key->is_pressed() && key->get_scancode() == KEY_ENTER) {
+ _member_create();
+ }
+ }
+}
+
void VisualShaderEditor::_input(const Ref<InputEvent> p_event) {
if (graph->has_focus()) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
- add_node->get_popup()->set_position(get_viewport()->get_mouse_position());
- add_node->get_popup()->show_modal();
+ saved_node_pos_dirty = true;
+ saved_node_pos = graph->get_local_mouse_position();
+
+ Point2 gpos = Input::get_singleton()->get_mouse_position();
+ members_dialog->popup();
+ members_dialog->set_position(gpos);
}
}
}
+void VisualShaderEditor::_show_members_dialog() {
+ saved_node_pos_dirty = false;
+ members_dialog->popup();
+ members_dialog->set_position(graph->get_global_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
+}
+
void VisualShaderEditor::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ node_filter->set_clear_button_enabled(true);
+
+ // collapse tree by default
+
+ TreeItem *category = members->get_root()->get_children();
+ while (category) {
+ category->set_collapsed(true);
+ TreeItem *sub_category = category->get_children();
+ while (sub_category) {
+ sub_category->set_collapsed(true);
+ sub_category = sub_category->get_next();
+ }
+ category = category->get_next();
+ }
+ }
+
+ if (p_what == NOTIFICATION_DRAG_BEGIN) {
+ Dictionary dd = get_viewport()->gui_get_drag_data();
+ if (members->is_visible_in_tree() && dd.has("id")) {
+ members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
+ }
+ } else if (p_what == NOTIFICATION_DRAG_END) {
+ members->set_drop_mode_flags(0);
+ }
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
error_label->add_color_override("font_color", get_color("error_color", "Editor"));
+ node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons"));
+
+ tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Tools", "EditorIcons"));
+
if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree())
_update_graph();
- }
-
- if (p_what == NOTIFICATION_PROCESS) {
+ } else if (p_what == NOTIFICATION_PROCESS) {
}
}
@@ -719,6 +1004,7 @@ void VisualShaderEditor::_duplicate_nodes() {
}
void VisualShaderEditor::_mode_selected(int p_id) {
+ _update_options_menu();
_update_graph();
}
@@ -756,6 +1042,128 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> input, St
undo_redo->commit_action();
}
+void VisualShaderEditor::_member_filter_changed(const String &p_text) {
+ _update_options_menu();
+}
+
+void VisualShaderEditor::_member_selected() {
+ TreeItem *item = members->get_selected();
+
+ if (item != NULL && item->has_meta("id")) {
+ members_dialog->get_ok()->set_disabled(false);
+ node_desc->set_text(add_options[item->get_meta("id")].description);
+ } else {
+ members_dialog->get_ok()->set_disabled(true);
+ node_desc->set_text("");
+ }
+}
+
+void VisualShaderEditor::_member_unselected() {
+}
+
+void VisualShaderEditor::_member_create() {
+ TreeItem *item = members->get_selected();
+ if (item != NULL && item->has_meta("id")) {
+ int idx = members->get_selected()->get_meta("id");
+ _add_node(idx, add_options[idx].sub_func);
+ members_dialog->hide();
+ }
+}
+
+void VisualShaderEditor::_tools_menu_option(int p_idx) {
+
+ TreeItem *category = members->get_root()->get_children();
+
+ switch (p_idx) {
+ case EXPAND_ALL:
+
+ while (category) {
+ category->set_collapsed(false);
+ TreeItem *sub_category = category->get_children();
+ while (sub_category) {
+ sub_category->set_collapsed(false);
+ sub_category = sub_category->get_next();
+ }
+ category = category->get_next();
+ }
+
+ break;
+
+ case COLLAPSE_ALL:
+
+ while (category) {
+ category->set_collapsed(true);
+ TreeItem *sub_category = category->get_children();
+ while (sub_category) {
+ sub_category->set_collapsed(true);
+ sub_category = sub_category->get_next();
+ }
+ category = category->get_next();
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+
+ if (p_from == members) {
+ TreeItem *it = members->get_item_at_position(p_point);
+ if (!it)
+ return Variant();
+ if (!it->has_meta("id"))
+ return Variant();
+
+ int id = it->get_meta("id");
+ AddOption op = add_options[id];
+
+ Dictionary d;
+ d["id"] = id;
+ if (op.sub_func == -1) {
+ d["sub_func"] = op.sub_func_str;
+ } else {
+ d["sub_func"] = op.sub_func;
+ }
+
+ Label *label = memnew(Label);
+ label->set_text(it->get_text(0));
+ set_drag_preview(label);
+ return d;
+ }
+ return Variant();
+}
+
+bool VisualShaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+
+ if (p_from == graph) {
+
+ Dictionary d = p_data;
+
+ if (d.has("id")) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+
+ if (p_from == graph) {
+
+ Dictionary d = p_data;
+
+ if (d.has("id")) {
+ int idx = d["id"];
+ saved_node_pos = p_point;
+ saved_node_pos_dirty = true;
+ _add_node(idx, add_options[idx].sub_func);
+ }
+ }
+}
+
void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);
@@ -777,6 +1185,19 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
ClassDB::bind_method("_preview_select_port", &VisualShaderEditor::_preview_select_port);
ClassDB::bind_method("_input", &VisualShaderEditor::_input);
+
+ ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("drop_data_fw"), &VisualShaderEditor::drop_data_fw);
+
+ ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
+ ClassDB::bind_method("_tools_menu_option", &VisualShaderEditor::_tools_menu_option);
+ ClassDB::bind_method("_show_members_dialog", &VisualShaderEditor::_show_members_dialog);
+ ClassDB::bind_method("_member_gui_input", &VisualShaderEditor::_member_gui_input);
+ ClassDB::bind_method("_member_filter_changed", &VisualShaderEditor::_member_filter_changed);
+ ClassDB::bind_method("_member_selected", &VisualShaderEditor::_member_selected);
+ ClassDB::bind_method("_member_unselected", &VisualShaderEditor::_member_unselected);
+ ClassDB::bind_method("_member_create", &VisualShaderEditor::_member_create);
}
VisualShaderEditor *VisualShaderEditor::singleton = NULL;
@@ -785,10 +1206,14 @@ VisualShaderEditor::VisualShaderEditor() {
singleton = this;
updating = false;
+ saved_node_pos_dirty = false;
+ saved_node_pos = Point2(0, 0);
graph = memnew(GraphEdit);
add_child(graph);
+ graph->set_drag_forwarding(this);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);
+ graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_TRANSFORM);
//graph->add_valid_left_disconnect_type(0);
@@ -800,8 +1225,13 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect("duplicate_nodes_request", this, "_duplicate_nodes");
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_BOOLEAN);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM);
VSeparator *vs = memnew(VSeparator);
@@ -817,40 +1247,315 @@ VisualShaderEditor::VisualShaderEditor() {
graph->get_zoom_hbox()->add_child(edit_type);
graph->get_zoom_hbox()->move_child(edit_type, 0);
- add_node = memnew(MenuButton);
+ add_node = memnew(ToolButton);
graph->get_zoom_hbox()->add_child(add_node);
add_node->set_text(TTR("Add Node..."));
graph->get_zoom_hbox()->move_child(add_node, 0);
- add_node->get_popup()->connect("id_pressed", this, "_add_node");
-
- add_options.push_back(AddOption("Scalar", "Constants", "VisualShaderNodeScalarConstant"));
- add_options.push_back(AddOption("Vector", "Constants", "VisualShaderNodeVec3Constant"));
- add_options.push_back(AddOption("Color", "Constants", "VisualShaderNodeColorConstant"));
- add_options.push_back(AddOption("Transform", "Constants", "VisualShaderNodeTransformConstant"));
- add_options.push_back(AddOption("Texture", "Constants", "VisualShaderNodeTexture"));
- add_options.push_back(AddOption("CubeMap", "Constants", "VisualShaderNodeCubeMap"));
- add_options.push_back(AddOption("ScalarOp", "Operators", "VisualShaderNodeScalarOp"));
- add_options.push_back(AddOption("VectorOp", "Operators", "VisualShaderNodeVectorOp"));
- add_options.push_back(AddOption("ColorOp", "Operators", "VisualShaderNodeColorOp"));
- add_options.push_back(AddOption("TransformMult", "Operators", "VisualShaderNodeTransformMult"));
- add_options.push_back(AddOption("TransformVectorMult", "Operators", "VisualShaderNodeTransformVecMult"));
- add_options.push_back(AddOption("ScalarFunc", "Functions", "VisualShaderNodeScalarFunc"));
- add_options.push_back(AddOption("VectorFunc", "Functions", "VisualShaderNodeVectorFunc"));
- add_options.push_back(AddOption("DotProduct", "Functions", "VisualShaderNodeDotProduct"));
- add_options.push_back(AddOption("VectorLen", "Functions", "VisualShaderNodeVectorLen"));
- add_options.push_back(AddOption("ScalarInterp", "Interpolation", "VisualShaderNodeScalarInterp"));
- add_options.push_back(AddOption("VectorInterp", "Interpolation", "VisualShaderNodeVectorInterp"));
- add_options.push_back(AddOption("VectorCompose", "Compose", "VisualShaderNodeVectorCompose"));
- add_options.push_back(AddOption("TransformCompose", "Compose", "VisualShaderNodeTransformCompose"));
- add_options.push_back(AddOption("VectorDecompose", "Decompose", "VisualShaderNodeVectorDecompose"));
- add_options.push_back(AddOption("TransformDecompose", "Decompose", "VisualShaderNodeTransformDecompose"));
- add_options.push_back(AddOption("Scalar", "Uniforms", "VisualShaderNodeScalarUniform"));
- add_options.push_back(AddOption("Vector", "Uniforms", "VisualShaderNodeVec3Uniform"));
- add_options.push_back(AddOption("Color", "Uniforms", "VisualShaderNodeColorUniform"));
- add_options.push_back(AddOption("Transform", "Uniforms", "VisualShaderNodeTransformUniform"));
- add_options.push_back(AddOption("Texture", "Uniforms", "VisualShaderNodeTextureUniform"));
- add_options.push_back(AddOption("CubeMap", "Uniforms", "VisualShaderNodeCubeMapUniform"));
- add_options.push_back(AddOption("Input", "Inputs", "VisualShaderNodeInput"));
+ add_node->connect("pressed", this, "_show_members_dialog");
+
+ ///////////////////////////////////////
+ // SHADER NODES TREE
+ ///////////////////////////////////////
+
+ VBoxContainer *members_vb = memnew(VBoxContainer);
+ members_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ HBoxContainer *filter_hb = memnew(HBoxContainer);
+ members_vb->add_child(filter_hb);
+
+ node_filter = memnew(LineEdit);
+ filter_hb->add_child(node_filter);
+ node_filter->connect("text_changed", this, "_member_filter_changed");
+ node_filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ node_filter->set_placeholder(TTR("Search"));
+
+ tools = memnew(MenuButton);
+ filter_hb->add_child(tools);
+ tools->set_tooltip(TTR("Options"));
+ tools->get_popup()->connect("id_pressed", this, "_tools_menu_option");
+ tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL);
+ tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL);
+
+ members = memnew(Tree);
+ members_vb->add_child(members);
+ members->set_drag_forwarding(this);
+ members->set_h_size_flags(SIZE_EXPAND_FILL);
+ members->set_v_size_flags(SIZE_EXPAND_FILL);
+ members->set_hide_root(true);
+ members->set_allow_reselect(true);
+ members->set_hide_folding(false);
+ members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));
+ members->connect("item_selected", this, "_member_selected");
+ members->connect("nothing_selected", this, "_member_unselected");
+ members->connect("gui_input", this, "_member_gui_input");
+
+ Label *desc_label = memnew(Label);
+ members_vb->add_child(desc_label);
+ desc_label->set_text(TTR("Description:"));
+
+ node_desc = memnew(RichTextLabel);
+ members_vb->add_child(node_desc);
+ node_desc->set_h_size_flags(SIZE_EXPAND_FILL);
+ node_desc->set_v_size_flags(SIZE_FILL);
+ node_desc->set_custom_minimum_size(Size2(0, 70 * EDSCALE));
+
+ members_dialog = memnew(ConfirmationDialog);
+ members_dialog->set_title(TTR("Create Shader Node"));
+ members_dialog->add_child(members_vb);
+ members_dialog->get_ok()->set_text(TTR("Create"));
+ members_dialog->get_ok()->connect("pressed", this, "_member_create");
+ members_dialog->get_ok()->set_disabled(true);
+ members_dialog->set_resizable(true);
+ members_dialog->set_as_minsize();
+ add_child(members_dialog);
+
+ alert = memnew(AcceptDialog);
+ alert->set_as_minsize();
+ alert->get_label()->set_autowrap(true);
+ alert->get_label()->set_align(Label::ALIGN_CENTER);
+ alert->get_label()->set_valign(Label::VALIGN_CENTER);
+ alert->get_label()->set_custom_minimum_size(Size2(400, 60) * EDSCALE);
+ add_child(alert);
+
+ ///////////////////////////////////////
+ // SHADER NODES TREE OPTIONS
+ ///////////////////////////////////////
+
+ // COLOR
+
+ add_options.push_back(AddOption("ColorFunc", "Color", "Common", "VisualShaderNodeColorFunc", TTR("Color function."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ColorOp", "Color", "Common", "VisualShaderNodeColorOp", TTR("Color operator."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("Grayscale", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), VisualShaderNodeColorFunc::FUNC_GRAYSCALE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("HSV2RGB", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts HSV vector to RGB equivalent."), VisualShaderNodeVectorFunc::FUNC_HSV2RGB, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("RGB2HSV", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts RGB vector to HSV equivalent."), VisualShaderNodeVectorFunc::FUNC_RGB2HSV, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Sepia", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), VisualShaderNodeColorFunc::FUNC_SEPIA, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("Burn", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), VisualShaderNodeColorOp::OP_BURN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Darken", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), VisualShaderNodeColorOp::OP_DARKEN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Difference", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Difference operator."), VisualShaderNodeColorOp::OP_DIFFERENCE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Dodge", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Dodge operator."), VisualShaderNodeColorOp::OP_DODGE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("HardLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("HardLight operator"), VisualShaderNodeColorOp::OP_HARD_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Lighten", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Lighten operator."), VisualShaderNodeColorOp::OP_LIGHTEN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Overlay", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Overlay operator."), VisualShaderNodeColorOp::OP_OVERLAY, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Screen", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), VisualShaderNodeColorOp::OP_SCREEN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SoftLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), VisualShaderNodeColorOp::OP_SOFT_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+ add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+
+ // BOOLEAN
+
+ add_options.push_back(AddOption("BooleanConstant", "Boolean", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("BooleanUniform", "Boolean", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN));
+
+ // INPUT
+
+ add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", TTR("'camera' input parameter for all shader modes."), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", TTR("'inv_camera' input parameter for all shader modes."), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", TTR("'inv_projection' input parameter for all shader modes."), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Normal", "Input", "All", "VisualShaderNodeInput", TTR("'normal' input parameter for all shader modes."), "normal", VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", TTR("'projection' input parameter for all shader modes."), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", TTR("'time' input parameter for all shader modes."), "time", VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", TTR("'viewport_size' input parameter for all shader modes."), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", TTR("'world' input parameter for all shader modes."), "world", VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ add_options.push_back(AddOption("Input", "Input", "Common", "VisualShaderNodeInput", TTR("Input parameter.")));
+
+ add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", TTR("'alpha' input parameter for fragment shader mode."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", TTR("'binormal' input parameter for fragment shader mode."), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", TTR("'color' input parameter for fragment shader mode."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for fragment shader mode."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'point_coord' input parameter for fragment shader mode."), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'screen_uv' input parameter for fragment shader mode."), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", TTR("'side' input parameter for fragment shader mode."), "side", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", TTR("'tangent' input parameter for fragment shader mode."), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'uv' input parameter for fragment shader mode."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", TTR("'uv2' input parameter for fragment shader mode."), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", TTR("'vertex' input parameter for fragment shader mode."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", TTR("'view' input parameter for fragment shader mode."), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+
+ add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", TTR("'albedo' input parameter for light shader mode."), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", TTR("'attenuation' input parameter for light shader mode."), "attenuation", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", TTR("'diffuse' input parameter for light shader mode."), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for light shader mode."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", TTR("'light' input parameter for light shader mode."), "light", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", TTR("'light_color' input parameter for light shader mode."), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", TTR("'roughness' input parameter for light shader mode."), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", TTR("'specular' input parameter for light shader mode."), "specular", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", TTR("'transmission' input parameter for light shader mode."), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", TTR("'view' input parameter for light shader mode."), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+
+ add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", TTR("'alpha' input parameter for vertex shader mode."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", TTR("'binormal' input parameter for vertex shader mode."), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", TTR("'color' input parameter for vertex shader mode."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", TTR("'modelview' input parameter for vertex shader mode."), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", TTR("'point_size' input parameter for vertex shader mode."), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", TTR("'tangent' input parameter for vertex shader mode."), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", TTR("'uv' input parameter for vertex shader mode."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", TTR("'uv2' input parameter for vertex shader mode."), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", TTR("'vertex' input parameter for vertex shader mode."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+
+ // SCALAR
+
+ add_options.push_back(AddOption("ScalarFunc", "Scalar", "Common", "VisualShaderNodeScalarFunc", TTR("Scalar function."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ScalarOp", "Scalar", "Common", "VisualShaderNodeScalarOp", TTR("Scalar operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeScalarFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ACos", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ACosH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ASin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ASIN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ASinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the inverse hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ASINH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_ATAN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATan2", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeScalarOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Ceil", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeScalarFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeScalarClamp", TTR("Constrains a value to lie between two further values."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Cos", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("CosH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the hyperbolic cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Degrees", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeScalarFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Exp", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-e Exponential."), VisualShaderNodeScalarFunc::FUNC_EXP, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Exp2", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-2 Exponential."), VisualShaderNodeScalarFunc::FUNC_EXP2, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Floor", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the nearest integer less than or equal to the parameter."), VisualShaderNodeScalarFunc::FUNC_FLOOR, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Fract", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Computes the fractional part of the argument."), VisualShaderNodeScalarFunc::FUNC_FRAC, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("InverseSqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the inverse of the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_INVERSE_SQRT, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Natural logarithm."), VisualShaderNodeScalarFunc::FUNC_LOG, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log2", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-2 logarithm."), VisualShaderNodeScalarFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Max", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the greater of two values."), VisualShaderNodeScalarOp::OP_MAX, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the lesser of two values."), VisualShaderNodeScalarOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeScalarInterp", TTR("Linear interpolation between two scalars."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeScalarFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Pow", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeScalarOp::OP_POW, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Radians", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeScalarFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Reciprocal", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("1.0 / scalar"), VisualShaderNodeScalarFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Round", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Finds the nearest integer to the parameter."), VisualShaderNodeScalarFunc::FUNC_ROUND, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("RoundEven", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Finds the nearest even integer to the parameter."), VisualShaderNodeScalarFunc::FUNC_ROUNDEVEN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Saturate", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Clamps the value between 0.0 and 1.0."), VisualShaderNodeScalarFunc::FUNC_SATURATE, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Finds the truncated value of the parameter."), VisualShaderNodeScalarFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Adds scalar to scalar."), VisualShaderNodeScalarOp::OP_ADD, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Divides scalar by scalar."), VisualShaderNodeScalarOp::OP_DIV, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Multiplies scalar by scalar."), VisualShaderNodeScalarOp::OP_MUL, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Returns the remainder of the two scalars."), VisualShaderNodeScalarOp::OP_MOD, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Subtracts scalar from scalar."), VisualShaderNodeScalarOp::OP_SUB, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ add_options.push_back(AddOption("ScalarConstant", "Scalar", "Variables", "VisualShaderNodeScalarConstant", TTR("Scalar constant."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ScalarUniform", "Scalar", "Variables", "VisualShaderNodeScalarUniform", TTR("Scalar uniform."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ // TEXTURES
+
+ add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+ add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+
+ add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+ add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+
+ // TRANSFORM
+
+ add_options.push_back(AddOption("TransformFunc", "Transform", "Common", "VisualShaderNodeTransformFunc", TTR("Transform function."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ add_options.push_back(AddOption("OuterProduct", "Transform", "Composition", "VisualShaderNodeOuterProduct", TTR("(GLES3 only) Calculate the outer product of a pair of vectors.\n\nOuterProduct treats the first parameter 'c' as a column vector (matrix with one column) and the second parameter 'r' as a row vector (matrix with one row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix whose number of rows is the number of components in 'c' and whose number of columns is the number of components in 'r'."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformCompose", "Transform", "Composition", "VisualShaderNodeTransformCompose", TTR("Composes transform from four vectors."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformDecompose", "Transform", "Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors.")));
+
+ add_options.push_back(AddOption("Determinant", "Transform", "Functions", "VisualShaderNodeDeterminant", TTR("(GLES3 only) Calculates the determinant of a transform."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("(GLES3 only) Calculates the inverse of a transform."), VisualShaderNodeTransformFunc::FUNC_INVERSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Transpose", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("(GLES3 only) Calculates the transpose of a transform."), VisualShaderNodeTransformFunc::FUNC_TRANSPOSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ add_options.push_back(AddOption("TransformMult", "Transform", "Operators", "VisualShaderNodeTransformMult", TTR("Multiplies transform by transform."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformVectorMult", "Transform", "Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("TransformConstant", "Transform", "Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformUniform", "Transform", "Variables", "VisualShaderNodeTransformUniform", TTR("Transform uniform."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ // VECTOR
+
+ add_options.push_back(AddOption("VectorFunc", "Vector", "Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("VectorOp", "Vector", "Common", "VisualShaderNodeVectorOp", TTR("Vector operator."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("VectorCompose", "Vector", "Composition", "VisualShaderNodeVectorCompose", TTR("Composes vector from three scalars."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("VectorDecompose", "Vector", "Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes vector to three scalars.")));
+
+ add_options.push_back(AddOption("Abs", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ACos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ACosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ASin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ASinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the inverse hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ATan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ATan2", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ATanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Ceil", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Clamp", "Vector", "Functions", "VisualShaderNodeVectorClamp", TTR("Constrains a value to lie between two further values."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Cos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("CosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the hyperbolic cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Cross", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Calculates the cross product of two vectors."), VisualShaderNodeVectorOp::OP_CROSS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Degrees", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Distance", "Vector", "Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Dot", "Vector", "Functions", "VisualShaderNodeDotProduct", TTR("Calculates the dot product of two vectors."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Exp", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Exp2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("FaceForward", "Vector", "Functions", "VisualShaderNodeFaceForward", TTR("Returns a vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("InverseSqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Length", "Vector", "Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Log2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Max", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), VisualShaderNodeVectorOp::OP_MAX, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), VisualShaderNodeVectorOp::OP_MIN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeVectorInterp", TTR("Linear interpolation between two vectors."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Pow", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeVectorOp::OP_POW, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Radians", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Reflect", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns a vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns a vector that points in the direction of refraction."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Finds the nearest integer to the parameter."), VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("RoundEven", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Finds the nearest even integer to the parameter."), VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Saturate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Sign", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Finds the truncated value of the parameter."), VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("Add", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Adds vector to vector."), VisualShaderNodeVectorOp::OP_ADD, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Divide", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Divides vector by vector."), VisualShaderNodeVectorOp::OP_DIV, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Multiply", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Multiplies vector by vector."), VisualShaderNodeVectorOp::OP_MUL, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Remainder", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two vectors."), VisualShaderNodeVectorOp::OP_MOD, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Subtract", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Subtracts vector from vector."), VisualShaderNodeVectorOp::OP_SUB, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("VectorConstant", "Vector", "Variables", "VisualShaderNodeVec3Constant", TTR("Vector constant."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("VectorUniform", "Vector", "Variables", "VisualShaderNodeVec3Uniform", TTR("Vector uniform."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ // SPECIAL
+
+ add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+
+ add_options.push_back(AddOption("DdX", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("DdXS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("DdY", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("DdYS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Sum", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeVectorDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("SumS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeScalarDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+
+ /////////////////////////////////////////////////////////////////////
_update_options_menu();
@@ -940,9 +1645,10 @@ public:
void setup(const Ref<VisualShaderNodeInput> &p_input) {
input = p_input;
- Ref<Texture> type_icon[3] = {
+ Ref<Texture> type_icon[4] = {
EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"),
};
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 2fb8a85d5b..2709d72931 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -60,7 +60,7 @@ class VisualShaderEditor : public VBoxContainer {
Ref<VisualShader> visual_shader;
GraphEdit *graph;
- MenuButton *add_node;
+ ToolButton *add_node;
OptionButton *edit_type;
@@ -68,18 +68,59 @@ class VisualShaderEditor : public VBoxContainer {
Label *error_label;
UndoRedo *undo_redo;
+ Point2 saved_node_pos;
+ bool saved_node_pos_dirty;
+
+ ConfirmationDialog *members_dialog;
+ MenuButton *tools;
+
+ enum ToolsMenuOptions {
+ EXPAND_ALL,
+ COLLAPSE_ALL
+ };
+
+ Tree *members;
+ AcceptDialog *alert;
+ LineEdit *node_filter;
+ RichTextLabel *node_desc;
+
+ void _tools_menu_option(int p_idx);
+ void _show_members_dialog();
void _update_graph();
struct AddOption {
String name;
String category;
+ String sub_category;
String type;
+ String description;
+ int sub_func;
+ String sub_func_str;
Ref<Script> script;
- AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_type = String()) {
+ int mode;
+ int return_type;
+
+ AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1) {
+ name = p_name;
+ type = p_type;
+ category = p_category;
+ sub_category = p_sub_category;
+ description = p_description;
+ sub_func = p_sub_func;
+ return_type = p_return_type;
+ mode = p_mode;
+ }
+
+ AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1) {
name = p_name;
type = p_type;
category = p_category;
+ sub_category = p_sub_category;
+ description = p_description;
+ sub_func_str = p_sub_func;
+ return_type = p_return_type;
+ mode = p_mode;
}
};
@@ -87,7 +128,7 @@ class VisualShaderEditor : public VBoxContainer {
void _draw_color_over_button(Object *obj, Color p_color);
- void _add_node(int p_idx);
+ void _add_node(int p_idx, int p_op_idx = -1);
void _update_options_menu();
static VisualShaderEditor *singleton;
@@ -126,6 +167,18 @@ class VisualShaderEditor : public VBoxContainer {
void _preview_select_port(int p_node, int p_port);
void _input(const Ref<InputEvent> p_event);
+ void _member_gui_input(const Ref<InputEvent> p_event);
+ void _member_filter_changed(const String &p_text);
+ void _member_selected();
+ void _member_unselected();
+ void _member_create();
+
+ Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+
+ bool _is_available(int p_flags);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index dda46d2414..717d6bc8f6 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -303,12 +303,49 @@ void ScriptEditorDebugger::_scene_tree_rmb_selected(const Vector2 &p_position) {
}
void ScriptEditorDebugger::_file_selected(const String &p_file) {
- if (file_dialog->get_mode() == EditorFileDialog::MODE_SAVE_FILE) {
+ if (file_dialog_mode == SAVE_NODE) {
+
Array msg;
msg.push_back("save_node");
msg.push_back(inspected_object_id);
msg.push_back(p_file);
ppeer->put_var(msg);
+ } else if (file_dialog_mode == SAVE_CSV) {
+
+ Error err;
+ FileAccessRef file = FileAccess::open(p_file, FileAccess::WRITE, &err);
+
+ if (err != OK) {
+ ERR_PRINTS("Failed to open " + p_file);
+ return;
+ }
+ Vector<String> line;
+ line.resize(Performance::MONITOR_MAX);
+
+ // signatures
+ for (int i = 0; i < Performance::MONITOR_MAX; i++) {
+ line.write[i] = Performance::get_singleton()->get_monitor_name(Performance::Monitor(i));
+ }
+ file->store_csv_line(line);
+
+ // values
+ List<Vector<float> >::Element *E = perf_history.back();
+ while (E) {
+
+ Vector<float> &perf_data = E->get();
+ for (int i = 0; i < perf_data.size(); i++) {
+
+ line.write[i] = String::num_real(perf_data[i]);
+ }
+ file->store_csv_line(line);
+ E = E->prev();
+ }
+ file->store_string("\n");
+
+ Vector<Vector<String> > profiler_data = profiler->get_data_as_csv();
+ for (int i = 0; i < profiler_data.size(); i++) {
+ file->store_csv_line(profiler_data[i]);
+ }
}
}
@@ -1374,6 +1411,13 @@ void ScriptEditorDebugger::_output_clear() {
//output->push_color(Color(0,0,0));
}
+void ScriptEditorDebugger::_export_csv() {
+
+ file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog_mode = SAVE_CSV;
+ file_dialog->popup_centered_ratio();
+}
+
String ScriptEditorDebugger::get_var_value(const String &p_var) const {
if (!breaked)
return String();
@@ -1859,6 +1903,7 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
file_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES);
file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog_mode = SAVE_NODE;
List<String> extensions;
Ref<PackedScene> sd = memnew(PackedScene);
@@ -1884,6 +1929,7 @@ void ScriptEditorDebugger::_bind_methods() {
ClassDB::bind_method(D_METHOD("debug_break"), &ScriptEditorDebugger::debug_break);
ClassDB::bind_method(D_METHOD("debug_continue"), &ScriptEditorDebugger::debug_continue);
ClassDB::bind_method(D_METHOD("_output_clear"), &ScriptEditorDebugger::_output_clear);
+ ClassDB::bind_method(D_METHOD("_export_csv"), &ScriptEditorDebugger::_export_csv);
ClassDB::bind_method(D_METHOD("_performance_draw"), &ScriptEditorDebugger::_performance_draw);
ClassDB::bind_method(D_METHOD("_performance_select"), &ScriptEditorDebugger::_performance_select);
ClassDB::bind_method(D_METHOD("_scene_tree_request"), &ScriptEditorDebugger::_scene_tree_request);
@@ -2205,10 +2251,13 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
}
{ // misc
+ VBoxContainer *misc = memnew(VBoxContainer);
+ misc->set_name(TTR("Misc"));
+ tabs->add_child(misc);
+
GridContainer *info_left = memnew(GridContainer);
info_left->set_columns(2);
- info_left->set_name(TTR("Misc"));
- tabs->add_child(info_left);
+ misc->add_child(info_left);
clicked_ctrl = memnew(LineEdit);
clicked_ctrl->set_h_size_flags(SIZE_EXPAND_FILL);
info_left->add_child(memnew(Label(TTR("Clicked Control:"))));
@@ -2233,6 +2282,16 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
le_set->set_disabled(true);
le_clear->set_disabled(true);
}
+
+ misc->add_child(memnew(VSeparator));
+
+ HBoxContainer *buttons = memnew(HBoxContainer);
+
+ export_csv = memnew(Button(TTR("Export measures as CSV")));
+ export_csv->connect("pressed", this, "_export_csv");
+ buttons->add_child(export_csv);
+
+ misc->add_child(buttons);
}
msgdialog = memnew(AcceptDialog);
diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h
index fb1545559c..5f21602579 100644
--- a/editor/script_editor_debugger.h
+++ b/editor/script_editor_debugger.h
@@ -77,6 +77,7 @@ class ScriptEditorDebugger : public Control {
LineEdit *live_edit_root;
Button *le_set;
Button *le_clear;
+ Button *export_csv;
bool updating_scene_tree;
float inspect_scene_tree_timeout;
@@ -92,7 +93,13 @@ class ScriptEditorDebugger : public Control {
Tree *inspect_scene_tree;
Button *clearbutton;
PopupMenu *item_menu;
+
EditorFileDialog *file_dialog;
+ enum FileDialogMode {
+ SAVE_CSV,
+ SAVE_NODE,
+ };
+ FileDialogMode file_dialog_mode;
int error_count;
int warning_count;
@@ -196,6 +203,8 @@ class ScriptEditorDebugger : public Control {
void _error_tree_item_rmb_selected(const Vector2 &p_pos);
void _item_menu_id_pressed(int p_option);
+ void _export_csv();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp
index 3465fd783e..dcbb930d1b 100644
--- a/main/tests/test_string.cpp
+++ b/main/tests/test_string.cpp
@@ -1053,6 +1053,19 @@ bool test_33() {
return empty.parse_utf8(NULL, -1) == true;
}
+bool test_34() {
+ OS::get_singleton()->print("\n\nTest 34: Cyrillic to_lower()\n");
+
+ String upper = L"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
+ String lower = L"абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
+
+ String test = upper.to_lower();
+
+ bool state = test == lower;
+
+ return state;
+}
+
typedef bool (*TestFunc)(void);
TestFunc test_funcs[] = {
@@ -1090,6 +1103,7 @@ TestFunc test_funcs[] = {
test_31,
test_32,
test_33,
+ test_34,
0
};
diff --git a/methods.py b/methods.py
index 5bc30dc643..ec9ecdb17f 100644
--- a/methods.py
+++ b/methods.py
@@ -4,7 +4,6 @@ import sys
import re
import glob
import string
-import datetime
import subprocess
from compat import iteritems, isbasestring, decode_utf8
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp
index 4662cf9d0a..ee66097ffd 100644
--- a/modules/assimp/editor_scene_importer_assimp.cpp
+++ b/modules/assimp/editor_scene_importer_assimp.cpp
@@ -1945,7 +1945,7 @@ void EditorSceneImporterAssimp::_add_mesh_to_mesh_instance(const aiNode *p_node,
morphs[j] = array_copy;
}
- r_name_morph_mesh_names.insert(_ai_raw_string_to_string(p_node->mName), morph_mesh_idx_names);
+ r_name_morph_mesh_names.insert(_ai_string_to_string(p_node->mName), morph_mesh_idx_names);
mesh->add_surface_from_arrays(primitive, array_mesh, morphs);
mesh->surface_set_material(i, mat);
mesh->surface_set_name(i, _ai_string_to_string(ai_mesh->mName));
diff --git a/modules/assimp/register_types.cpp b/modules/assimp/register_types.cpp
index 0afb1e72bf..2e8181372e 100644
--- a/modules/assimp/register_types.cpp
+++ b/modules/assimp/register_types.cpp
@@ -44,7 +44,13 @@ static void _editor_init() {
void register_assimp_types() {
#ifdef TOOLS_ENABLED
+ ClassDB::APIType prev_api = ClassDB::get_current_api();
+ ClassDB::set_current_api(ClassDB::API_EDITOR);
+
ClassDB::register_class<EditorSceneImporterAssimp>();
+
+ ClassDB::set_current_api(prev_api);
+
EditorNode::add_init_callback(_editor_init);
#endif
}
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.cpp b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
index 9cd37ac950..8c602e0cba 100644
--- a/modules/gdnative/arvr/arvr_interface_gdnative.cpp
+++ b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
@@ -198,6 +198,17 @@ CameraMatrix ARVRInterfaceGDNative::get_projection_for_eye(ARVRInterface::Eyes p
return cm;
}
+unsigned int ARVRInterfaceGDNative::get_external_texture_for_eye(ARVRInterface::Eyes p_eye) {
+
+ ERR_FAIL_COND_V(interface == NULL, 0);
+
+ if ((interface->version.major > 1) || ((interface->version.major) == 1 && (interface->version.minor >= 1))) {
+ return (unsigned int)interface->get_external_texture_for_eye(data, (godot_int)p_eye);
+ } else {
+ return 0;
+ }
+}
+
void ARVRInterfaceGDNative::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
ERR_FAIL_COND(interface == NULL);
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.h b/modules/gdnative/arvr/arvr_interface_gdnative.h
index 015d0c8a2a..3f966ece51 100644
--- a/modules/gdnative/arvr/arvr_interface_gdnative.h
+++ b/modules/gdnative/arvr/arvr_interface_gdnative.h
@@ -78,6 +78,7 @@ public:
// and a CameraMatrix version to ARVRServer
virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+ virtual unsigned int get_external_texture_for_eye(ARVRInterface::Eyes p_eye);
virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
virtual void process();
diff --git a/modules/gdnative/include/arvr/godot_arvr.h b/modules/gdnative/include/arvr/godot_arvr.h
index 0d14f3743f..321b471d0e 100644
--- a/modules/gdnative/include/arvr/godot_arvr.h
+++ b/modules/gdnative/include/arvr/godot_arvr.h
@@ -42,7 +42,7 @@ extern "C" {
// Use these to populate version in your plugin
#define GODOTVR_API_MAJOR 1
-#define GODOTVR_API_MINOR 0
+#define GODOTVR_API_MINOR 1
typedef struct {
godot_gdnative_api_version version; /* version of our API */
@@ -61,6 +61,8 @@ typedef struct {
void (*fill_projection_for_eye)(void *, godot_real *, godot_int, godot_real, godot_real, godot_real);
void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
void (*process)(void *);
+ // only in 1.1 onwards
+ godot_int (*get_external_texture_for_eye)(void *, godot_int);
} godot_arvr_interface_gdnative;
void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface);
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 7eb4294732..4577c7327a 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -323,6 +323,9 @@ List<ClassAPI> generate_c_api_classes() {
arg_type = "Variant";
} else if (arg_info.type == Variant::OBJECT) {
arg_type = arg_info.class_name;
+ if (arg_type == "") {
+ arg_type = Variant::get_type_name(arg_info.type);
+ }
} else {
arg_type = Variant::get_type_name(arg_info.type);
}
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index 3450a032c5..8dbbd2e4eb 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -34,7 +34,7 @@
#include "pluginscript_instance.h"
#include "pluginscript_script.h"
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
#define __ASSERT_SCRIPT_REASON "Cannot retrieve pluginscript class for this script, is you code correct ?"
#define ASSERT_SCRIPT_VALID() \
{ \
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 4385cf12ad..0676317f6e 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -597,7 +597,7 @@ Error GDScript::reload(bool p_keep_state) {
return err;
}
}
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) {
const GDScriptWarning &warning = E->get();
if (ScriptDebugger::get_singleton()) {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index ded873c7d3..c67e390e32 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -444,6 +444,7 @@ public:
virtual void get_reserved_words(List<String> *p_words) const;
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
+ virtual String _get_processed_template(const String &p_template, const String &p_base_class_name) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
virtual bool is_using_templates();
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index fafc73b7e6..ee0d5ae055 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -44,12 +44,43 @@ void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const
p_delimiters->push_back("#");
}
+
void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("\" \"");
p_delimiters->push_back("' '");
p_delimiters->push_back("\"\"\" \"\"\"");
}
+
+String GDScriptLanguage::_get_processed_template(const String &p_template, const String &p_base_class_name) const {
+
+ String processed_template = p_template;
+
+#ifdef TOOLS_ENABLED
+ if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) {
+ processed_template = processed_template.replace("%INT_TYPE%", ": int");
+ processed_template = processed_template.replace("%STRING_TYPE%", ": String");
+ processed_template = processed_template.replace("%FLOAT_TYPE%", ": float");
+ processed_template = processed_template.replace("%VOID_RETURN%", " -> void");
+ } else {
+ processed_template = processed_template.replace("%INT_TYPE%", "");
+ processed_template = processed_template.replace("%STRING_TYPE%", "");
+ processed_template = processed_template.replace("%FLOAT_TYPE%", "");
+ processed_template = processed_template.replace("%VOID_RETURN%", "");
+ }
+#else
+ processed_template = processed_template.replace("%INT_TYPE%", "");
+ processed_template = processed_template.replace("%STRING_TYPE%", "");
+ processed_template = processed_template.replace("%FLOAT_TYPE%", "");
+ processed_template = processed_template.replace("%VOID_RETURN%", "");
+#endif
+
+ processed_template = processed_template.replace("%BASE%", p_base_class_name);
+ processed_template = processed_template.replace("%TS%", _get_indentation());
+
+ return processed_template;
+}
+
Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
String _template = "extends %BASE%\n"
"\n"
@@ -65,27 +96,7 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str
"#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:\n"
"#%TS%pass\n";
-#ifdef TOOLS_ENABLED
- if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) {
- _template = _template.replace("%INT_TYPE%", ": int");
- _template = _template.replace("%STRING_TYPE%", ": String");
- _template = _template.replace("%FLOAT_TYPE%", ": float");
- _template = _template.replace("%VOID_RETURN%", " -> void");
- } else {
- _template = _template.replace("%INT_TYPE%", "");
- _template = _template.replace("%STRING_TYPE%", "");
- _template = _template.replace("%FLOAT_TYPE%", "");
- _template = _template.replace("%VOID_RETURN%", "");
- }
-#else
- _template = _template.replace("%INT_TYPE%", "");
- _template = _template.replace("%STRING_TYPE%", "");
- _template = _template.replace("%FLOAT_TYPE%", "");
- _template = _template.replace("%VOID_RETURN%", "");
-#endif
-
- _template = _template.replace("%BASE%", p_base_class_name);
- _template = _template.replace("%TS%", _get_indentation());
+ _template = _get_processed_template(_template, p_base_class_name);
Ref<GDScript> script;
script.instance();
@@ -101,10 +112,8 @@ bool GDScriptLanguage::is_using_templates() {
void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {
- String src = p_script->get_source_code();
- src = src.replace("%BASE%", p_base_class_name);
- src = src.replace("%TS%", _get_indentation());
- p_script->set_source_code(src);
+ String _template = _get_processed_template(p_script->get_source_code(), p_base_class_name);
+ p_script->set_source_code(_template);
}
bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 46c9efd54f..4fd136d5cc 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -74,6 +74,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"lerp",
"inverse_lerp",
"range_lerp",
+ "smoothstep",
"dectime",
"randomize",
"randi",
@@ -369,6 +370,13 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(4);
r_ret = Math::range_lerp((double)*p_args[0], (double)*p_args[1], (double)*p_args[2], (double)*p_args[3], (double)*p_args[4]);
} break;
+ case MATH_SMOOTHSTEP: {
+ VALIDATE_ARG_COUNT(3);
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ r_ret = Math::smoothstep((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
+ } break;
case MATH_DECTIME: {
VALIDATE_ARG_COUNT(3);
VALIDATE_ARG_NUM(0);
@@ -1435,6 +1443,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) {
case MATH_LERP:
case MATH_INVERSE_LERP:
case MATH_RANGE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME:
case MATH_DEG2RAD:
case MATH_RAD2DEG:
@@ -1618,6 +1627,11 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
mi.return_val.type = Variant::REAL;
return mi;
} break;
+ case MATH_SMOOTHSTEP: {
+ MethodInfo mi("smoothstep", PropertyInfo(Variant::REAL, "from"), PropertyInfo(Variant::REAL, "to"), PropertyInfo(Variant::REAL, "weight"));
+ mi.return_val.type = Variant::REAL;
+ return mi;
+ } break;
case MATH_DECTIME: {
MethodInfo mi("dectime", PropertyInfo(Variant::REAL, "value"), PropertyInfo(Variant::REAL, "amount"), PropertyInfo(Variant::REAL, "step"));
mi.return_val.type = Variant::REAL;
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h
index fcb8f32e54..14bf3d7560 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_functions.h
@@ -65,6 +65,7 @@ public:
MATH_LERP,
MATH_INVERSE_LERP,
MATH_RANGE_LERP,
+ MATH_SMOOTHSTEP,
MATH_DECTIME,
MATH_RANDOMIZE,
MATH_RAND,
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index 706949154e..b6ba9b1c23 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -257,7 +257,6 @@ def find_msbuild_windows():
def mono_build_solution(source, target, env):
import subprocess
- import mono_reg_utils as monoreg
from shutil import copyfile
sln_path = os.path.abspath(str(source[0]))
diff --git a/modules/mono/config.py b/modules/mono/config.py
index a81ecfce70..6b88600c56 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -5,7 +5,7 @@ import sys
import subprocess
from distutils.version import LooseVersion
-from SCons.Script import BoolVariable, Dir, Environment, File, SCons, Variables
+from SCons.Script import BoolVariable, Dir, Environment, Variables
monoreg = imp.load_source('mono_reg_utils', 'modules/mono/mono_reg_utils.py')
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index dfdb4a0b3a..5f97069485 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -571,7 +571,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
MonoException *exc = NULL;
- MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, (MonoObject **)&exc);
+ MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -595,7 +595,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
MonoString *file_name;
int file_line_num;
MonoString *method_decl;
- invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, (MonoObject **)&exc);
+ invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -625,7 +625,7 @@ void CSharpLanguage::frame() {
if (task_scheduler) {
MonoException *exc = NULL;
- invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, &exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
@@ -2166,7 +2166,8 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
CRASH_NOW();
}
- Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type);
+ GDMonoMarshal::ExportInfo export_info;
+ Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type, &export_info);
if (!p_member->has_attribute(CACHED_CLASS(ExportAttribute))) {
r_prop_info = PropertyInfo(variant_type, name.operator String(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
@@ -2191,6 +2192,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
ERR_PRINTS("Unknown type of exported member: " + p_class->get_full_name() + "." + name.operator String());
return false;
} else if (variant_type == Variant::INT && type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(type.type_class->get_mono_ptr())) {
+ // TODO: Move to ExportInfo?
variant_type = Variant::INT;
hint = PROPERTY_HINT_ENUM;
@@ -2257,6 +2259,11 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_
hint = PROPERTY_HINT_RESOURCE_TYPE;
hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class);
+ } else if (variant_type == Variant::ARRAY && export_info.array.element_type != Variant::NIL) {
+ hint = PROPERTY_HINT_TYPE_STRING;
+ hint_string = itos(export_info.array.element_type) + ":";
+ } else if (variant_type == Variant::DICTIONARY && export_info.dictionary.key_type != Variant::NIL && export_info.dictionary.value_type != Variant::NIL) {
+ // TODO: There is no hint for this yet
} else {
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index 921b9f987b..9d42528927 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -502,11 +502,11 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
String settings_hint_str = "Disabled";
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED)
settings_hint_str += ",MonoDevelop,Visual Studio Code";
-#elif OSX_ENABLED
+#elif defined(OSX_ENABLED)
settings_hint_str += ",Visual Studio,MonoDevelop,Visual Studio Code";
-#elif UNIX_ENABLED
+#elif defined(UNIX_ENABLED)
settings_hint_str += ",MonoDevelop,Visual Studio Code";
#endif
diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h
index cf0d2aec84..d9523c384c 100644
--- a/modules/mono/editor/godotsharp_editor.h
+++ b/modules/mono/editor/godotsharp_editor.h
@@ -81,15 +81,15 @@ public:
enum ExternalEditor {
EDITOR_NONE,
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED)
//EDITOR_VISUALSTUDIO, // TODO
EDITOR_MONODEVELOP,
EDITOR_VSCODE
-#elif OSX_ENABLED
+#elif defined(OSX_ENABLED)
EDITOR_VISUALSTUDIO_MAC,
EDITOR_MONODEVELOP,
EDITOR_VSCODE
-#elif UNIX_ENABLED
+#elif defined(UNIX_ENABLED)
EDITOR_MONODEVELOP,
EDITOR_VSCODE
#endif
diff --git a/modules/mono/glue/Managed/Files/Array.cs b/modules/mono/glue/Managed/Files/Array.cs
index 1ee64f3b71..2277c7bf18 100644
--- a/modules/mono/glue/Managed/Files/Array.cs
+++ b/modules/mono/glue/Managed/Files/Array.cs
@@ -28,7 +28,7 @@ namespace Godot.Collections
}
}
- public class Array : IList<object>, ICollection<object>, IEnumerable<object>, IDisposable
+ public class Array : IList, IDisposable
{
ArraySafeHandle safeHandle;
bool disposed = false;
@@ -38,6 +38,14 @@ namespace Godot.Collections
safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
}
+ public Array(IEnumerable collection) : this()
+ {
+ if (collection == null)
+ throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
+
+ MarshalUtils.EnumerableToArray(collection, GetPtr());
+ }
+
internal Array(ArraySafeHandle handle)
{
safeHandle = handle;
@@ -56,6 +64,13 @@ namespace Godot.Collections
return safeHandle.DangerousGetHandle();
}
+ public Error Resize(int newSize)
+ {
+ return godot_icall_Array_Resize(GetPtr(), newSize);
+ }
+
+ // IDisposable
+
public void Dispose()
{
if (disposed)
@@ -70,62 +85,55 @@ namespace Godot.Collections
disposed = true;
}
+ // IList
+
+ public bool IsReadOnly => false;
+
+ public bool IsFixedSize => false;
+
public object this[int index]
{
- get
- {
- return godot_icall_Array_At(GetPtr(), index);
- }
- set
- {
- godot_icall_Array_SetAt(GetPtr(), index, value);
- }
+ get => godot_icall_Array_At(GetPtr(), index);
+ set => godot_icall_Array_SetAt(GetPtr(), index, value);
}
- public int Count
- {
- get
- {
- return godot_icall_Array_Count(GetPtr());
- }
- }
+ public int Add(object value) => godot_icall_Array_Add(GetPtr(), value);
- public bool IsReadOnly
- {
- get
- {
- return false;
- }
- }
+ public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value);
- public void Add(object item)
- {
- godot_icall_Array_Add(GetPtr(), item);
- }
+ public void Clear() => godot_icall_Array_Clear(GetPtr());
- public void Clear()
- {
- godot_icall_Array_Clear(GetPtr());
- }
+ public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value);
- public bool Contains(object item)
- {
- return godot_icall_Array_Contains(GetPtr(), item);
- }
+ public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value);
+
+ public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value);
+
+ public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index);
+
+ // ICollection
+
+ public int Count => godot_icall_Array_Count(GetPtr());
+
+ public object SyncRoot => this;
- public void CopyTo(object[] array, int arrayIndex)
+ public bool IsSynchronized => false;
+
+ public void CopyTo(System.Array array, int index)
{
if (array == null)
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
- if (arrayIndex < 0)
- throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
// Internal call may throw ArgumentException
- godot_icall_Array_CopyTo(GetPtr(), array, arrayIndex);
+ godot_icall_Array_CopyTo(GetPtr(), array, index);
}
- public IEnumerator<object> GetEnumerator()
+ // IEnumerable
+
+ public IEnumerator GetEnumerator()
{
int count = Count;
@@ -135,36 +143,6 @@ namespace Godot.Collections
}
}
- public int IndexOf(object item)
- {
- return godot_icall_Array_IndexOf(GetPtr(), item);
- }
-
- public void Insert(int index, object item)
- {
- godot_icall_Array_Insert(GetPtr(), index, item);
- }
-
- public bool Remove(object item)
- {
- return godot_icall_Array_Remove(GetPtr(), item);
- }
-
- public void RemoveAt(int index)
- {
- godot_icall_Array_RemoveAt(GetPtr(), index);
- }
-
- public Error Resize(int newSize)
- {
- return godot_icall_Array_Resize(GetPtr(), newSize);
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_Array_Ctor();
@@ -184,7 +162,7 @@ namespace Godot.Collections
internal extern static int godot_icall_Array_Count(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_Array_Add(IntPtr ptr, object item);
+ internal extern static int godot_icall_Array_Add(IntPtr ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Clear(IntPtr ptr);
@@ -193,7 +171,7 @@ namespace Godot.Collections
internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex);
+ internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
@@ -231,6 +209,14 @@ namespace Godot.Collections
objectArray = new Array();
}
+ public Array(IEnumerable<T> collection)
+ {
+ if (collection == null)
+ throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
+
+ objectArray = new Array(collection);
+ }
+
public Array(Array array)
{
objectArray = array;
@@ -246,11 +232,23 @@ namespace Godot.Collections
objectArray = new Array(handle);
}
+ internal IntPtr GetPtr()
+ {
+ return objectArray.GetPtr();
+ }
+
public static explicit operator Array(Array<T> from)
{
return from.objectArray;
}
+ public Error Resize(int newSize)
+ {
+ return objectArray.Resize(newSize);
+ }
+
+ // IList<T>
+
public T this[int index]
{
get
@@ -263,6 +261,23 @@ namespace Godot.Collections
}
}
+ public int IndexOf(T item)
+ {
+ return objectArray.IndexOf(item);
+ }
+
+ public void Insert(int index, T item)
+ {
+ objectArray.Insert(index, item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ objectArray.RemoveAt(index);
+ }
+
+ // ICollection<T>
+
public int Count
{
get
@@ -317,6 +332,13 @@ namespace Godot.Collections
}
}
+ public bool Remove(T item)
+ {
+ return Array.godot_icall_Array_Remove(GetPtr(), item);
+ }
+
+ // IEnumerable<T>
+
public IEnumerator<T> GetEnumerator()
{
int count = objectArray.Count;
@@ -327,39 +349,9 @@ namespace Godot.Collections
}
}
- public int IndexOf(T item)
- {
- return objectArray.IndexOf(item);
- }
-
- public void Insert(int index, T item)
- {
- objectArray.Insert(index, item);
- }
-
- public bool Remove(T item)
- {
- return objectArray.Remove(item);
- }
-
- public void RemoveAt(int index)
- {
- objectArray.RemoveAt(index);
- }
-
- public Error Resize(int newSize)
- {
- return objectArray.Resize(newSize);
- }
-
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
-
- internal IntPtr GetPtr()
- {
- return objectArray.GetPtr();
- }
}
}
diff --git a/modules/mono/glue/Managed/Files/Dictionary.cs b/modules/mono/glue/Managed/Files/Dictionary.cs
index fb4521065f..af1782b79a 100644
--- a/modules/mono/glue/Managed/Files/Dictionary.cs
+++ b/modules/mono/glue/Managed/Files/Dictionary.cs
@@ -29,9 +29,7 @@ namespace Godot.Collections
}
public class Dictionary :
- IDictionary<object, object>,
- ICollection<KeyValuePair<object, object>>,
- IEnumerable<KeyValuePair<object, object>>,
+ IDictionary,
IDisposable
{
DictionarySafeHandle safeHandle;
@@ -42,6 +40,14 @@ namespace Godot.Collections
safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
}
+ public Dictionary(IDictionary dictionary) : this()
+ {
+ if (dictionary == null)
+ throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
+
+ MarshalUtils.IDictionaryToDictionary(dictionary, GetPtr());
+ }
+
internal Dictionary(DictionarySafeHandle handle)
{
safeHandle = handle;
@@ -74,19 +80,9 @@ namespace Godot.Collections
disposed = true;
}
- public object this[object key]
- {
- get
- {
- return godot_icall_Dictionary_GetValue(GetPtr(), key);
- }
- set
- {
- godot_icall_Dictionary_SetValue(GetPtr(), key, value);
- }
- }
+ // IDictionary
- public ICollection<object> Keys
+ public ICollection Keys
{
get
{
@@ -95,7 +91,7 @@ namespace Godot.Collections
}
}
- public ICollection<object> Values
+ public ICollection Values
{
get
{
@@ -104,97 +100,97 @@ namespace Godot.Collections
}
}
- public int Count
- {
- get
- {
- return godot_icall_Dictionary_Count(GetPtr());
- }
- }
+ public bool IsFixedSize => false;
- public bool IsReadOnly
- {
- get
- {
- return false;
- }
- }
+ public bool IsReadOnly => false;
- public void Add(object key, object value)
+ public object this[object key]
{
- godot_icall_Dictionary_Add(GetPtr(), key, value);
+ get => godot_icall_Dictionary_GetValue(GetPtr(), key);
+ set => godot_icall_Dictionary_SetValue(GetPtr(), key, value);
}
- public void Add(KeyValuePair<object, object> item)
- {
- Add(item.Key, item.Value);
- }
+ public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value);
- public void Clear()
- {
- godot_icall_Dictionary_Clear(GetPtr());
- }
+ public void Clear() => godot_icall_Dictionary_Clear(GetPtr());
- public bool Contains(KeyValuePair<object, object> item)
- {
- return godot_icall_Dictionary_Contains(GetPtr(), item.Key, item.Value);
- }
+ public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key);
- public bool ContainsKey(object key)
- {
- return godot_icall_Dictionary_ContainsKey(GetPtr(), key);
- }
+ public IDictionaryEnumerator GetEnumerator() => new DictionaryEnumerator(this);
+
+ public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+
+ // ICollection
+
+ public object SyncRoot => this;
- public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex)
+ public bool IsSynchronized => false;
+
+ public int Count => godot_icall_Dictionary_Count(GetPtr());
+
+ public void CopyTo(System.Array array, int index)
{
- // TODO 3 internal calls, can reduce to 1
+ // TODO Can be done with single internal call
+
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
+
Array keys = (Array)Keys;
Array values = (Array)Values;
int count = Count;
+ if (array.Length < (index + count))
+ throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+
for (int i = 0; i < count; i++)
{
- // TODO 2 internal calls, can reduce to 1
- array[arrayIndex] = new KeyValuePair<object, object>(keys[i], values[i]);
- arrayIndex++;
+ array.SetValue(new DictionaryEntry(keys[i], values[i]), index);
+ index++;
}
}
- public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
+ // IEnumerable
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ private class DictionaryEnumerator : IDictionaryEnumerator
{
- // TODO 3 internal calls, can reduce to 1
- Array keys = (Array)Keys;
- Array values = (Array)Values;
- int count = Count;
+ Array keys;
+ Array values;
+ int count;
+ int index = -1;
- for (int i = 0; i < count; i++)
+ public DictionaryEnumerator(Dictionary dictionary)
{
- // TODO 2 internal calls, can reduce to 1
- yield return new KeyValuePair<object, object>(keys[i], values[i]);
+ // TODO 3 internal calls, can reduce to 1
+ keys = (Array)dictionary.Keys;
+ values = (Array)dictionary.Values;
+ count = dictionary.Count;
}
- }
- public bool Remove(object key)
- {
- return godot_icall_Dictionary_RemoveKey(GetPtr(), key);
- }
+ public object Current => Entry;
- public bool Remove(KeyValuePair<object, object> item)
- {
- return godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
- }
+ public DictionaryEntry Entry =>
+ // TODO 2 internal calls, can reduce to 1
+ new DictionaryEntry(keys[index], values[index]);
- public bool TryGetValue(object key, out object value)
- {
- object retValue;
- bool found = godot_icall_Dictionary_TryGetValue(GetPtr(), key, out retValue);
- value = found ? retValue : default(object);
- return found;
- }
+ public object Key => Entry.Key;
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
+ public object Value => Entry.Value;
+
+ public bool MoveNext()
+ {
+ index++;
+ return index < count;
+ }
+
+ public void Reset()
+ {
+ index = -1;
+ }
}
[MethodImpl(MethodImplOptions.InternalCall)]
@@ -250,9 +246,7 @@ namespace Godot.Collections
}
public class Dictionary<TKey, TValue> :
- IDictionary<TKey, TValue>,
- ICollection<KeyValuePair<TKey, TValue>>,
- IEnumerable<KeyValuePair<TKey, TValue>>
+ IDictionary<TKey, TValue>
{
Dictionary objectDict;
@@ -269,6 +263,23 @@ namespace Godot.Collections
objectDict = new Dictionary();
}
+ public Dictionary(IDictionary<TKey, TValue> dictionary)
+ {
+ objectDict = new Dictionary();
+
+ if (dictionary == null)
+ throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
+
+ // TODO: Can be optimized
+
+ IntPtr godotDictionaryPtr = GetPtr();
+
+ foreach (KeyValuePair<TKey, TValue> entry in dictionary)
+ {
+ Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
+ }
+ }
+
public Dictionary(Dictionary dictionary)
{
objectDict = dictionary;
@@ -289,6 +300,13 @@ namespace Godot.Collections
return from.objectDict;
}
+ internal IntPtr GetPtr()
+ {
+ return objectDict.GetPtr();
+ }
+
+ // IDictionary<TKey, TValue>
+
public TValue this[TKey key]
{
get
@@ -319,6 +337,31 @@ namespace Godot.Collections
}
}
+ public void Add(TKey key, TValue value)
+ {
+ objectDict.Add(key, value);
+ }
+
+ public bool ContainsKey(TKey key)
+ {
+ return objectDict.Contains(key);
+ }
+
+ public bool Remove(TKey key)
+ {
+ return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ object retValue;
+ bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass);
+ value = found ? (TValue)retValue : default(TValue);
+ return found;
+ }
+
+ // ICollection<KeyValuePair<TKey, TValue>>
+
public int Count
{
get
@@ -335,11 +378,6 @@ namespace Godot.Collections
}
}
- public void Add(TKey key, TValue value)
- {
- objectDict.Add(key, value);
- }
-
public void Add(KeyValuePair<TKey, TValue> item)
{
objectDict.Add(item.Key, item.Value);
@@ -355,18 +393,22 @@ namespace Godot.Collections
return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
}
- public bool ContainsKey(TKey key)
- {
- return objectDict.ContainsKey(key);
- }
-
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+
// TODO 3 internal calls, can reduce to 1
Array<TKey> keys = (Array<TKey>)Keys;
Array<TValue> values = (Array<TValue>)Values;
int count = Count;
+ if (array.Length < (arrayIndex + count))
+ throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+
for (int i = 0; i < count; i++)
{
// TODO 2 internal calls, can reduce to 1
@@ -375,6 +417,13 @@ namespace Godot.Collections
}
}
+ public bool Remove(KeyValuePair<TKey, TValue> item)
+ {
+ return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); ;
+ }
+
+ // IEnumerable<KeyValuePair<TKey, TValue>>
+
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
// TODO 3 internal calls, can reduce to 1
@@ -389,32 +438,9 @@ namespace Godot.Collections
}
}
- public bool Remove(TKey key)
- {
- return objectDict.Remove(key);
- }
-
- public bool Remove(KeyValuePair<TKey, TValue> item)
- {
- return objectDict.Remove(new KeyValuePair<object, object>(item.Key, item.Value));
- }
-
- public bool TryGetValue(TKey key, out TValue value)
- {
- object retValue;
- bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass);
- value = found ? (TValue)retValue : default(TValue);
- return found;
- }
-
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
-
- internal IntPtr GetPtr()
- {
- return objectDict.GetPtr();
- }
}
}
diff --git a/modules/mono/glue/Managed/Files/MarshalUtils.cs b/modules/mono/glue/Managed/Files/MarshalUtils.cs
index f7699a15bf..7e72b0edb5 100644
--- a/modules/mono/glue/Managed/Files/MarshalUtils.cs
+++ b/modules/mono/glue/Managed/Files/MarshalUtils.cs
@@ -1,18 +1,68 @@
using System;
-using Godot.Collections;
+using System.Collections;
namespace Godot
{
+ using Array = Godot.Collections.Array;
+ using Dictionary = Godot.Collections.Dictionary;
+
static class MarshalUtils
{
- static bool IsArrayGenericType(Type type)
+ static bool TypeIsGenericArray(Type type)
{
- return type.GetGenericTypeDefinition() == typeof(Array<>);
+ return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
+ }
+
+ static bool TypeIsGenericDictionary(Type type)
+ {
+ return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
+ }
+
+ static void ArrayGetElementType(Type type, out Type elementType)
+ {
+ elementType = type.GetGenericArguments()[0];
+ }
+
+ static void DictionaryGetKeyValueTypes(Type type, out Type keyType, out Type valueType)
+ {
+ var genericArgs = type.GetGenericArguments();
+
+ keyType = genericArgs[0];
+ valueType = genericArgs[1];
+ }
+
+ // TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue>
+ // TODO: EnumerableToArray and IDictionaryToDictionary can be optimized
+
+ internal static void EnumerableToArray(IEnumerable enumerable, IntPtr godotArrayPtr)
+ {
+ if (enumerable is ICollection collection)
+ {
+ int count = collection.Count;
+
+ object[] tempArray = new object[count];
+ collection.CopyTo(tempArray, 0);
+
+ for (int i = 0; i < count; i++)
+ {
+ Array.godot_icall_Array_Add(godotArrayPtr, tempArray[i]);
+ }
+ }
+ else
+ {
+ foreach (object element in enumerable)
+ {
+ Array.godot_icall_Array_Add(godotArrayPtr, element);
+ }
+ }
}
- static bool IsDictionaryGenericType(Type type)
+ internal static void IDictionaryToDictionary(IDictionary dictionary, IntPtr godotDictionaryPtr)
{
- return type.GetGenericTypeDefinition() == typeof(Dictionary<, >);
+ foreach (DictionaryEntry entry in dictionary)
+ {
+ Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
+ }
}
}
}
diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs
index 5f5de12959..a064278237 100644
--- a/modules/mono/glue/Managed/Files/Mathf.cs
+++ b/modules/mono/glue/Managed/Files/Mathf.cs
@@ -261,6 +261,16 @@ namespace Godot
return (real_t)Math.Sinh(s);
}
+ public static real_t SmoothStep(real_t from, real_t to, real_t weight)
+ {
+ if (IsEqualApprox(from, to))
+ {
+ return from;
+ }
+ real_t x = Clamp((weight - from) / (to - from), (real_t)0.0, (real_t)1.0);
+ return x * x * (3 - 2 * x);
+ }
+
public static real_t Sqrt(real_t s)
{
return (real_t)Math.Sqrt(s);
diff --git a/modules/mono/glue/Managed/Files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs
index 73a3252fdb..908162ec45 100644
--- a/modules/mono/glue/Managed/Files/Vector2.cs
+++ b/modules/mono/glue/Managed/Files/Vector2.cs
@@ -132,6 +132,11 @@ namespace Godot
(-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
}
+ public Vector2 DirectionTo(Vector2 b)
+ {
+ return new Vector2(b.x - x, b.y - y).Normalized();
+ }
+
public real_t DistanceSquaredTo(Vector2 to)
{
return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y);
diff --git a/modules/mono/glue/Managed/Files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs
index f6ff27989d..0c96d346a9 100644
--- a/modules/mono/glue/Managed/Files/Vector3.cs
+++ b/modules/mono/glue/Managed/Files/Vector3.cs
@@ -126,6 +126,11 @@ namespace Godot
);
}
+ public Vector3 DirectionTo(Vector3 b)
+ {
+ return new Vector3(b.x - x, b.y - y, b.z - z).Normalized();
+ }
+
public real_t DistanceSquaredTo(Vector3 b)
{
return (b - this).LengthSquared();
diff --git a/modules/mono/glue/Managed/IgnoredFiles/Variant.cs b/modules/mono/glue/Managed/IgnoredFiles/Variant.cs
new file mode 100644
index 0000000000..802140b062
--- /dev/null
+++ b/modules/mono/glue/Managed/IgnoredFiles/Variant.cs
@@ -0,0 +1,11 @@
+
+namespace Godot
+{
+ public static class Variant
+ {
+ public enum Type
+ {
+
+ }
+ }
+}
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index b690de0d20..7f367fa095 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -192,7 +192,7 @@ MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoStrin
*r_result = GDMonoMarshal::variant_to_mono_object(result);
- return error.error == OK;
+ return error.error == Variant::CallError::CALL_OK;
}
MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result) {
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 1aad1c53bc..84c3f354d8 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -73,8 +73,9 @@ int godot_icall_Array_Count(Array *ptr) {
return ptr->size();
}
-void godot_icall_Array_Add(Array *ptr, MonoObject *item) {
+int godot_icall_Array_Add(Array *ptr, MonoObject *item) {
ptr->append(GDMonoMarshal::mono_object_to_variant(item));
+ return ptr->size();
}
void godot_icall_Array_Clear(Array *ptr) {
diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h
index 85a2e243a2..69768500d8 100644
--- a/modules/mono/glue/collections_glue.h
+++ b/modules/mono/glue/collections_glue.h
@@ -51,7 +51,7 @@ void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value);
int godot_icall_Array_Count(Array *ptr);
-void godot_icall_Array_Add(Array *ptr, MonoObject *item);
+int godot_icall_Array_Add(Array *ptr, MonoObject *item);
void godot_icall_Array_Clear(Array *ptr);
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index bba7df2c6a..48bea4addf 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -212,7 +212,7 @@ void GDMono::initialize() {
String config_dir;
#ifdef TOOLS_ENABLED
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED)
mono_reg_info = MonoRegUtils::find_mono();
if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) {
@@ -222,7 +222,7 @@ void GDMono::initialize() {
if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
config_dir = mono_reg_info.config_dir;
}
-#elif OSX_ENABLED
+#elif defined(OSX_ENABLED)
const char *c_assembly_rootdir = mono_assembly_getrootdir();
const char *c_config_dir = mono_get_config_dir();
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 92324d73f9..4342f46109 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -55,7 +55,8 @@ String GDMonoClass::get_full_name() const {
}
MonoType *GDMonoClass::get_mono_type() {
- // Care, you cannot compare MonoType pointers
+ // Careful, you cannot compare two MonoType*.
+ // There is mono_metadata_type_equal, how is this different from comparing two MonoClass*?
return get_mono_type(mono_class);
}
@@ -260,6 +261,11 @@ bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) {
return get_fetched_method_unknown_params(p_name) != NULL;
}
+bool GDMonoClass::implements_interface(GDMonoClass *p_interface) {
+
+ return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr());
+}
+
GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
MethodKey key = MethodKey(p_name, p_params_count);
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index 4af909450e..249422b844 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -135,6 +135,8 @@ public:
void fetch_attributes();
void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
+ bool implements_interface(GDMonoClass *p_interface);
+
GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0);
GDMonoMethod *get_method(MonoMethod *p_raw_method);
GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 5e9d4db122..9779797d1a 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -313,6 +313,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
ERR_FAIL();
} break;
@@ -422,8 +434,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -434,8 +446,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
@@ -443,6 +455,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
mono_field_set_value(p_object, mono_field, managed);
break;
}
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
} break;
default: {
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
index dd8c047386..d7962eac8b 100644
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ b/modules/mono/mono_gd/gd_mono_header.h
@@ -35,24 +35,12 @@
class GDMonoAssembly;
class GDMonoClass;
-class IMonoClassMember;
class GDMonoField;
-class GDMonoProperty;
class GDMonoMethod;
+class GDMonoProperty;
-struct ManagedType {
- int type_encoding;
- GDMonoClass *type_class;
-
- ManagedType() :
- type_encoding(0),
- type_class(NULL) {
- }
+class IMonoClassMember;
- ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
- type_encoding(p_type_encoding),
- type_class(p_type_class) {
- }
-};
+#include "managed_type.h"
#endif // GD_MONO_HEADER_H
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 7fe8ae608a..de4f3650bd 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -35,7 +35,7 @@
namespace GDMonoMarshal {
-Variant::Type managed_to_variant_type(const ManagedType &p_type) {
+Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return Variant::BOOL;
@@ -156,26 +156,66 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
if (CACHED_CLASS(Array) == type_class) {
return Variant::ARRAY;
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return Variant::DICTIONARY;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return Variant::ARRAY;
+ }
} break;
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
+ if (r_export_info) {
+ MonoReflectionType *key_reftype;
+ MonoReflectionType *value_reftype;
+
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes),
+ reftype, &key_reftype, &value_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ r_export_info->dictionary.key_type = managed_to_variant_type(ManagedType::from_reftype(key_reftype));
+ r_export_info->dictionary.value_type = managed_to_variant_type(ManagedType::from_reftype(value_reftype));
+ }
+
return Variant::DICTIONARY;
}
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
+ if (r_export_info) {
+ MonoReflectionType *elem_reftype;
+
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType),
+ reftype, &elem_reftype, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+ r_export_info->array.element_type = managed_to_variant_type(ManagedType::from_reftype(elem_reftype));
+ }
+
+ return Variant::ARRAY;
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return Variant::DICTIONARY;
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
return Variant::ARRAY;
}
} break;
@@ -453,6 +493,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
if (CACHED_CLASS(Array) == type_class) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ }
} break;
case MONO_TYPE_OBJECT: {
// Variant
@@ -548,8 +596,8 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -557,13 +605,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
}
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+ }
+
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+ }
} break;
} break;
}
@@ -577,15 +633,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (!p_obj)
return Variant();
- GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
- ERR_FAIL_COND_V(!tclass, Variant());
+ ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
- MonoType *raw_type = tclass->get_mono_type();
-
- ManagedType type;
-
- type.type_encoding = mono_type_get_type(raw_type);
- type.type_class = tclass;
+ ERR_FAIL_COND_V(!type.type_class, Variant());
switch (type.type_encoding) {
case MONO_TYPE_BOOLEAN:
@@ -717,17 +767,33 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (CACHED_CLASS(Array) == type_class) {
MonoException *exc = NULL;
- Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, (MonoObject **)&exc);
+ Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
if (CACHED_CLASS(Dictionary) == type_class) {
MonoException *exc = NULL;
- Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, (MonoObject **)&exc);
+ Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ Dictionary dict;
+ MonoException *exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return dict;
+ }
+
+ if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ Array array;
+ MonoException *exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return array;
+ }
} break;
case MONO_TYPE_GENERICINST: {
@@ -735,8 +801,8 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
MonoException *exc = NULL;
- GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -748,8 +814,8 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
exc = NULL;
- GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+ GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
@@ -758,6 +824,22 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return *unbox<Array *>(ret);
}
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ Dictionary dict;
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return dict;
+ }
+
+ if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ Array array;
+ exc = NULL;
+ invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
+ UNLIKELY_UNHANDLED_EXCEPTION(exc);
+ return array;
+ }
} break;
}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 4f86e02f87..4a73f9e3e6 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -32,6 +32,7 @@
#define GDMONOMARSHAL_H
#include "core/variant.h"
+
#include "gd_mono.h"
#include "gd_mono_utils.h"
@@ -56,7 +57,25 @@ T unbox(MonoObject *p_obj) {
#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x)
-Variant::Type managed_to_variant_type(const ManagedType &p_type);
+// FIXME: Made this struct in a hurry. It could be done differently.
+struct ExportInfo {
+ struct ArrayInfo {
+ Variant::Type element_type;
+
+ ArrayInfo() :
+ element_type(Variant::NIL) {}
+ } array;
+ struct DictionaryInfo {
+ Variant::Type key_type;
+ Variant::Type value_type;
+
+ DictionaryInfo() :
+ key_type(Variant::NIL),
+ value_type(Variant::NIL) {}
+ } dictionary;
+};
+
+Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info = NULL);
// String
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 6cc1c8afc2..429d4f68d9 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -63,6 +63,7 @@ MonoCache mono_cache;
#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val)
#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val)
#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
+#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.property_##m_class##_##m_property, m_val)
void MonoCache::clear_members() {
@@ -81,6 +82,9 @@ void MonoCache::clear_members() {
class_String = NULL;
class_IntPtr = NULL;
+ class_System_Collections_IEnumerable = NULL;
+ class_System_Collections_IDictionary = NULL;
+
#ifdef DEBUG_ENABLED
class_System_Diagnostics_StackTrace = NULL;
methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL;
@@ -143,12 +147,17 @@ void MonoCache::clear_members() {
methodthunk_GodotObject_Dispose = NULL;
methodthunk_Array_GetPtr = NULL;
methodthunk_Dictionary_GetPtr = NULL;
- methodthunk_MarshalUtils_IsArrayGenericType = NULL;
- methodthunk_MarshalUtils_IsDictionaryGenericType = NULL;
methodthunk_SignalAwaiter_SignalCallback = NULL;
methodthunk_SignalAwaiter_FailureCallback = NULL;
methodthunk_GodotTaskScheduler_Activate = NULL;
+ methodthunk_MarshalUtils_TypeIsGenericArray = NULL;
+ methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL;
+ methodthunk_MarshalUtils_ArrayGetElementType = NULL;
+ methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL;
+ methodthunk_MarshalUtils_EnumerableToArray = NULL;
+ methodthunk_MarshalUtils_IDictionaryToDictionary = NULL;
+
task_scheduler_handle = Ref<MonoGCHandle>();
}
@@ -178,6 +187,9 @@ void update_corlib_cache() {
CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
+ CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
+ CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
+
#ifdef DEBUG_ENABLED
CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace"));
CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_thunk("GetFrames"));
@@ -242,12 +254,17 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, (GodotObject_Dispose)CACHED_CLASS(GodotObject)->get_method_thunk("Dispose", 0));
CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0));
CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsArrayGenericType", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsDictionaryGenericType", 1));
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1));
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0));
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2));
+
#ifdef DEBUG_ENABLED
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4));
#endif
@@ -712,7 +729,7 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &
}
void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
- invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, (MonoObject **)r_exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc);
}
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index e88bf1ced9..87610e286c 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -49,18 +49,21 @@
namespace GDMonoUtils {
-typedef void (*GodotObject_Dispose)(MonoObject *, MonoObject **);
-typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **);
-typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **);
-typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
-typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
-typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
-typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **);
-typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **);
-typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **);
+typedef void (*GodotObject_Dispose)(MonoObject *, MonoException **);
+typedef Array *(*Array_GetPtr)(MonoObject *, MonoException **);
+typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoException **);
+typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoException **);
+typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoException **);
+typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoException **);
+typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoException **);
+typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoException **);
+
+typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **);
+typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **);
+typedef MonoBoolean (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **);
+typedef MonoBoolean (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
+typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **);
+typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **);
struct MonoCache {
@@ -83,6 +86,9 @@ struct MonoCache {
GDMonoClass *class_String;
GDMonoClass *class_IntPtr;
+ GDMonoClass *class_System_Collections_IEnumerable;
+ GDMonoClass *class_System_Collections_IDictionary;
+
#ifdef DEBUG_ENABLED
GDMonoClass *class_System_Diagnostics_StackTrace;
StackTrace_GetFrames methodthunk_System_Diagnostics_StackTrace_GetFrames;
@@ -146,12 +152,17 @@ struct MonoCache {
GodotObject_Dispose methodthunk_GodotObject_Dispose;
Array_GetPtr methodthunk_Array_GetPtr;
Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
- IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType;
- IsDictionaryGenericType methodthunk_MarshalUtils_IsDictionaryGenericType;
SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
+ TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray;
+ TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary;
+ ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType;
+ DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
+ EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray;
+ IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary;
+
Ref<MonoGCHandle> task_scheduler_handle;
bool corlib_cache_updated;
@@ -255,6 +266,7 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc);
#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field)
#define CACHED_METHOD(m_class, m_method) (GDMonoUtils::mono_cache.method_##m_class##_##m_method)
#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method)
+#define CACHED_PROPERTY(m_class, m_property) (GDMonoUtils::mono_cache.property_##m_class##_##m_property)
#ifdef REAL_T_IS_DOUBLE
#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp
new file mode 100644
index 0000000000..9f736b71cd
--- /dev/null
+++ b/modules/mono/mono_gd/managed_type.cpp
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* managed_type.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. */
+/*************************************************************************/
+
+#include "managed_type.h"
+
+#include "gd_mono.h"
+#include "gd_mono_class.h"
+
+ManagedType ManagedType::from_class(GDMonoClass *p_class) {
+ return ManagedType(mono_type_get_type(p_class->get_mono_type()), p_class);
+}
+
+ManagedType ManagedType::from_class(MonoClass *p_mono_class) {
+ GDMonoClass *tclass = GDMono::get_singleton()->get_class(p_mono_class);
+ ERR_FAIL_COND_V(!tclass, ManagedType());
+
+ return ManagedType(mono_type_get_type(tclass->get_mono_type()), tclass);
+}
+
+ManagedType ManagedType::from_type(MonoType *p_mono_type) {
+ MonoClass *mono_class = mono_class_from_mono_type(p_mono_type);
+ GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_class);
+ ERR_FAIL_COND_V(!tclass, ManagedType());
+
+ return ManagedType(mono_type_get_type(p_mono_type), tclass);
+}
+
+ManagedType ManagedType::from_reftype(MonoReflectionType *p_mono_reftype) {
+ MonoType *mono_type = mono_reflection_type_get_type(p_mono_reftype);
+ return from_type(mono_type);
+}
diff --git a/drivers/gl_context/context_gl.cpp b/modules/mono/mono_gd/managed_type.h
index 759ab6f3ec..a537e56aea 100644
--- a/drivers/gl_context/context_gl.cpp
+++ b/modules/mono/mono_gd/managed_type.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* context_gl.cpp */
+/* managed_type.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,28 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "context_gl.h"
+#ifndef MANAGED_TYPE_H
+#define MANAGED_TYPE_H
-#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED)
+#include <mono/metadata/object.h>
-ContextGL *ContextGL::singleton = NULL;
+#include "gd_mono_header.h"
-ContextGL *ContextGL::get_singleton() {
+struct ManagedType {
+ int type_encoding;
+ GDMonoClass *type_class;
- return singleton;
-}
+ static ManagedType from_class(GDMonoClass *p_class);
+ static ManagedType from_class(MonoClass *p_mono_class);
+ static ManagedType from_type(MonoType *p_mono_type);
+ static ManagedType from_reftype(MonoReflectionType *p_mono_reftype);
-ContextGL::ContextGL() {
+ ManagedType() :
+ type_encoding(0),
+ type_class(NULL) {
+ }
- ERR_FAIL_COND(singleton);
+ ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
+ type_encoding(p_type_encoding),
+ type_class(p_type_class) {
+ }
+};
- singleton = this;
-}
-
-ContextGL::~ContextGL() {
-
- if (singleton == this)
- singleton = NULL;
-}
-
-#endif
+#endif // MANAGED_TYPE_H
diff --git a/modules/mono/mono_reg_utils.py b/modules/mono/mono_reg_utils.py
index c8ebb54ded..583708bf07 100644
--- a/modules/mono/mono_reg_utils.py
+++ b/modules/mono/mono_reg_utils.py
@@ -40,7 +40,7 @@ def _reg_open_key_bits(key, subkey, bits):
def _find_mono_in_reg(subkey, bits):
try:
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- value, regtype = winreg.QueryValueEx(hKey, 'SdkInstallRoot')
+ value = winreg.QueryValueEx(hKey, 'SdkInstallRoot')[0]
return value
except (WindowsError, OSError):
return None
@@ -49,7 +49,7 @@ def _find_mono_in_reg(subkey, bits):
def _find_mono_in_reg_old(subkey, bits):
try:
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- default_clr, regtype = winreg.QueryValueEx(hKey, 'DefaultCLR')
+ default_clr = winreg.QueryValueEx(hKey, 'DefaultCLR')[0]
if default_clr:
return _find_mono_in_reg(subkey + '\\' + default_clr, bits)
return None
@@ -91,7 +91,13 @@ def find_msbuild_tools_path_reg():
if not val:
raise ValueError('Value of `installationPath` entry is empty')
- return os.path.join(val, "MSBuild\\15.0\\Bin")
+ # Since VS2019, the directory is simply named "Current"
+ msbuild_dir = os.path.join(val, 'MSBuild\\Current\\Bin')
+ if os.path.isdir(msbuild_dir):
+ return msbuild_dir
+
+ # Directory name "15.0" is used in VS 2017
+ return os.path.join(val, 'MSBuild\\15.0\\Bin')
raise ValueError('Cannot find `installationPath` entry')
except ValueError as e:
@@ -106,7 +112,7 @@ def find_msbuild_tools_path_reg():
try:
subkey = r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0'
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
- value, regtype = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')
+ value = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')[0]
return value
except (WindowsError, OSError):
return ''
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 5051d83694..5d37e8212f 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -100,7 +100,7 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc
MonoException *exc = NULL;
GD_MONO_BEGIN_RUNTIME_INVOKE;
- invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, &exc);
GD_MONO_END_RUNTIME_INVOKE;
if (exc) {
@@ -132,7 +132,7 @@ SignalAwaiterHandle::~SignalAwaiterHandle() {
if (awaiter) {
MonoException *exc = NULL;
GD_MONO_BEGIN_RUNTIME_INVOKE;
- invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, &exc);
GD_MONO_END_RUNTIME_INVOKE;
if (exc) {
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index d7f9b22c31..98aeadc8c8 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -202,9 +202,9 @@ String find_msbuild_tools_path() {
}
// Since VS2019, the directory is simply named "Current"
- String msBuildDirectory = val + "MSBuild\\Current\\Bin";
- if (DirAccess::exists(msBuildDirectory)) {
- return msBuildDirectory;
+ String msbuild_dir = val + "MSBuild\\Current\\Bin";
+ if (DirAccess::exists(msbuild_dir)) {
+ return msbuild_dir;
}
// Directory name "15.0" is used in VS 2017
diff --git a/modules/mono/utils/thread_local.h b/modules/mono/utils/thread_local.h
index 276db8830b..488cc2619a 100644
--- a/modules/mono/utils/thread_local.h
+++ b/modules/mono/utils/thread_local.h
@@ -39,7 +39,7 @@
#error Platform or compiler not supported
#endif
-#ifdef __GNUC__
+#if defined(__GNUC__)
#ifdef HAVE_GCC___THREAD
#define _THREAD_LOCAL_(m_t) __thread m_t
@@ -47,7 +47,7 @@
#define USE_CUSTOM_THREAD_LOCAL
#endif
-#elif _MSC_VER
+#elif defined(_MSC_VER)
#ifdef HAVE_DECLSPEC_THREAD
#define _THREAD_LOCAL_(m_t) __declspec(thread) m_t
diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp
index b2d6b5e718..3a3a698e5c 100644
--- a/modules/opensimplex/open_simplex_noise.cpp
+++ b/modules/opensimplex/open_simplex_noise.cpp
@@ -173,6 +173,7 @@ void OpenSimplexNoise::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_image", "width", "height"), &OpenSimplexNoise::get_image);
ClassDB::bind_method(D_METHOD("get_seamless_image", "size"), &OpenSimplexNoise::get_seamless_image);
+ ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &OpenSimplexNoise::get_noise_1d);
ClassDB::bind_method(D_METHOD("get_noise_2d", "x", "y"), &OpenSimplexNoise::get_noise_2d);
ClassDB::bind_method(D_METHOD("get_noise_3d", "x", "y", "z"), &OpenSimplexNoise::get_noise_3d);
ClassDB::bind_method(D_METHOD("get_noise_4d", "x", "y", "z", "w"), &OpenSimplexNoise::get_noise_4d);
@@ -187,6 +188,11 @@ void OpenSimplexNoise::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "lacunarity", PROPERTY_HINT_RANGE, "0.1,4.0,0.01"), "set_lacunarity", "get_lacunarity");
}
+float OpenSimplexNoise::get_noise_1d(float x) {
+
+ return get_noise_2d(x, 1.0);
+}
+
float OpenSimplexNoise::get_noise_2d(float x, float y) {
x /= period;
diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h
index ac4c6e361f..96885f5893 100644
--- a/modules/opensimplex/open_simplex_noise.h
+++ b/modules/opensimplex/open_simplex_noise.h
@@ -73,6 +73,7 @@ public:
Ref<Image> get_image(int p_width, int p_height);
Ref<Image> get_seamless_image(int p_size);
+ float get_noise_1d(float x);
float get_noise_2d(float x, float y);
float get_noise_3d(float x, float y, float z);
float get_noise_4d(float x, float y, float z, float w);
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
index dd14d60327..104a90059e 100644
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
@@ -204,7 +204,14 @@
<constant name="COLORN" value="62" enum="BuiltinFunc">
Return the [Color] with the given name and alpha ranging from 0 to 1. Note: names are defined in color_names.inc.
</constant>
- <constant name="FUNC_MAX" value="63" enum="BuiltinFunc">
+ <constant name="MATH_SMOOTHSTEP" value="63" enum="BuiltinFunc">
+ Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [code]MATH_LERP[/code], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula:
+ [codeblock]
+ var t = clamp((weight - from) / (to - from), 0.0, 1.0)
+ return t * t * (3.0 - 2.0 * t)
+ [/codeblock]
+ </constant>
+ <constant name="FUNC_MAX" value="64" enum="BuiltinFunc">
The maximum value the [member function] property can have.
</constant>
</constants>
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 0d379205e4..c2ce5f0bf5 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -102,6 +102,7 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"var2bytes",
"bytes2var",
"color_named",
+ "smoothstep",
};
VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String &p_string) {
@@ -204,6 +205,7 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
return 2;
case MATH_LERP:
case MATH_INVERSE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME:
case MATH_WRAP:
case MATH_WRAPF:
@@ -337,6 +339,14 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
else
return PropertyInfo(Variant::REAL, "ostop");
} break;
+ case MATH_SMOOTHSTEP: {
+ if (p_idx == 0)
+ return PropertyInfo(Variant::REAL, "from");
+ else if (p_idx == 1)
+ return PropertyInfo(Variant::REAL, "to");
+ else
+ return PropertyInfo(Variant::REAL, "weight");
+ } break;
case MATH_DECTIME: {
if (p_idx == 0)
return PropertyInfo(Variant::REAL, "value");
@@ -569,6 +579,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
case MATH_LERP:
case MATH_INVERSE_LERP:
case MATH_RANGE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME: {
t = Variant::REAL;
@@ -899,6 +910,12 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
VALIDATE_ARG_NUM(4);
*r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
} break;
+ case VisualScriptBuiltinFunc::MATH_SMOOTHSTEP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case VisualScriptBuiltinFunc::MATH_DECTIME: {
VALIDATE_ARG_NUM(0);
@@ -1379,6 +1396,7 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(VAR_TO_BYTES);
BIND_ENUM_CONSTANT(BYTES_TO_VAR);
BIND_ENUM_CONSTANT(COLORN);
+ BIND_ENUM_CONSTANT(MATH_SMOOTHSTEP);
BIND_ENUM_CONSTANT(FUNC_MAX);
}
@@ -1433,6 +1451,7 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/smoothstep", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SMOOTHSTEP>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/dectime", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/rand", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>);
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
index 2d8454ddd4..50854c16b1 100644
--- a/modules/visual_script/visual_script_builtin_funcs.h
+++ b/modules/visual_script/visual_script_builtin_funcs.h
@@ -101,6 +101,7 @@ public:
VAR_TO_BYTES,
BYTES_TO_VAR,
COLORN,
+ MATH_SMOOTHSTEP,
FUNC_MAX
};
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 7e54891d97..6e7e566206 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -579,7 +579,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
if (gnode->is_comment())
sbf = EditorNode::get_singleton()->get_theme_base()->get_theme()->get_stylebox("comment", "GraphNode");
- Color c = sbf->get_border_color(MARGIN_TOP);
+ Color c = sbf->get_border_color();
c.a = 1;
if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
@@ -3054,10 +3054,10 @@ void VisualScriptEditor::_notification(int p_what) {
Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
if (!sb.is_null()) {
Ref<StyleBoxFlat> frame_style = sb->duplicate();
- Color c = sb->get_border_color(MARGIN_TOP);
+ Color c = sb->get_border_color();
Color cn = E->get().second;
cn.a = c.a;
- frame_style->set_border_color_all(cn);
+ frame_style->set_border_color(cn);
node_styles[E->get().first] = frame_style;
}
}
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 80ee6644f3..d494372bcd 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -2,7 +2,6 @@
Import('env')
-import shutil
from compat import open_utf8
from distutils.version import LooseVersion
from detect import get_ndk_version
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index cb25575b74..1232fc7453 100644
--- a/platform/android/audio_driver_opensl.cpp
+++ b/platform/android/audio_driver_opensl.cpp
@@ -326,7 +326,7 @@ Error AudioDriverOpenSL::capture_stop() {
int AudioDriverOpenSL::get_mix_rate() const {
- return 44100;
+ return 44100; // hardcoded for Android, as selected by SL_SAMPLINGRATE_44_1
}
AudioDriver::SpeakerMode AudioDriverOpenSL::get_speaker_mode() const {
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 80cda68a9e..5623274050 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -1,6 +1,5 @@
import os
import sys
-import string
import platform
from distutils.version import LooseVersion
diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp
index 8b7dd08bb7..3c4e31da36 100644
--- a/platform/haiku/audio_driver_media_kit.cpp
+++ b/platform/haiku/audio_driver_media_kit.cpp
@@ -39,11 +39,11 @@ int32_t *AudioDriverMediaKit::samples_in = NULL;
Error AudioDriverMediaKit::init() {
active = false;
- mix_rate = 44100;
+ mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
- int latency = GLOBAL_DEF_RST("audio/output_latency", 25);
+ int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
buffer_size = next_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_size * channels);
diff --git a/platform/haiku/context_gl_haiku.h b/platform/haiku/context_gl_haiku.h
index 6eb67fea70..8452f5fbfb 100644
--- a/platform/haiku/context_gl_haiku.h
+++ b/platform/haiku/context_gl_haiku.h
@@ -33,12 +33,10 @@
#if defined(OPENGL_ENABLED)
-#include "drivers/gl_context/context_gl.h"
-
#include "haiku_direct_window.h"
#include "haiku_gl_view.h"
-class ContextGL_Haiku : public ContextGL {
+class ContextGL_Haiku {
private:
HaikuGLView *view;
HaikuDirectWindow *window;
@@ -46,18 +44,18 @@ private:
bool use_vsync;
public:
- virtual Error initialize();
- virtual void release_current();
- virtual void make_current();
- virtual void swap_buffers();
- virtual int get_window_width();
- virtual int get_window_height();
+ Error initialize();
+ void release_current();
+ void make_current();
+ void swap_buffers();
+ int get_window_width();
+ int get_window_height();
- virtual void set_use_vsync(bool p_use);
- virtual bool is_using_vsync() const;
+ void set_use_vsync(bool p_use);
+ bool is_using_vsync() const;
ContextGL_Haiku(HaikuDirectWindow *p_window);
- virtual ~ContextGL_Haiku();
+ ~ContextGL_Haiku();
};
#endif
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
index 41991bce86..fa1b124561 100644
--- a/platform/iphone/SCsub
+++ b/platform/iphone/SCsub
@@ -2,8 +2,6 @@
Import('env')
-import os
-
iphone_lib = [
'godot_iphone.cpp',
'os_iphone.cpp',
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index 172572bcb4..853f24379e 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -1,5 +1,4 @@
import os
-import string
import sys
from methods import detect_darwin_sdk_path
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 47da8de5df..c7acbde3f7 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -1,5 +1,4 @@
import os
-import sys
def is_active():
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index d2952ebdc0..e15b4339a7 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -2,7 +2,6 @@
Import('env')
-import os
from platform_methods import run_in_subprocess
import platform_osx_builders
diff --git a/platform/server/SCsub b/platform/server/SCsub
index 62d45efbc0..f977275595 100644
--- a/platform/server/SCsub
+++ b/platform/server/SCsub
@@ -1,7 +1,5 @@
#!/usr/bin/env python
-import os
-import platform
import sys
Import('env')
diff --git a/platform/uwp/context_egl_uwp.h b/platform/uwp/context_egl_uwp.h
index 812bdfb688..0c62fe7456 100644
--- a/platform/uwp/context_egl_uwp.h
+++ b/platform/uwp/context_egl_uwp.h
@@ -37,11 +37,10 @@
#include "core/error_list.h"
#include "core/os/os.h"
-#include "drivers/gl_context/context_gl.h"
using namespace Windows::UI::Core;
-class ContextEGL_UWP : public ContextGL {
+class ContextEGL_UWP {
public:
enum Driver {
@@ -64,24 +63,24 @@ private:
Driver driver;
public:
- virtual void release_current();
+ void release_current();
- virtual void make_current();
+ void make_current();
- virtual int get_window_width();
- virtual int get_window_height();
- virtual void swap_buffers();
+ int get_window_width();
+ int get_window_height();
+ void swap_buffers();
- virtual void set_use_vsync(bool use) { vsync = use; }
- virtual bool is_using_vsync() const { return vsync; }
+ void set_use_vsync(bool use) { vsync = use; }
+ bool is_using_vsync() const { return vsync; }
- virtual Error initialize();
+ Error initialize();
void reset();
void cleanup();
ContextEGL_UWP(CoreWindow ^ p_window, Driver p_driver);
- virtual ~ContextEGL_UWP();
+ ~ContextEGL_UWP();
};
#endif // CONTEXT_EGL_UWP_H
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index c32a11b396..f8f1b066f6 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -1,6 +1,5 @@
import methods
import os
-import string
import sys
@@ -25,8 +24,6 @@ def can_build():
def get_opts():
- from SCons.Variables import BoolVariable
-
return [
('msvc_version', 'MSVC version to use (ignored if the VCINSTALLDIR environment variable is set)', None),
]
diff --git a/platform/windows/context_gl_windows.h b/platform/windows/context_gl_windows.h
index 09801b9146..d23fba50e1 100644
--- a/platform/windows/context_gl_windows.h
+++ b/platform/windows/context_gl_windows.h
@@ -37,13 +37,12 @@
#include "core/error_list.h"
#include "core/os/os.h"
-#include "drivers/gl_context/context_gl.h"
#include <windows.h>
typedef bool(APIENTRY *PFNWGLSWAPINTERVALEXTPROC)(int interval);
-class ContextGL_Windows : public ContextGL {
+class ContextGL_Windows {
HDC hDC;
HGLRC hRC;
@@ -55,21 +54,21 @@ class ContextGL_Windows : public ContextGL {
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
public:
- virtual void release_current();
+ void release_current();
- virtual void make_current();
+ void make_current();
- virtual int get_window_width();
- virtual int get_window_height();
- virtual void swap_buffers();
+ int get_window_width();
+ int get_window_height();
+ void swap_buffers();
- virtual Error initialize();
+ Error initialize();
- virtual void set_use_vsync(bool p_use);
- virtual bool is_using_vsync() const;
+ void set_use_vsync(bool p_use);
+ bool is_using_vsync() const;
ContextGL_Windows(HWND hwnd, bool p_opengl_3_context);
- virtual ~ContextGL_Windows();
+ ~ContextGL_Windows();
};
#endif
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 426a5e9e61..0118b5bae2 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,6 +1,5 @@
import methods
import os
-import sys
def is_active():
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
index e302f09c88..3d5aa15208 100644
--- a/platform/x11/SCsub
+++ b/platform/x11/SCsub
@@ -2,7 +2,6 @@
Import('env')
-import os
from platform_methods import run_in_subprocess
import platform_x11_builders
diff --git a/platform/x11/context_gl_x11.h b/platform/x11/context_gl_x11.h
index 02455ce005..46420df48b 100644
--- a/platform/x11/context_gl_x11.h
+++ b/platform/x11/context_gl_x11.h
@@ -39,13 +39,12 @@
#if defined(OPENGL_ENABLED)
#include "core/os/os.h"
-#include "drivers/gl_context/context_gl.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
struct ContextGL_X11_Private;
-class ContextGL_X11 : public ContextGL {
+class ContextGL_X11 {
public:
enum ContextType {
@@ -67,19 +66,19 @@ private:
ContextType context_type;
public:
- virtual void release_current();
- virtual void make_current();
- virtual void swap_buffers();
- virtual int get_window_width();
- virtual int get_window_height();
+ void release_current();
+ void make_current();
+ void swap_buffers();
+ int get_window_width();
+ int get_window_height();
- virtual Error initialize();
+ Error initialize();
- virtual void set_use_vsync(bool p_use);
- virtual bool is_using_vsync() const;
+ void set_use_vsync(bool p_use);
+ bool is_using_vsync() const;
ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type);
- virtual ~ContextGL_X11();
+ ~ContextGL_X11();
};
#endif
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 5cc5ef4ac0..5f7b825f5e 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -1,9 +1,9 @@
import os
import platform
import sys
-from compat import decode_utf8
from methods import get_compiler_version, using_gcc
+
def is_active():
return True
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index 7a50574be2..932db8f001 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -679,7 +679,7 @@ void AnimatedSprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite::_set_playing);
ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite::_is_playing);
- ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite::play, DEFVAL(StringName()));
+ ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite::play, DEFVAL(StringName()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite::stop);
ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite::is_playing);
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index fec861ad2f..4097006b33 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -95,7 +95,7 @@ void Path2D::_notification(int p_what) {
return;
}
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
const float line_width = 2 * EDSCALE;
#else
const float line_width = 2;
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index 17b698c1b8..e5346c4c53 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -233,6 +233,13 @@ void ARVRController::_notification(int p_what) {
} else {
button_states = 0;
};
+
+ // check for an updated mesh
+ Ref<Mesh> trackerMesh = tracker->get_mesh();
+ if (mesh != trackerMesh) {
+ mesh = trackerMesh;
+ emit_signal("mesh_updated", mesh);
+ }
};
}; break;
default:
@@ -258,8 +265,11 @@ void ARVRController::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &ARVRController::set_rumble);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
+ ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRController::get_mesh);
+
ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button")));
ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button")));
+ ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
};
void ARVRController::set_controller_id(int p_controller_id) {
@@ -341,6 +351,10 @@ void ARVRController::set_rumble(real_t p_rumble) {
};
};
+Ref<Mesh> ARVRController::get_mesh() const {
+ return mesh;
+}
+
bool ARVRController::get_is_active() const {
return is_active;
};
@@ -423,6 +437,13 @@ void ARVRAnchor::_notification(int p_what) {
// apply our reference frame and set our transform
set_transform(arvr_server->get_reference_frame() * transform);
+
+ // check for an updated mesh
+ Ref<Mesh> trackerMesh = tracker->get_mesh();
+ if (mesh != trackerMesh) {
+ mesh = trackerMesh;
+ emit_signal("mesh_updated", mesh);
+ }
};
}; break;
default:
@@ -441,6 +462,9 @@ void ARVRAnchor::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_size"), &ARVRAnchor::get_size);
ClassDB::bind_method(D_METHOD("get_plane"), &ARVRAnchor::get_plane);
+
+ ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRAnchor::get_mesh);
+ ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
};
void ARVRAnchor::set_anchor_id(int p_anchor_id) {
@@ -501,6 +525,10 @@ Plane ARVRAnchor::get_plane() const {
return plane;
};
+Ref<Mesh> ARVRAnchor::get_mesh() const {
+ return mesh;
+}
+
ARVRAnchor::ARVRAnchor() {
anchor_id = 0;
is_active = true;
diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h
index 523bc112c1..0833e18d48 100644
--- a/scene/3d/arvr_nodes.h
+++ b/scene/3d/arvr_nodes.h
@@ -33,6 +33,7 @@
#include "scene/3d/camera.h"
#include "scene/3d/spatial.h"
+#include "scene/resources/mesh.h"
#include "servers/arvr/arvr_positional_tracker.h"
/**
@@ -75,6 +76,7 @@ private:
int controller_id;
bool is_active;
int button_states;
+ Ref<Mesh> mesh;
protected:
void _notification(int p_what);
@@ -95,6 +97,8 @@ public:
bool get_is_active() const;
ARVRPositionalTracker::TrackerHand get_hand() const;
+ Ref<Mesh> get_mesh(void) const;
+
String get_configuration_warning() const;
ARVRController();
@@ -113,6 +117,7 @@ private:
int anchor_id;
bool is_active;
Vector3 size;
+ Ref<Mesh> mesh;
protected:
void _notification(int p_what);
@@ -128,6 +133,8 @@ public:
Plane get_plane() const;
+ Ref<Mesh> get_mesh(void) const;
+
String get_configuration_warning() const;
ARVRAnchor();
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index ac20609c21..d6a0595519 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -104,6 +104,14 @@ SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
offset = obj_tocopy.offset;
}
+SoftBody::PinnedPoint SoftBody::PinnedPoint::operator=(const PinnedPoint &obj) {
+ point_index = obj.point_index;
+ spatial_attachment_path = obj.spatial_attachment_path;
+ spatial_attachment = obj.spatial_attachment;
+ offset = obj.offset;
+ return *this;
+}
+
void SoftBody::_update_pickable() {
if (!is_inside_tree())
return;
diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h
index 2516d39552..ee455f8dab 100644
--- a/scene/3d/soft_body.h
+++ b/scene/3d/soft_body.h
@@ -75,6 +75,7 @@ public:
PinnedPoint();
PinnedPoint(const PinnedPoint &obj_tocopy);
+ PinnedPoint operator=(const PinnedPoint &obj);
};
private:
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index caae48336b..2195de9694 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -38,30 +38,32 @@ void TextureRect::_notification(int p_what) {
if (texture.is_null())
return;
+ Size2 size;
+ Point2 offset;
+ Rect2 region;
+ bool tile = false;
+
switch (stretch_mode) {
case STRETCH_SCALE_ON_EXPAND: {
- Size2 s = expand ? get_size() : texture->get_size();
- draw_texture_rect(texture, Rect2(Point2(), s), false);
+ size = expand ? get_size() : texture->get_size();
} break;
case STRETCH_SCALE: {
- draw_texture_rect(texture, Rect2(Point2(), get_size()), false);
+ size = get_size();
} break;
case STRETCH_TILE: {
- draw_texture_rect(texture, Rect2(Point2(), get_size()), true);
+ size = get_size();
+ tile = true;
} break;
case STRETCH_KEEP: {
- draw_texture_rect(texture, Rect2(Point2(), texture->get_size()), false);
-
+ size = texture->get_size();
} break;
case STRETCH_KEEP_CENTERED: {
-
- Vector2 ofs = (get_size() - texture->get_size()) / 2;
- draw_texture_rect(texture, Rect2(ofs, texture->get_size()), false);
+ offset = (get_size() - texture->get_size()) / 2;
+ size = texture->get_size();
} break;
case STRETCH_KEEP_ASPECT_CENTERED:
case STRETCH_KEEP_ASPECT: {
-
- Size2 size = get_size();
+ size = get_size();
int tex_width = texture->get_width() * size.height / texture->get_height();
int tex_height = size.height;
@@ -70,26 +72,35 @@ void TextureRect::_notification(int p_what) {
tex_height = texture->get_height() * tex_width / texture->get_width();
}
- int ofs_x = 0;
- int ofs_y = 0;
-
if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) {
- ofs_x += (size.width - tex_width) / 2;
- ofs_y += (size.height - tex_height) / 2;
+ offset.x += (size.width - tex_width) / 2;
+ offset.y += (size.height - tex_height) / 2;
}
- draw_texture_rect(texture, Rect2(ofs_x, ofs_y, tex_width, tex_height));
+ size.width = tex_width;
+ size.height = tex_height;
} break;
case STRETCH_KEEP_ASPECT_COVERED: {
- Size2 size = get_size();
+ size = get_size();
+
Size2 tex_size = texture->get_size();
Size2 scaleSize(size.width / tex_size.width, size.height / tex_size.height);
float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height;
Size2 scaledTexSize = tex_size * scale;
- Point2 ofs = ((scaledTexSize - size) / scale).abs() / 2.0f;
- draw_texture_rect_region(texture, Rect2(Point2(), size), Rect2(ofs, size / scale));
+
+ region.position = ((scaledTexSize - size) / scale).abs() / 2.0f;
+ region.size = size / scale;
} break;
}
+
+ size.width *= hflip ? -1.0f : 1.0f;
+ size.height *= vflip ? -1.0f : 1.0f;
+
+ if (region.no_area()) {
+ draw_texture_rect(texture, Rect2(offset, size), tile);
+ } else {
+ draw_texture_rect_region(texture, Rect2(offset, size), region);
+ }
}
}
@@ -106,12 +117,18 @@ void TextureRect::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture"), &TextureRect::get_texture);
ClassDB::bind_method(D_METHOD("set_expand", "enable"), &TextureRect::set_expand);
ClassDB::bind_method(D_METHOD("has_expand"), &TextureRect::has_expand);
+ ClassDB::bind_method(D_METHOD("set_flip_h", "enable"), &TextureRect::set_flip_h);
+ ClassDB::bind_method(D_METHOD("is_flipped_h"), &TextureRect::is_flipped_h);
+ ClassDB::bind_method(D_METHOD("set_flip_v", "enable"), &TextureRect::set_flip_v);
+ ClassDB::bind_method(D_METHOD("is_flipped_v"), &TextureRect::is_flipped_v);
ClassDB::bind_method(D_METHOD("set_stretch_mode", "stretch_mode"), &TextureRect::set_stretch_mode);
ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureRect::get_stretch_mode);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand");
ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale On Expand (Compat),Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
BIND_ENUM_CONSTANT(STRETCH_SCALE_ON_EXPAND);
BIND_ENUM_CONSTANT(STRETCH_SCALE);
@@ -161,9 +178,31 @@ TextureRect::StretchMode TextureRect::get_stretch_mode() const {
return stretch_mode;
}
+void TextureRect::set_flip_h(bool p_flip) {
+
+ hflip = p_flip;
+ update();
+}
+bool TextureRect::is_flipped_h() const {
+
+ return hflip;
+}
+
+void TextureRect::set_flip_v(bool p_flip) {
+
+ vflip = p_flip;
+ update();
+}
+bool TextureRect::is_flipped_v() const {
+
+ return vflip;
+}
+
TextureRect::TextureRect() {
expand = false;
+ hflip = false;
+ vflip = false;
set_mouse_filter(MOUSE_FILTER_PASS);
stretch_mode = STRETCH_SCALE_ON_EXPAND;
}
diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h
index ddd101573b..3ab35324e5 100644
--- a/scene/gui/texture_rect.h
+++ b/scene/gui/texture_rect.h
@@ -53,6 +53,8 @@ public:
private:
bool expand;
+ bool hflip;
+ bool vflip;
Ref<Texture> texture;
StretchMode stretch_mode;
@@ -71,6 +73,12 @@ public:
void set_stretch_mode(StretchMode p_mode);
StretchMode get_stretch_mode() const;
+ void set_flip_h(bool p_flip);
+ bool is_flipped_h() const;
+
+ void set_flip_v(bool p_flip);
+ bool is_flipped_v() const;
+
TextureRect();
~TextureRect();
};
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 49c9c4c23c..87a15bbeda 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -139,6 +139,7 @@
#include "scene/resources/dynamic_font.h"
#include "scene/resources/dynamic_font_stb.h"
#include "scene/resources/gradient.h"
+#include "scene/resources/height_map_shape.h"
#include "scene/resources/line_shape_2d.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
@@ -476,6 +477,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeInput>();
ClassDB::register_virtual_class<VisualShaderNodeOutput>();
ClassDB::register_class<VisualShaderNodeScalarConstant>();
+ ClassDB::register_class<VisualShaderNodeBooleanConstant>();
ClassDB::register_class<VisualShaderNodeColorConstant>();
ClassDB::register_class<VisualShaderNodeVec3Constant>();
ClassDB::register_class<VisualShaderNodeTransformConstant>();
@@ -486,8 +488,23 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeTransformVecMult>();
ClassDB::register_class<VisualShaderNodeScalarFunc>();
ClassDB::register_class<VisualShaderNodeVectorFunc>();
+ ClassDB::register_class<VisualShaderNodeColorFunc>();
+ ClassDB::register_class<VisualShaderNodeTransformFunc>();
ClassDB::register_class<VisualShaderNodeDotProduct>();
ClassDB::register_class<VisualShaderNodeVectorLen>();
+ ClassDB::register_class<VisualShaderNodeDeterminant>();
+ ClassDB::register_class<VisualShaderNodeScalarDerivativeFunc>();
+ ClassDB::register_class<VisualShaderNodeVectorDerivativeFunc>();
+ ClassDB::register_class<VisualShaderNodeScalarClamp>();
+ ClassDB::register_class<VisualShaderNodeVectorClamp>();
+ ClassDB::register_class<VisualShaderNodeFaceForward>();
+ ClassDB::register_class<VisualShaderNodeOuterProduct>();
+ ClassDB::register_class<VisualShaderNodeVectorScalarStep>();
+ ClassDB::register_class<VisualShaderNodeScalarSmoothStep>();
+ ClassDB::register_class<VisualShaderNodeVectorSmoothStep>();
+ ClassDB::register_class<VisualShaderNodeVectorScalarSmoothStep>();
+ ClassDB::register_class<VisualShaderNodeVectorDistance>();
+ ClassDB::register_class<VisualShaderNodeVectorRefract>();
ClassDB::register_class<VisualShaderNodeScalarInterp>();
ClassDB::register_class<VisualShaderNodeVectorInterp>();
ClassDB::register_class<VisualShaderNodeVectorCompose>();
@@ -498,6 +515,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeCubeMap>();
ClassDB::register_virtual_class<VisualShaderNodeUniform>();
ClassDB::register_class<VisualShaderNodeScalarUniform>();
+ ClassDB::register_class<VisualShaderNodeBooleanUniform>();
ClassDB::register_class<VisualShaderNodeColorUniform>();
ClassDB::register_class<VisualShaderNodeVec3Uniform>();
ClassDB::register_class<VisualShaderNodeTransformUniform>();
@@ -591,6 +609,7 @@ void register_scene_types() {
ClassDB::register_class<BoxShape>();
ClassDB::register_class<CapsuleShape>();
ClassDB::register_class<CylinderShape>();
+ ClassDB::register_class<HeightMapShape>();
ClassDB::register_class<PlaneShape>();
ClassDB::register_class<ConvexPolygonShape>();
ClassDB::register_class<ConcavePolygonShape>();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index f73914b186..e58ec9d71e 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1466,7 +1466,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const {
int high = len - 1;
int middle = 0;
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
if (low > high)
ERR_PRINT("low > high, this may be a bug");
#endif
diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp
index 98d3460ed2..5845e4be50 100644
--- a/scene/resources/convex_polygon_shape.cpp
+++ b/scene/resources/convex_polygon_shape.cpp
@@ -83,6 +83,4 @@ void ConvexPolygonShape::_bind_methods() {
ConvexPolygonShape::ConvexPolygonShape() :
Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON)) {
-
- //set_points(Vector3(1,1,1));
}
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index f275405de2..d424fb2814 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -99,10 +99,4 @@ Rect2 ConvexPolygonShape2D::get_rect() const {
ConvexPolygonShape2D::ConvexPolygonShape2D() :
Shape2D(Physics2DServer::get_singleton()->convex_polygon_shape_create()) {
-
- int pcount = 3;
- for (int i = 0; i < pcount; i++)
- points.push_back(Vector2(Math::sin(i * Math_PI * 2 / pcount), -Math::cos(i * Math_PI * 2 / pcount)) * 10);
-
- _update_shape();
}
diff --git a/scene/resources/default_theme/make_header.py b/scene/resources/default_theme/make_header.py
index 73b1ae0b0b..bd5a723b23 100755
--- a/scene/resources/default_theme/make_header.py
+++ b/scene/resources/default_theme/make_header.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python
-import os
import glob
-import string
enc = "utf-8"
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index a51a0ca0d0..7e7fc99a5d 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -91,7 +91,7 @@ public:
int high = points.size() - 1;
int middle = 0;
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
if (low > high)
ERR_PRINT("low > high, this may be a bug");
#endif
diff --git a/scene/resources/height_map_shape.cpp b/scene/resources/height_map_shape.cpp
new file mode 100644
index 0000000000..32e9c527ef
--- /dev/null
+++ b/scene/resources/height_map_shape.cpp
@@ -0,0 +1,196 @@
+/*************************************************************************/
+/* height_map_shape.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. */
+/*************************************************************************/
+
+#include "height_map_shape.h"
+#include "servers/physics_server.h"
+
+Vector<Vector3> HeightMapShape::_gen_debug_mesh_lines() {
+ Vector<Vector3> points;
+
+ // This will be slow for large maps...
+ // also we'll have to figure out how well bullet centers this shape...
+
+ Vector2 size(map_width - 1, map_depth - 1);
+ Vector2 start = size * -0.5;
+ int offset = 0;
+
+ PoolRealArray::Read r = map_data.read();
+
+ for (int d = 0; d < map_depth; d++) {
+ Vector3 height(start.x, 0.0, start.y);
+
+ for (int w = 0; w < map_width; w++) {
+ height.y = r[offset++];
+
+ if (w != map_width - 1) {
+ points.push_back(height);
+ points.push_back(Vector3(height.x + 1.0, r[offset], height.z));
+ }
+
+ if (d != map_depth - 1) {
+ points.push_back(height);
+ points.push_back(Vector3(height.x, r[offset + map_width - 1], height.z + 1.0));
+ }
+
+ height.x += 1.0;
+ }
+
+ start.y += 1.0;
+ }
+
+ return points;
+}
+
+void HeightMapShape::_update_shape() {
+
+ Dictionary d;
+ d["width"] = map_width;
+ d["depth"] = map_depth;
+ d["heights"] = map_data;
+ d["min_height"] = min_height;
+ d["max_height"] = max_height;
+ PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
+}
+
+void HeightMapShape::set_map_width(int p_new) {
+ if (p_new < 1) {
+ // ignore
+ } else if (map_width != p_new) {
+ int was_size = map_width * map_depth;
+ map_width = p_new;
+
+ int new_size = map_width * map_depth;
+ map_data.resize(map_width * map_depth);
+
+ PoolRealArray::Write w = map_data.write();
+ while (was_size < new_size) {
+ w[was_size++] = 0.0;
+ }
+
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("map_width");
+ _change_notify("map_data");
+ }
+}
+
+int HeightMapShape::get_map_width() const {
+ return map_width;
+}
+
+void HeightMapShape::set_map_depth(int p_new) {
+ if (p_new < 1) {
+ // ignore
+ } else if (map_depth != p_new) {
+ int was_size = map_width * map_depth;
+ map_depth = p_new;
+
+ int new_size = map_width * map_depth;
+ map_data.resize(new_size);
+
+ PoolRealArray::Write w = map_data.write();
+ while (was_size < new_size) {
+ w[was_size++] = 0.0;
+ }
+
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("map_depth");
+ _change_notify("map_data");
+ }
+}
+
+int HeightMapShape::get_map_depth() const {
+ return map_depth;
+}
+
+void HeightMapShape::set_map_data(PoolRealArray p_new) {
+ int size = (map_width * map_depth);
+ if (p_new.size() != size) {
+ // fail
+ return;
+ }
+
+ // copy
+ PoolRealArray::Write w = map_data.write();
+ PoolRealArray::Read r = p_new.read();
+ for (int i = 0; i < size; i++) {
+ float val = r[i];
+ w[i] = val;
+ if (i == 0) {
+ min_height = val;
+ max_height = val;
+ } else {
+ if (min_height > val)
+ min_height = val;
+
+ if (max_height < val)
+ max_height = val;
+ }
+ }
+
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("map_data");
+}
+
+PoolRealArray HeightMapShape::get_map_data() const {
+ return map_data;
+}
+
+void HeightMapShape::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape::set_map_width);
+ ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape::get_map_width);
+ ClassDB::bind_method(D_METHOD("set_map_depth", "height"), &HeightMapShape::set_map_depth);
+ ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape::get_map_depth);
+ ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape::set_map_data);
+ ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape::get_map_data);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "1,4096,1"), "set_map_width", "get_map_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "1,4096,1"), "set_map_depth", "get_map_depth");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_REAL_ARRAY, "map_data"), "set_map_data", "get_map_data");
+}
+
+HeightMapShape::HeightMapShape() :
+ Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_HEIGHTMAP)) {
+
+ map_width = 2;
+ map_depth = 2;
+ map_data.resize(map_width * map_depth);
+ PoolRealArray::Write w = map_data.write();
+ w[0] = 0.0;
+ w[1] = 0.0;
+ w[2] = 0.0;
+ w[3] = 0.0;
+ min_height = 0.0;
+ max_height = 0.0;
+
+ _update_shape();
+}
diff --git a/drivers/gl_context/context_gl.h b/scene/resources/height_map_shape.h
index 890683b7c5..b062f4e893 100644
--- a/drivers/gl_context/context_gl.h
+++ b/scene/resources/height_map_shape.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* context_gl.h */
+/* height_map_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,39 +28,35 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CONTEXT_GL_H
-#define CONTEXT_GL_H
+#ifndef HEIGHT_MAP_SHAPE_H
+#define HEIGHT_MAP_SHAPE_H
-#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED)
+#include "scene/resources/shape.h"
-#include "core/typedefs.h"
+class HeightMapShape : public Shape {
+ GDCLASS(HeightMapShape, Shape);
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+ int map_width;
+ int map_depth;
+ PoolRealArray map_data;
+ float min_height;
+ float max_height;
-class ContextGL {
+protected:
+ static void _bind_methods();
+ virtual void _update_shape();
- static ContextGL *singleton;
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
- static ContextGL *get_singleton();
-
- virtual void release_current() = 0;
-
- virtual void make_current() = 0;
-
- virtual void swap_buffers() = 0;
-
- virtual Error initialize() = 0;
-
- virtual void set_use_vsync(bool p_use) = 0;
- virtual bool is_using_vsync() const = 0;
-
- ContextGL();
- virtual ~ContextGL();
+ void set_map_width(int p_new);
+ int get_map_width() const;
+ void set_map_depth(int p_new);
+ int get_map_depth() const;
+ void set_map_data(PoolRealArray p_new);
+ PoolRealArray get_map_data() const;
+
+ HeightMapShape();
};
-#endif
-
-#endif
+#endif /* !HEIGHT_MAP_SHAPE_H */
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index cdd65c7642..5dd429fa75 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -368,25 +368,14 @@ Color StyleBoxFlat::get_bg_color() const {
return bg_color;
}
-void StyleBoxFlat::set_border_color_all(const Color &p_color) {
- for (int i = 0; i < 4; i++) {
+void StyleBoxFlat::set_border_color(const Color &p_color) {
- border_color.write()[i] = p_color;
- }
+ border_color = p_color;
emit_changed();
}
-Color StyleBoxFlat::get_border_color_all() const {
+Color StyleBoxFlat::get_border_color() const {
- return border_color[MARGIN_TOP];
-}
-void StyleBoxFlat::set_border_color(Margin p_border, const Color &p_color) {
-
- border_color.write()[p_border] = p_color;
- emit_changed();
-}
-Color StyleBoxFlat::get_border_color(Margin p_border) const {
-
- return border_color[p_border];
+ return border_color;
}
void StyleBoxFlat::set_border_width_all(int p_size) {
@@ -511,6 +500,16 @@ int StyleBoxFlat::get_shadow_size() const {
return shadow_size;
}
+void StyleBoxFlat::set_shadow_offset(const Point2 &p_offset) {
+
+ shadow_offset = p_offset;
+ emit_changed();
+}
+Point2 StyleBoxFlat::get_shadow_offset() const {
+
+ return shadow_offset;
+}
+
void StyleBoxFlat::set_anti_aliased(const bool &p_anti_aliased) {
anti_aliased = p_anti_aliased;
emit_changed();
@@ -552,7 +551,7 @@ inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_re
inner_corner_radius[0] = MAX(corner_radius[0] - rad, 0);
//tr
- rad = MIN(border_top, border_bottom);
+ rad = MIN(border_top, border_right);
inner_corner_radius[1] = MAX(corner_radius[1] - rad, 0);
//br
@@ -565,12 +564,13 @@ inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_re
}
inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 style_rect, const int corner_radius[4],
- const Rect2 ring_rect, const int border_width[4], const Color inner_color[4], const Color outer_color[4], const int corner_detail) {
+ const Rect2 ring_rect, const int border_width[4], const Color &inner_color, const Color &outer_color, const int corner_detail, const bool fill_center = false) {
int vert_offset = verts.size();
if (!vert_offset) {
vert_offset = 0;
}
+
int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;
int ring_corner_radius[4];
@@ -585,10 +585,11 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
Rect2 inner_rect;
inner_rect = ring_rect.grow_individual(-border_width[MARGIN_LEFT], -border_width[MARGIN_TOP], -border_width[MARGIN_RIGHT], -border_width[MARGIN_BOTTOM]);
+
int inner_corner_radius[4];
+ set_inner_corner_radius(style_rect, inner_rect, corner_radius, inner_corner_radius);
Vector<Point2> inner_points;
- set_inner_corner_radius(style_rect, inner_rect, corner_radius, inner_corner_radius);
inner_points.push_back(inner_rect.position + Vector2(inner_corner_radius[0], inner_corner_radius[0])); //tl
inner_points.push_back(Point2(inner_rect.position.x + inner_rect.size.x - inner_corner_radius[1], inner_rect.position.y + inner_corner_radius[1])); //tr
inner_points.push_back(inner_rect.position + inner_rect.size - Vector2(inner_corner_radius[2], inner_corner_radius[2])); //br
@@ -603,11 +604,11 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
Point2 corner_point;
if (inner_outer == 0) {
radius = inner_corner_radius[corner_index];
- color = *inner_color;
+ color = inner_color;
corner_point = inner_points[corner_index];
} else {
radius = ring_corner_radius[corner_index];
- color = *outer_color;
+ color = outer_color;
corner_point = outer_points[corner_index];
}
float x = radius * (float)cos((double)corner_index * Math_PI / 2.0 + (double)detail / (double)adapted_corner_detail * Math_PI / 2.0 + Math_PI) + corner_point.x;
@@ -618,17 +619,28 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
}
}
- int vert_count = (adapted_corner_detail + 1) * 4 * 2;
+ int ring_vert_count = verts.size() - vert_offset;
+
//fill the indices and the colors for the border
- for (int i = 0; i < vert_count; i++) {
- //poly 1
- indices.push_back(vert_offset + ((i + 0) % vert_count));
- indices.push_back(vert_offset + ((i + 2) % vert_count));
- indices.push_back(vert_offset + ((i + 1) % vert_count));
- //poly 2
- indices.push_back(vert_offset + ((i + 1) % vert_count));
- indices.push_back(vert_offset + ((i + 2) % vert_count));
- indices.push_back(vert_offset + ((i + 3) % vert_count));
+ for (int i = 0; i < ring_vert_count; i++) {
+ indices.push_back(vert_offset + ((i + 0) % ring_vert_count));
+ indices.push_back(vert_offset + ((i + 2) % ring_vert_count));
+ indices.push_back(vert_offset + ((i + 1) % ring_vert_count));
+ }
+
+ if (fill_center) {
+ //fill the indices and the colors for the center
+ for (int index = 0; index < ring_vert_count / 2; index += 2) {
+ int i = index;
+ //poly 1
+ indices.push_back(vert_offset + i);
+ indices.push_back(vert_offset + ring_vert_count - 4 - i);
+ indices.push_back(vert_offset + i + 2);
+ //poly 2
+ indices.push_back(vert_offset + i);
+ indices.push_back(vert_offset + ring_vert_count - 2 - i);
+ indices.push_back(vert_offset + ring_vert_count - 4 - i);
+ }
}
}
@@ -657,13 +669,29 @@ inline void adapt_values(int p_index_a, int p_index_b, int *adapted_values, cons
void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
//PREPARATIONS
+ bool draw_border = (border_width[0] > 0) || (border_width[1] > 0) || (border_width[2] > 0) || (border_width[3] > 0);
+ bool draw_shadow = (shadow_size > 0);
+ if (!draw_border && !draw_center && !draw_shadow) {
+ return;
+ }
bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
bool aa_on = rounded_corners && anti_aliased;
+ Color border_color_alpha = Color(border_color.r, border_color.g, border_color.b, 0);
+
+ bool blend_on = blend_border && draw_border;
+
Rect2 style_rect = p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]);
- if (aa_on) {
- style_rect = style_rect.grow(-((aa_size + 1) / 2));
+ Rect2 border_style_rect = style_rect;
+ if (aa_on && !blend_on) {
+ float aa_size_grow = 0.5 * ((aa_size + 1) / 2);
+ style_rect = style_rect.grow(-aa_size_grow);
+ for (int i = 0; i < 4; i++) {
+ if (border_width[i] > 0) {
+ border_style_rect = border_style_rect.grow_margin((Margin)i, -aa_size_grow);
+ }
+ }
}
//adapt borders (prevent weird overlapping/glitchy drawings)
@@ -686,79 +714,93 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Vector<int> indices;
Vector<Color> colors;
- //DRAWING
- VisualServer *vs = VisualServer::get_singleton();
-
//DRAW SHADOW
- if (shadow_size > 0) {
+ if (draw_shadow) {
int shadow_width[4] = { shadow_size, shadow_size, shadow_size, shadow_size };
- Color shadow_colors[4] = { shadow_color, shadow_color, shadow_color, shadow_color };
- Color shadow_colors_transparent[4];
- for (int i = 0; i < 4; i++) {
- shadow_colors_transparent[i] = Color(shadow_color.r, shadow_color.g, shadow_color.b, 0);
+
+ Rect2 shadow_inner_rect = style_rect;
+ shadow_inner_rect.position += shadow_offset;
+
+ Rect2 shadow_rect = style_rect.grow(shadow_size);
+ shadow_rect.position += shadow_offset;
+
+ Color shadow_color_transparent = Color(shadow_color.r, shadow_color.g, shadow_color.b, 0);
+
+ draw_ring(verts, indices, colors, shadow_inner_rect, adapted_corner,
+ shadow_rect, shadow_width, shadow_color, shadow_color_transparent, corner_detail);
+
+ if (draw_center) {
+ int no_border[4] = { 0, 0, 0, 0 };
+ draw_ring(verts, indices, colors, shadow_inner_rect, adapted_corner,
+ shadow_inner_rect, no_border, shadow_color, shadow_color, corner_detail, true);
}
- draw_ring(verts, indices, colors, style_rect, adapted_corner,
- style_rect.grow(shadow_size), shadow_width, shadow_colors, shadow_colors_transparent, corner_detail);
}
//DRAW border
- Color bg_color_array[4] = { bg_color, bg_color, bg_color, bg_color };
- const Color *inner_color = ((blend_border) ? bg_color_array : border_color.read().ptr());
- draw_ring(verts, indices, colors, style_rect, adapted_corner,
- style_rect, adapted_border, inner_color, border_color.read().ptr(), corner_detail);
+ if (draw_border) {
+ draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
+ border_style_rect, adapted_border, blend_on ? (draw_center ? bg_color : border_color_alpha) : border_color, border_color, corner_detail);
+ }
//DRAW INFILL
if (draw_center) {
- int temp_vert_offset = verts.size();
int no_border[4] = { 0, 0, 0, 0 };
draw_ring(verts, indices, colors, style_rect, adapted_corner,
- infill_rect, no_border, &bg_color, &bg_color, corner_detail);
- int added_vert_count = verts.size() - temp_vert_offset;
- //fill the indices and the colors for the center
- for (int index = 0; index <= added_vert_count / 2; index += 2) {
- int i = index;
- //poly 1
- indices.push_back(temp_vert_offset + i);
- indices.push_back(temp_vert_offset + added_vert_count - 4 - i);
- indices.push_back(temp_vert_offset + i + 2);
- //poly 1
- indices.push_back(temp_vert_offset + i);
- indices.push_back(temp_vert_offset + added_vert_count - 2 - i);
- indices.push_back(temp_vert_offset + added_vert_count - 4 - i);
- }
+ infill_rect, no_border, bg_color, bg_color, corner_detail, true);
}
if (aa_on) {
-
- //HELPER ARRAYS
- Color border_color_alpha[4];
- for (int i = 0; i < 4; i++) {
- Color c = border_color.read().ptr()[i];
- border_color_alpha[i] = Color(c.r, c.g, c.b, 0);
+ Rect2 border_inner_rect = infill_rect;
+ int aa_border_width[4];
+ int aa_fill_width[4];
+ if (draw_border) {
+ border_inner_rect = border_style_rect.grow_individual(-adapted_border[MARGIN_LEFT], -adapted_border[MARGIN_TOP], -adapted_border[MARGIN_RIGHT], -adapted_border[MARGIN_BOTTOM]);
+ for (int i = 0; i < 4; i++) {
+ if (border_width[i] > 0) {
+ aa_border_width[i] = aa_size;
+ aa_fill_width[i] = 0;
+ } else {
+ aa_border_width[i] = 0;
+ aa_fill_width[i] = aa_size;
+ }
+ }
+ } else {
+ for (int i = 0; i < 4; i++) {
+ aa_fill_width[i] = aa_size;
+ }
}
- Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0);
- Color bg_color_array_alpha[4] = { alpha_bg, alpha_bg, alpha_bg, alpha_bg };
-
- int aa_border_width[4] = { aa_size, aa_size, aa_size, aa_size };
if (draw_center) {
- if (!blend_border) {
+ if (!draw_border || !blend_on) {
+ Rect2 aa_rect = infill_rect.grow_individual(aa_fill_width[MARGIN_LEFT], aa_fill_width[MARGIN_TOP],
+ aa_fill_width[MARGIN_RIGHT], aa_fill_width[MARGIN_BOTTOM]);
+
+ Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0);
+
//INFILL AA
draw_ring(verts, indices, colors, style_rect, adapted_corner,
- infill_rect.grow(aa_size), aa_border_width, bg_color_array, bg_color_array_alpha, corner_detail);
+ aa_rect, aa_fill_width, bg_color, alpha_bg, corner_detail);
}
- } else if (!(border_width[0] == 0 && border_width[1] == 0 && border_width[2] == 0 && border_width[3] == 0)) {
- //DRAW INNER BORDER AA
- draw_ring(verts, indices, colors, style_rect, adapted_corner,
- infill_rect, aa_border_width, border_color_alpha, border_color.read().ptr(), corner_detail);
}
- //DRAW OUTER BORDER AA
- if (!(border_width[0] == 0 && border_width[1] == 0 && border_width[2] == 0 && border_width[3] == 0)) {
- draw_ring(verts, indices, colors, style_rect, adapted_corner,
- style_rect.grow(aa_size), aa_border_width, border_color.read().ptr(), border_color_alpha, corner_detail);
+
+ if (draw_border) {
+ if (!blend_on) {
+ //DRAW INNER BORDER AA
+ draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
+ border_inner_rect, aa_border_width, border_color_alpha, border_color, corner_detail);
+ }
+
+ Rect2 aa_rect = border_style_rect.grow_individual(aa_border_width[MARGIN_LEFT], aa_border_width[MARGIN_TOP],
+ aa_border_width[MARGIN_RIGHT], aa_border_width[MARGIN_BOTTOM]);
+
+ //DRAW OUTER BORDER AA
+ draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
+ aa_rect, aa_border_width, border_color, border_color_alpha, corner_detail);
}
}
+ //DRAWING
+ VisualServer *vs = VisualServer::get_singleton();
vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors);
}
@@ -770,8 +812,8 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &StyleBoxFlat::set_bg_color);
ClassDB::bind_method(D_METHOD("get_bg_color"), &StyleBoxFlat::get_bg_color);
- ClassDB::bind_method(D_METHOD("set_border_color", "color"), &StyleBoxFlat::set_border_color_all);
- ClassDB::bind_method(D_METHOD("get_border_color"), &StyleBoxFlat::get_border_color_all);
+ ClassDB::bind_method(D_METHOD("set_border_color", "color"), &StyleBoxFlat::set_border_color);
+ ClassDB::bind_method(D_METHOD("get_border_color"), &StyleBoxFlat::get_border_color);
ClassDB::bind_method(D_METHOD("set_border_width_all", "width"), &StyleBoxFlat::set_border_width_all);
ClassDB::bind_method(D_METHOD("get_border_width_min"), &StyleBoxFlat::get_border_width_min);
@@ -802,6 +844,9 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shadow_size", "size"), &StyleBoxFlat::set_shadow_size);
ClassDB::bind_method(D_METHOD("get_shadow_size"), &StyleBoxFlat::get_shadow_size);
+ ClassDB::bind_method(D_METHOD("set_shadow_offset", "offset"), &StyleBoxFlat::set_shadow_offset);
+ ClassDB::bind_method(D_METHOD("get_shadow_offset"), &StyleBoxFlat::get_shadow_offset);
+
ClassDB::bind_method(D_METHOD("set_anti_aliased", "anti_aliased"), &StyleBoxFlat::set_anti_aliased);
ClassDB::bind_method(D_METHOD("is_anti_aliased"), &StyleBoxFlat::is_anti_aliased);
@@ -843,6 +888,7 @@ void StyleBoxFlat::_bind_methods() {
ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size"), "set_shadow_size", "get_shadow_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset"), "set_shadow_offset", "get_shadow_offset");
ADD_GROUP("Anti Aliasing", "anti_aliasing_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "anti_aliasing"), "set_anti_aliased", "is_anti_aliased");
@@ -853,17 +899,14 @@ StyleBoxFlat::StyleBoxFlat() {
bg_color = Color(0.6, 0.6, 0.6);
shadow_color = Color(0, 0, 0, 0.6);
-
- border_color.append(Color(0.8, 0.8, 0.8));
- border_color.append(Color(0.8, 0.8, 0.8));
- border_color.append(Color(0.8, 0.8, 0.8));
- border_color.append(Color(0.8, 0.8, 0.8));
+ border_color = Color(0.8, 0.8, 0.8);
blend_border = false;
draw_center = true;
anti_aliased = true;
shadow_size = 0;
+ shadow_offset = Point2(0, 0);
corner_detail = 8;
aa_size = 1;
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 9062270765..c3965fe076 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -149,7 +149,7 @@ class StyleBoxFlat : public StyleBox {
Color bg_color;
Color shadow_color;
- PoolVector<Color> border_color;
+ Color border_color;
int border_width[4];
int expand_margin[4];
@@ -161,6 +161,7 @@ class StyleBoxFlat : public StyleBox {
int corner_detail;
int shadow_size;
+ Point2 shadow_offset;
int aa_size;
protected:
@@ -173,10 +174,8 @@ public:
Color get_bg_color() const;
//Border Color
- void set_border_color_all(const Color &p_color);
- Color get_border_color_all() const;
- void set_border_color(Margin p_border, const Color &p_color);
- Color get_border_color(Margin p_border) const;
+ void set_border_color(const Color &p_color);
+ Color get_border_color() const;
//BORDER
//width
@@ -218,6 +217,9 @@ public:
void set_shadow_size(const int &p_size);
int get_shadow_size() const;
+ void set_shadow_offset(const Point2 &p_offset);
+ Point2 get_shadow_offset() const;
+
//ANTI_ALIASING
void set_anti_aliased(const bool &p_anti_aliased);
bool is_anti_aliased() const;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 4ddfc0331b..21b2893502 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -215,7 +215,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = autotile_get_spacing(id);
else if (what == "bitmask_flags") {
Array p;
- for (Map<Vector2, uint16_t>::Element *E = tile_map[id].autotile_data.flags.front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tile_map[id].autotile_data.flags.front(); E; E = E->next()) {
p.push_back(E->key());
p.push_back(E->value());
}
@@ -544,7 +544,7 @@ const Map<Vector2, int> &TileSet::autotile_get_z_index_map(int p_id) const {
return tile_map[p_id].autotile_data.z_index_map;
}
-void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag) {
+void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag) {
ERR_FAIL_COND(!tile_map.has(p_id));
if (p_flag == 0) {
@@ -555,7 +555,7 @@ void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag) {
}
}
-uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
+uint32_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
if (!tile_map[p_id].autotile_data.flags.has(p_coord)) {
@@ -564,13 +564,13 @@ uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
return tile_map[p_id].autotile_data.flags[p_coord];
}
-const Map<Vector2, uint16_t> &TileSet::autotile_get_bitmask_map(int p_id) {
+const Map<Vector2, uint32_t> &TileSet::autotile_get_bitmask_map(int p_id) {
- static Map<Vector2, uint16_t> dummy;
- static Map<Vector2, uint16_t> dummy_atlas;
+ static Map<Vector2, uint32_t> dummy;
+ static Map<Vector2, uint32_t> dummy_atlas;
ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
if (tile_get_tile_mode(p_id) == ATLAS_TILE) {
- dummy_atlas = Map<Vector2, uint16_t>();
+ dummy_atlas = Map<Vector2, uint32_t>();
Rect2 region = tile_get_region(p_id);
Size2 size = autotile_get_size(p_id);
float spacing = autotile_get_spacing(p_id);
@@ -600,18 +600,25 @@ Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask,
}
List<Vector2> coords;
- uint16_t mask;
- for (Map<Vector2, uint16_t>::Element *E = tile_map[p_id].autotile_data.flags.front(); E; E = E->next()) {
+ uint32_t mask;
+ uint16_t mask_;
+ uint16_t mask_ignore;
+ for (Map<Vector2, uint32_t>::Element *E = tile_map[p_id].autotile_data.flags.front(); E; E = E->next()) {
mask = E->get();
if (tile_map[p_id].autotile_data.bitmask_mode == BITMASK_2X2) {
- mask &= (BIND_BOTTOMLEFT | BIND_BOTTOMRIGHT | BIND_TOPLEFT | BIND_TOPRIGHT);
+ mask |= (BIND_IGNORE_TOP | BIND_IGNORE_LEFT | BIND_IGNORE_CENTER | BIND_IGNORE_RIGHT | BIND_IGNORE_BOTTOM);
}
- if (mask == p_bitmask) {
+
+ mask_ = mask & 0xFFFF;
+ mask_ignore = mask >> 16;
+
+ if (((mask_ & (~mask_ignore)) == (p_bitmask & (~mask_ignore))) && (((~mask_) | mask_ignore) == ((~p_bitmask) | mask_ignore))) {
for (int i = 0; i < autotile_get_subtile_priority(p_id, E->key()); i++) {
coords.push_back(E->key());
}
}
}
+
if (coords.size() == 0) {
return autotile_get_icon_coordinate(p_id);
} else {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index fac48243d0..fb84cee218 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -72,7 +72,17 @@ public:
BIND_RIGHT = 32,
BIND_BOTTOMLEFT = 64,
BIND_BOTTOM = 128,
- BIND_BOTTOMRIGHT = 256
+ BIND_BOTTOMRIGHT = 256,
+
+ BIND_IGNORE_TOPLEFT = 1 << 16,
+ BIND_IGNORE_TOP = 1 << 17,
+ BIND_IGNORE_TOPRIGHT = 1 << 18,
+ BIND_IGNORE_LEFT = 1 << 19,
+ BIND_IGNORE_CENTER = 1 << 20,
+ BIND_IGNORE_RIGHT = 1 << 21,
+ BIND_IGNORE_BOTTOMLEFT = 1 << 22,
+ BIND_IGNORE_BOTTOM = 1 << 23,
+ BIND_IGNORE_BOTTOMRIGHT = 1 << 24
};
enum TileMode {
@@ -86,7 +96,7 @@ public:
Size2 size;
int spacing;
Vector2 icon_coord;
- Map<Vector2, uint16_t> flags;
+ Map<Vector2, uint32_t> flags;
Map<Vector2, Ref<OccluderPolygon2D> > occluder_map;
Map<Vector2, Ref<NavigationPolygon> > navpoly_map;
Map<Vector2, int> priority_map;
@@ -181,9 +191,9 @@ public:
int autotile_get_z_index(int p_id, const Vector2 &p_coord);
const Map<Vector2, int> &autotile_get_z_index_map(int p_id) const;
- void autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag);
- uint16_t autotile_get_bitmask(int p_id, Vector2 p_coord);
- const Map<Vector2, uint16_t> &autotile_get_bitmask_map(int p_id);
+ void autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag);
+ uint32_t autotile_get_bitmask(int p_id, Vector2 p_coord);
+ const Map<Vector2, uint32_t> &autotile_get_bitmask_map(int p_id);
Vector2 autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node = NULL, const Vector2 &p_tile_location = Vector2());
void tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape);
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 4e5909eb2e..bac10a1cd5 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -252,7 +252,7 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po
VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port);
VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port);
- if (MAX(0, from_port_type - 1) != (MAX(0, to_port_type - 1))) {
+ if (MAX(0, from_port_type - 2) != (MAX(0, to_port_type - 2))) {
return false;
}
@@ -278,8 +278,8 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port);
VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port);
- if (MAX(0, from_port_type - 1) != (MAX(0, to_port_type - 1))) {
- ERR_EXPLAIN("Incompatible port types (scalar/vec with transform");
+ if (MAX(0, from_port_type - 2) != (MAX(0, to_port_type - 2))) {
+ ERR_EXPLAIN("Incompatible port types (scalar/vec/bool with transform");
ERR_FAIL_V(ERR_INVALID_PARAMETER)
return ERR_INVALID_PARAMETER;
}
@@ -456,6 +456,8 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR) {
code += "\tCOLOR.rgb = vec3( n_out" + itos(p_node) + "p" + itos(p_port) + " );\n";
+ } else if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_BOOLEAN) {
+ code += "\tCOLOR.rgb = vec3( n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0 );\n";
} else {
code += "\tCOLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
}
@@ -779,6 +781,14 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
inputs[i] = "dot(" + src_var + ",vec3(0.333333,0.333333,0.333333))";
} else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_SCALAR) {
inputs[i] = "vec3(" + src_var + ")";
+ } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_VECTOR) {
+ inputs[i] = "all(" + src_var + ")";
+ } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_SCALAR) {
+ inputs[i] = src_var + ">0.0?true:false";
+ } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) {
+ inputs[i] = src_var + "?1.0:0.0";
+ } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) {
+ inputs[i] = "vec3(" + src_var + "?1.0:0.0)";
}
} else {
@@ -787,6 +797,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
float val = defval;
inputs[i] = "n_in" + itos(node) + "p" + itos(i);
code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n";
+ } else if (defval.get_type() == Variant::BOOL) {
+ bool val = defval;
+ inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ code += "\nbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n";
} else if (defval.get_type() == Variant::VECTOR3) {
Vector3 val = defval;
inputs[i] = "n_in" + itos(node) + "p" + itos(i);
@@ -823,6 +837,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_SCALAR: code += String() + "\tfloat " + outputs[i] + ";\n"; break;
case VisualShaderNode::PORT_TYPE_VECTOR: code += String() + "\tvec3 " + outputs[i] + ";\n"; break;
+ case VisualShaderNode::PORT_TYPE_BOOLEAN: code += String() + "\tbool " + outputs[i] + ";\n"; break;
case VisualShaderNode::PORT_TYPE_TRANSFORM: code += String() + "\tmat4 " + outputs[i] + ";\n"; break;
default: {}
}
@@ -1262,6 +1277,11 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T
case PORT_TYPE_TRANSFORM: {
code = "\t" + p_output_vars[0] + " = mat4( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), vec4(0.0,0.0,1.0,0.0), vec4(0.0,0.0,0.0,1.0) );\n";
} break; //default (none found) is scalar
+ case PORT_TYPE_BOOLEAN: {
+ code = "\t" + p_output_vars[0] + " = false;\n";
+ } break;
+ default:
+ break;
}
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 4792038351..cf10de9bf5 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -175,7 +175,9 @@ public:
enum PortType {
PORT_TYPE_SCALAR,
PORT_TYPE_VECTOR,
+ PORT_TYPE_BOOLEAN,
PORT_TYPE_TRANSFORM,
+ PORT_TYPE_COLOR // just a hint for node tree icons, do not use it as actual port type !
};
virtual String get_caption() const = 0;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index e47069d723..dac999bf1d 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -88,6 +88,67 @@ VisualShaderNodeScalarConstant::VisualShaderNodeScalarConstant() {
constant = 0;
}
+////////////// Boolean
+
+String VisualShaderNodeBooleanConstant::get_caption() const {
+ return "Boolean";
+}
+
+int VisualShaderNodeBooleanConstant::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeBooleanConstant::PortType VisualShaderNodeBooleanConstant::get_input_port_type(int p_port) const {
+ return PORT_TYPE_BOOLEAN;
+}
+
+String VisualShaderNodeBooleanConstant::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeBooleanConstant::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeBooleanConstant::PortType VisualShaderNodeBooleanConstant::get_output_port_type(int p_port) const {
+ return PORT_TYPE_BOOLEAN;
+}
+
+String VisualShaderNodeBooleanConstant::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeBooleanConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = " + (constant ? "true" : "false") + ";\n";
+}
+
+void VisualShaderNodeBooleanConstant::set_constant(bool p_value) {
+ constant = p_value;
+ emit_changed();
+}
+
+bool VisualShaderNodeBooleanConstant::get_constant() const {
+ return constant;
+}
+
+Vector<StringName> VisualShaderNodeBooleanConstant::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("constant");
+ return props;
+}
+
+void VisualShaderNodeBooleanConstant::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeBooleanConstant::set_constant);
+ ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeBooleanConstant::get_constant);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "constant"), "set_constant", "get_constant");
+}
+
+VisualShaderNodeBooleanConstant::VisualShaderNodeBooleanConstant() {
+ constant = false;
+}
+
////////////// Color
String VisualShaderNodeColorConstant::get_caption() const {
@@ -666,6 +727,7 @@ String VisualShaderNodeScalarOp::generate_code(Shader::Mode p_mode, VisualShader
case OP_MAX: code += "max( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
case OP_MIN: code += "min( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
case OP_ATAN2: code += "atan( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_STEP: code += "step( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
}
return code;
@@ -693,7 +755,7 @@ void VisualShaderNodeScalarOp::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeScalarOp::set_operator);
ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeScalarOp::get_operator);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Atan2"), "set_operator", "get_operator");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Atan2,Step"), "set_operator", "get_operator");
BIND_ENUM_CONSTANT(OP_ADD);
BIND_ENUM_CONSTANT(OP_SUB);
@@ -704,6 +766,7 @@ void VisualShaderNodeScalarOp::_bind_methods() {
BIND_ENUM_CONSTANT(OP_MAX);
BIND_ENUM_CONSTANT(OP_MIN);
BIND_ENUM_CONSTANT(OP_ATAN2);
+ BIND_ENUM_CONSTANT(OP_STEP);
}
VisualShaderNodeScalarOp::VisualShaderNodeScalarOp() {
@@ -752,6 +815,9 @@ String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader
case OP_MAX: code += "max( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
case OP_MIN: code += "min( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
case OP_CROSS: code += "cross( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_ATAN2: code += "atan( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_REFLECT: code += "reflect( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_STEP: code += "step( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
}
return code;
@@ -779,7 +845,7 @@ void VisualShaderNodeVectorOp::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeVectorOp::set_operator);
ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeVectorOp::get_operator);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Cross"), "set_operator", "get_operator");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Cross,Atan2,Reflect,Step"), "set_operator", "get_operator");
BIND_ENUM_CONSTANT(OP_ADD);
BIND_ENUM_CONSTANT(OP_SUB);
@@ -790,6 +856,9 @@ void VisualShaderNodeVectorOp::_bind_methods() {
BIND_ENUM_CONSTANT(OP_MAX);
BIND_ENUM_CONSTANT(OP_MIN);
BIND_ENUM_CONSTANT(OP_CROSS);
+ BIND_ENUM_CONSTANT(OP_ATAN2);
+ BIND_ENUM_CONSTANT(OP_REFLECT);
+ BIND_ENUM_CONSTANT(OP_STEP);
}
VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() {
@@ -976,8 +1045,12 @@ String VisualShaderNodeTransformMult::generate_code(Shader::Mode p_mode, VisualS
if (op == OP_AxB) {
return "\t" + p_output_vars[0] + " = " + p_input_vars[0] + " * " + p_input_vars[1] + ";\n";
- } else {
+ } else if (op == OP_BxA) {
return "\t" + p_output_vars[0] + " = " + p_input_vars[1] + " * " + p_input_vars[0] + ";\n";
+ } else if (op == OP_AxB_COMP) {
+ return "\t" + p_output_vars[0] + " = matrixCompMult( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n";
+ } else {
+ return "\t" + p_output_vars[0] + " = matrixCompMult( " + p_input_vars[1] + " , " + p_input_vars[0] + " );\n";
}
}
@@ -1003,10 +1076,12 @@ void VisualShaderNodeTransformMult::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeTransformMult::set_operator);
ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeTransformMult::get_operator);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "A x B,B x A"), "set_operator", "get_operator");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "A x B,B x A,A x B(per component),B x A(per component)"), "set_operator", "get_operator");
BIND_ENUM_CONSTANT(OP_AxB);
BIND_ENUM_CONSTANT(OP_BxA);
+ BIND_ENUM_CONSTANT(OP_AxB_COMP);
+ BIND_ENUM_CONSTANT(OP_BxA_COMP);
}
VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() {
@@ -1117,7 +1192,7 @@ String VisualShaderNodeScalarFunc::get_output_port_name(int p_port) const {
String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- static const char *scalar_func_id[FUNC_NEGATE + 1] = {
+ static const char *scalar_func_id[FUNC_TRUNC + 1] = {
"sin($)",
"cos($)",
"tan($)",
@@ -1138,6 +1213,17 @@ String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShad
"fract($)",
"min(max($,0.0),1.0)",
"-($)",
+ "acosh($)",
+ "asinh($)",
+ "atanh($)",
+ "degrees($)",
+ "exp2($)",
+ "inversesqrt($)",
+ "log2($)",
+ "radians($)",
+ "1.0/($)",
+ "roundEven($)",
+ "trunc($)"
};
return "\t" + p_output_vars[0] + " = " + String(scalar_func_id[func]).replace("$", p_input_vars[0]) + ";\n";
@@ -1165,7 +1251,7 @@ void VisualShaderNodeScalarFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_SIN);
BIND_ENUM_CONSTANT(FUNC_COS);
@@ -1187,6 +1273,17 @@ void VisualShaderNodeScalarFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_FRAC);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
BIND_ENUM_CONSTANT(FUNC_NEGATE);
+ BIND_ENUM_CONSTANT(FUNC_ACOSH);
+ BIND_ENUM_CONSTANT(FUNC_ASINH);
+ BIND_ENUM_CONSTANT(FUNC_ATANH);
+ BIND_ENUM_CONSTANT(FUNC_DEGREES);
+ BIND_ENUM_CONSTANT(FUNC_EXP2);
+ BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT);
+ BIND_ENUM_CONSTANT(FUNC_LOG2);
+ BIND_ENUM_CONSTANT(FUNC_RADIANS);
+ BIND_ENUM_CONSTANT(FUNC_RECIPROCAL);
+ BIND_ENUM_CONSTANT(FUNC_ROUNDEVEN);
+ BIND_ENUM_CONSTANT(FUNC_TRUNC);
}
VisualShaderNodeScalarFunc::VisualShaderNodeScalarFunc() {
@@ -1222,13 +1319,41 @@ String VisualShaderNodeVectorFunc::get_output_port_name(int p_port) const {
String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- static const char *vec_func_id[FUNC_HSV2RGB + 1] = {
+ static const char *vec_func_id[FUNC_TRUNC + 1] = {
"normalize($)",
"max(min($,vec3(1.0)),vec3(0.0))",
"-($)",
"1.0/($)",
"",
"",
+ "abs($)",
+ "acos($)",
+ "acosh($)",
+ "asin($)",
+ "asinh($)",
+ "atan($)",
+ "atanh($)",
+ "ceil($)",
+ "cos($)",
+ "cosh($)",
+ "degrees($)",
+ "exp($)",
+ "exp2($)",
+ "floor($)",
+ "fract($)",
+ "inversesqrt($)",
+ "log($)",
+ "log2($)",
+ "radians($)",
+ "round($)",
+ "roundEven($)",
+ "sign($)",
+ "sin($)",
+ "sinh($)",
+ "sqrt($)",
+ "tan($)",
+ "tanh($)",
+ "trunc($)"
};
String code;
@@ -1280,7 +1405,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_NORMALIZE);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
@@ -1288,6 +1413,34 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_RECIPROCAL);
BIND_ENUM_CONSTANT(FUNC_RGB2HSV);
BIND_ENUM_CONSTANT(FUNC_HSV2RGB);
+ BIND_ENUM_CONSTANT(FUNC_ABS);
+ BIND_ENUM_CONSTANT(FUNC_ACOS);
+ BIND_ENUM_CONSTANT(FUNC_ACOSH);
+ BIND_ENUM_CONSTANT(FUNC_ASIN);
+ BIND_ENUM_CONSTANT(FUNC_ASINH);
+ BIND_ENUM_CONSTANT(FUNC_ATAN);
+ BIND_ENUM_CONSTANT(FUNC_ATANH);
+ BIND_ENUM_CONSTANT(FUNC_CEIL);
+ BIND_ENUM_CONSTANT(FUNC_COS);
+ BIND_ENUM_CONSTANT(FUNC_COSH);
+ BIND_ENUM_CONSTANT(FUNC_DEGREES);
+ BIND_ENUM_CONSTANT(FUNC_EXP);
+ BIND_ENUM_CONSTANT(FUNC_EXP2);
+ BIND_ENUM_CONSTANT(FUNC_FLOOR);
+ BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT);
+ BIND_ENUM_CONSTANT(FUNC_LOG);
+ BIND_ENUM_CONSTANT(FUNC_LOG2);
+ BIND_ENUM_CONSTANT(FUNC_RADIANS);
+ BIND_ENUM_CONSTANT(FUNC_ROUND);
+ BIND_ENUM_CONSTANT(FUNC_ROUNDEVEN);
+ BIND_ENUM_CONSTANT(FUNC_SIGN);
+ BIND_ENUM_CONSTANT(FUNC_SIN);
+ BIND_ENUM_CONSTANT(FUNC_SINH);
+ BIND_ENUM_CONSTANT(FUNC_SQRT);
+ BIND_ENUM_CONSTANT(FUNC_TAN);
+ BIND_ENUM_CONSTANT(FUNC_TANH);
+ BIND_ENUM_CONSTANT(FUNC_TRUNC);
}
VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() {
@@ -1295,6 +1448,172 @@ VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() {
set_input_port_default_value(0, Vector3());
}
+////////////// ColorFunc
+
+String VisualShaderNodeColorFunc::get_caption() const {
+ return "ColorFunc";
+}
+
+int VisualShaderNodeColorFunc::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeColorFunc::PortType VisualShaderNodeColorFunc::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeColorFunc::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeColorFunc::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeColorFunc::PortType VisualShaderNodeColorFunc::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeColorFunc::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+
+ String code;
+
+ switch (func) {
+ case FUNC_GRAYSCALE:
+ code += "\t{\n";
+ code += "\t\tvec3 c = " + p_input_vars[0] + ";\n";
+ code += "\t\tfloat max1 = max(c.r, c.g);\n";
+ code += "\t\tfloat max2 = max(max1, c.b);\n";
+ code += "\t\tfloat max3 = max(max1, max2);\n";
+ code += "\t\t" + p_output_vars[0] + " = vec3(max3, max3, max3);\n";
+ code += "\t}\n";
+ break;
+ case FUNC_SEPIA:
+ code += "\t{\n";
+ code += "\t\tvec3 c = " + p_input_vars[0] + ";\n";
+ code += "\t\tfloat r = (c.r * .393) + (c.g *.769) + (c.b * .189);\n";
+ code += "\t\tfloat g = (c.r * .349) + (c.g *.686) + (c.b * .168);\n";
+ code += "\t\tfloat b = (c.r * .272) + (c.g *.534) + (c.b * .131);\n";
+ code += "\t\t" + p_output_vars[0] + " = vec3(r, g, b);\n";
+ code += "\t}\n";
+ break;
+ }
+
+ return code;
+}
+
+void VisualShaderNodeColorFunc::set_function(Function p_func) {
+
+ func = p_func;
+ emit_changed();
+}
+
+VisualShaderNodeColorFunc::Function VisualShaderNodeColorFunc::get_function() const {
+
+ return func;
+}
+
+Vector<StringName> VisualShaderNodeColorFunc::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("function");
+ return props;
+}
+
+void VisualShaderNodeColorFunc::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeColorFunc::set_function);
+ ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeColorFunc::get_function);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,Sepia"), "set_function", "get_function");
+
+ BIND_ENUM_CONSTANT(FUNC_GRAYSCALE);
+ BIND_ENUM_CONSTANT(FUNC_SEPIA);
+}
+
+VisualShaderNodeColorFunc::VisualShaderNodeColorFunc() {
+ func = FUNC_GRAYSCALE;
+ set_input_port_default_value(0, Vector3());
+}
+
+////////////// Transform Func
+
+String VisualShaderNodeTransformFunc::get_caption() const {
+ return "TransformFunc";
+}
+
+int VisualShaderNodeTransformFunc::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeTransformFunc::PortType VisualShaderNodeTransformFunc::get_input_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+
+String VisualShaderNodeTransformFunc::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeTransformFunc::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeTransformFunc::PortType VisualShaderNodeTransformFunc::get_output_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+
+String VisualShaderNodeTransformFunc::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeTransformFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+
+ static const char *funcs[FUNC_TRANSPOSE + 1] = {
+ "inverse($)",
+ "transpose($)"
+ };
+
+ String code;
+ code += "\t" + p_output_vars[0] + "=" + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n";
+ return code;
+}
+
+void VisualShaderNodeTransformFunc::set_function(Function p_func) {
+
+ func = p_func;
+ emit_changed();
+}
+
+VisualShaderNodeTransformFunc::Function VisualShaderNodeTransformFunc::get_function() const {
+
+ return func;
+}
+
+Vector<StringName> VisualShaderNodeTransformFunc::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("function");
+ return props;
+}
+
+void VisualShaderNodeTransformFunc::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeTransformFunc::set_function);
+ ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeTransformFunc::get_function);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Inverse,Transpose"), "set_function", "get_function");
+
+ BIND_ENUM_CONSTANT(FUNC_INVERSE);
+ BIND_ENUM_CONSTANT(FUNC_TRANSPOSE);
+}
+
+VisualShaderNodeTransformFunc::VisualShaderNodeTransformFunc() {
+ func = FUNC_INVERSE;
+ set_input_port_default_value(0, Transform());
+}
+
////////////// Dot Product
String VisualShaderNodeDotProduct::get_caption() const {
@@ -1364,6 +1683,670 @@ VisualShaderNodeVectorLen::VisualShaderNodeVectorLen() {
set_input_port_default_value(0, Vector3());
}
+////////////// Determinant
+
+String VisualShaderNodeDeterminant::get_caption() const {
+ return "Determinant";
+}
+
+int VisualShaderNodeDeterminant::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeScalarClamp::PortType VisualShaderNodeDeterminant::get_input_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+
+String VisualShaderNodeDeterminant::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeDeterminant::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeDeterminant::PortType VisualShaderNodeDeterminant::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeDeterminant::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeDeterminant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = determinant( " + p_input_vars[0] + " );\n";
+}
+
+VisualShaderNodeDeterminant::VisualShaderNodeDeterminant() {
+ set_input_port_default_value(0, Transform());
+}
+
+////////////// Scalar Derivative Function
+
+String VisualShaderNodeScalarDerivativeFunc::get_caption() const {
+ return "ScalarDerivativeFunc";
+}
+
+int VisualShaderNodeScalarDerivativeFunc::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeScalarDerivativeFunc::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeScalarDerivativeFunc::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeScalarDerivativeFunc::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeScalarDerivativeFunc::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeScalarDerivativeFunc::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeScalarDerivativeFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+
+ static const char *funcs[FUNC_Y + 1] = {
+ "fwidth($)",
+ "dFdx($)",
+ "dFdy($)"
+ };
+
+ String code;
+ code += "\t" + p_output_vars[0] + "=" + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n";
+ return code;
+}
+
+void VisualShaderNodeScalarDerivativeFunc::set_function(Function p_func) {
+
+ func = p_func;
+ emit_changed();
+}
+
+VisualShaderNodeScalarDerivativeFunc::Function VisualShaderNodeScalarDerivativeFunc::get_function() const {
+
+ return func;
+}
+
+Vector<StringName> VisualShaderNodeScalarDerivativeFunc::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("function");
+ return props;
+}
+
+void VisualShaderNodeScalarDerivativeFunc::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarDerivativeFunc::set_function);
+ ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarDerivativeFunc::get_function);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function");
+
+ BIND_ENUM_CONSTANT(FUNC_SUM);
+ BIND_ENUM_CONSTANT(FUNC_X);
+ BIND_ENUM_CONSTANT(FUNC_Y);
+}
+
+VisualShaderNodeScalarDerivativeFunc::VisualShaderNodeScalarDerivativeFunc() {
+ func = FUNC_SUM;
+ set_input_port_default_value(0, 0.0);
+}
+
+////////////// Vector Derivative Function
+
+String VisualShaderNodeVectorDerivativeFunc::get_caption() const {
+ return "VectorDerivativeFunc";
+}
+
+int VisualShaderNodeVectorDerivativeFunc::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVectorDerivativeFunc::PortType VisualShaderNodeVectorDerivativeFunc::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorDerivativeFunc::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeVectorDerivativeFunc::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeVectorDerivativeFunc::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorDerivativeFunc::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeVectorDerivativeFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+
+ static const char *funcs[FUNC_Y + 1] = {
+ "fwidth($)",
+ "dFdx($)",
+ "dFdy($)"
+ };
+
+ String code;
+ code += "\t" + p_output_vars[0] + "=" + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n";
+ return code;
+}
+
+void VisualShaderNodeVectorDerivativeFunc::set_function(Function p_func) {
+
+ func = p_func;
+ emit_changed();
+}
+
+VisualShaderNodeVectorDerivativeFunc::Function VisualShaderNodeVectorDerivativeFunc::get_function() const {
+
+ return func;
+}
+
+Vector<StringName> VisualShaderNodeVectorDerivativeFunc::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("function");
+ return props;
+}
+
+void VisualShaderNodeVectorDerivativeFunc::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorDerivativeFunc::set_function);
+ ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorDerivativeFunc::get_function);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function");
+
+ BIND_ENUM_CONSTANT(FUNC_SUM);
+ BIND_ENUM_CONSTANT(FUNC_X);
+ BIND_ENUM_CONSTANT(FUNC_Y);
+}
+
+VisualShaderNodeVectorDerivativeFunc::VisualShaderNodeVectorDerivativeFunc() {
+ func = FUNC_SUM;
+ set_input_port_default_value(0, Vector3());
+}
+
+////////////// Scalar Clamp
+
+String VisualShaderNodeScalarClamp::get_caption() const {
+ return "ScalarClamp";
+}
+
+int VisualShaderNodeScalarClamp::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeScalarClamp::get_input_port_name(int p_port) const {
+ if (p_port == 0)
+ return "";
+ else if (p_port == 1)
+ return "min";
+ else if (p_port == 2)
+ return "max";
+ return "";
+}
+
+int VisualShaderNodeScalarClamp::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeScalarClamp::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeScalarClamp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = clamp( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeScalarClamp::VisualShaderNodeScalarClamp() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 1.0);
+}
+
+////////////// Vector Clamp
+
+String VisualShaderNodeVectorClamp::get_caption() const {
+ return "VectorClamp";
+}
+
+int VisualShaderNodeVectorClamp::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorClamp::get_input_port_name(int p_port) const {
+ if (p_port == 0)
+ return "";
+ else if (p_port == 1)
+ return "min";
+ else if (p_port == 2)
+ return "max";
+ return "";
+}
+
+int VisualShaderNodeVectorClamp::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorClamp::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeVectorClamp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = clamp( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeVectorClamp::VisualShaderNodeVectorClamp() {
+ set_input_port_default_value(0, Vector3(0, 0, 0));
+ set_input_port_default_value(1, Vector3(0, 0, 0));
+ set_input_port_default_value(2, Vector3(1, 1, 1));
+}
+
+////////////// FaceForward
+
+String VisualShaderNodeFaceForward::get_caption() const {
+ return "FaceForward";
+}
+
+int VisualShaderNodeFaceForward::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeFaceForward::PortType VisualShaderNodeFaceForward::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeFaceForward::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "N";
+ case 1:
+ return "I";
+ case 2:
+ return "Nref";
+ default:
+ return "";
+ }
+}
+
+int VisualShaderNodeFaceForward::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeFaceForward::PortType VisualShaderNodeFaceForward::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeFaceForward::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeFaceForward::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = faceforward( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeFaceForward::VisualShaderNodeFaceForward() {
+ set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0));
+}
+
+////////////// Outer Product
+
+String VisualShaderNodeOuterProduct::get_caption() const {
+ return "OuterProduct";
+}
+
+int VisualShaderNodeOuterProduct::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeFaceForward::PortType VisualShaderNodeOuterProduct::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeOuterProduct::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "c";
+ case 1:
+ return "r";
+ default:
+ return "";
+ }
+}
+
+int VisualShaderNodeOuterProduct::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeOuterProduct::PortType VisualShaderNodeOuterProduct::get_output_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+
+String VisualShaderNodeOuterProduct::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeOuterProduct::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = outerProduct( " + p_input_vars[0] + ", " + p_input_vars[1] + " );\n";
+}
+
+VisualShaderNodeOuterProduct::VisualShaderNodeOuterProduct() {
+ set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
+}
+
+////////////// Vector-Scalar Step
+
+String VisualShaderNodeVectorScalarStep::get_caption() const {
+ return "VectorScalarStep";
+}
+
+int VisualShaderNodeVectorScalarStep::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeVectorScalarStep::PortType VisualShaderNodeVectorScalarStep::get_input_port_type(int p_port) const {
+ if (p_port == 0) {
+ return PORT_TYPE_SCALAR;
+ }
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorScalarStep::get_input_port_name(int p_port) const {
+ if (p_port == 0)
+ return "edge";
+ else if (p_port == 1)
+ return "x";
+ return "";
+}
+
+int VisualShaderNodeVectorScalarStep::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorScalarStep::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorScalarStep::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeVectorScalarStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = step( " + p_input_vars[0] + ", " + p_input_vars[1] + " );\n";
+}
+
+VisualShaderNodeVectorScalarStep::VisualShaderNodeVectorScalarStep() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
+}
+
+////////////// Scalar SmoothStep
+
+String VisualShaderNodeScalarSmoothStep::get_caption() const {
+ return "ScalarSmoothStep";
+}
+
+int VisualShaderNodeScalarSmoothStep::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeScalarSmoothStep::get_input_port_name(int p_port) const {
+ if (p_port == 0)
+ return "edge0";
+ else if (p_port == 1)
+ return "edge1";
+ else if (p_port == 2)
+ return "x";
+ return "";
+}
+
+int VisualShaderNodeScalarSmoothStep::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeScalarSmoothStep::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeScalarSmoothStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = smoothstep( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeScalarSmoothStep::VisualShaderNodeScalarSmoothStep() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 0.0);
+}
+
+////////////// Vector SmoothStep
+
+String VisualShaderNodeVectorSmoothStep::get_caption() const {
+ return "VectorSmoothStep";
+}
+
+int VisualShaderNodeVectorSmoothStep::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorSmoothStep::get_input_port_name(int p_port) const {
+ if (p_port == 0)
+ return "edge0";
+ else if (p_port == 1)
+ return "edge1";
+ else if (p_port == 2)
+ return "x";
+ return "";
+}
+
+int VisualShaderNodeVectorSmoothStep::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorSmoothStep::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorSmoothStep::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeVectorSmoothStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = smoothstep( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeVectorSmoothStep::VisualShaderNodeVectorSmoothStep() {
+ set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0));
+}
+
+////////////// Vector-Scalar SmoothStep
+
+String VisualShaderNodeVectorScalarSmoothStep::get_caption() const {
+ return "VectorScalarSmoothStep";
+}
+
+int VisualShaderNodeVectorScalarSmoothStep::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeVectorScalarSmoothStep::PortType VisualShaderNodeVectorScalarSmoothStep::get_input_port_type(int p_port) const {
+ if (p_port == 0) {
+ return PORT_TYPE_SCALAR;
+ } else if (p_port == 1) {
+ return PORT_TYPE_SCALAR;
+ }
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorScalarSmoothStep::get_input_port_name(int p_port) const {
+ if (p_port == 0)
+ return "edge0";
+ else if (p_port == 1)
+ return "edge1";
+ else if (p_port == 2)
+ return "x";
+ return "";
+}
+
+int VisualShaderNodeVectorScalarSmoothStep::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorScalarSmoothStep::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorScalarSmoothStep::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeVectorScalarSmoothStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = smoothstep( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeVectorScalarSmoothStep::VisualShaderNodeVectorScalarSmoothStep() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0));
+}
+
+////////////// Distance
+
+String VisualShaderNodeVectorDistance::get_caption() const {
+ return "Distance";
+}
+
+int VisualShaderNodeVectorDistance::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeVectorDistance::PortType VisualShaderNodeVectorDistance::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorDistance::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "p0";
+ } else if (p_port == 1) {
+ return "p1";
+ }
+ return "";
+}
+
+int VisualShaderNodeVectorDistance::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVectorDistance::PortType VisualShaderNodeVectorDistance::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeVectorDistance::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeVectorDistance::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = distance( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n";
+}
+
+VisualShaderNodeVectorDistance::VisualShaderNodeVectorDistance() {
+ set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
+}
+
+////////////// Refract Vector
+
+String VisualShaderNodeVectorRefract::get_caption() const {
+ return "Refract";
+}
+
+int VisualShaderNodeVectorRefract::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_input_port_type(int p_port) const {
+
+ if (p_port == 2) {
+ return PORT_TYPE_SCALAR;
+ }
+
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorRefract::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "I";
+ } else if (p_port == 1) {
+ return "N";
+ } else if (p_port == 2) {
+ return "eta";
+ }
+ return "";
+}
+
+int VisualShaderNodeVectorRefract::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeVectorRefract::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeVectorRefract::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = refract( " + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() {
+ set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(2, 0.0);
+}
+
////////////// Scalar Interp
String VisualShaderNodeScalarInterp::get_caption() const {
@@ -1662,6 +2645,47 @@ String VisualShaderNodeScalarUniform::generate_code(Shader::Mode p_mode, VisualS
VisualShaderNodeScalarUniform::VisualShaderNodeScalarUniform() {
}
+////////////// Boolean Uniform
+
+String VisualShaderNodeBooleanUniform::get_caption() const {
+ return "BooleanUniform";
+}
+
+int VisualShaderNodeBooleanUniform::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_input_port_type(int p_port) const {
+ return PORT_TYPE_BOOLEAN;
+}
+
+String VisualShaderNodeBooleanUniform::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeBooleanUniform::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_output_port_type(int p_port) const {
+ return PORT_TYPE_BOOLEAN;
+}
+
+String VisualShaderNodeBooleanUniform::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform bool " + get_uniform_name() + ";\n";
+}
+
+String VisualShaderNodeBooleanUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+}
+
+VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() {
+}
+
////////////// Color Uniform
String VisualShaderNodeColorUniform::get_caption() const {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 27b557494a..28ead64fe2 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -33,7 +33,9 @@
#include "scene/resources/visual_shader.h"
-/// CONSTANTS ///
+///////////////////////////////////////
+/// CONSTANTS
+///////////////////////////////////////
class VisualShaderNodeScalarConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeScalarConstant, VisualShaderNode)
@@ -63,6 +65,38 @@ public:
VisualShaderNodeScalarConstant();
};
+///////////////////////////////////////
+
+class VisualShaderNodeBooleanConstant : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNode)
+ bool constant;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_constant(bool p_value);
+ bool get_constant() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeBooleanConstant();
+};
+
+///////////////////////////////////////
+
class VisualShaderNodeColorConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode)
Color constant;
@@ -91,6 +125,8 @@ public:
VisualShaderNodeColorConstant();
};
+///////////////////////////////////////
+
class VisualShaderNodeVec3Constant : public VisualShaderNode {
GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNode)
Vector3 constant;
@@ -119,6 +155,8 @@ public:
VisualShaderNodeVec3Constant();
};
+///////////////////////////////////////
+
class VisualShaderNodeTransformConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNode)
Transform constant;
@@ -147,7 +185,9 @@ public:
VisualShaderNodeTransformConstant();
};
-//////////////////////////////////
+///////////////////////////////////////
+/// TEXTURES
+///////////////////////////////////////
class VisualShaderNodeTexture : public VisualShaderNode {
GDCLASS(VisualShaderNodeTexture, VisualShaderNode)
@@ -208,7 +248,7 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeTexture::TextureType)
VARIANT_ENUM_CAST(VisualShaderNodeTexture::Source)
-//////////////////////////////////
+///////////////////////////////////////
class VisualShaderNodeCubeMap : public VisualShaderNode {
GDCLASS(VisualShaderNodeCubeMap, VisualShaderNode)
@@ -254,6 +294,9 @@ public:
};
VARIANT_ENUM_CAST(VisualShaderNodeCubeMap::TextureType)
+
+///////////////////////////////////////
+/// OPS
///////////////////////////////////////
class VisualShaderNodeScalarOp : public VisualShaderNode {
@@ -269,7 +312,8 @@ public:
OP_POW,
OP_MAX,
OP_MIN,
- OP_ATAN2
+ OP_ATAN2,
+ OP_STEP
};
protected:
@@ -313,8 +357,10 @@ public:
OP_POW,
OP_MAX,
OP_MIN,
- OP_CROSS
-
+ OP_CROSS,
+ OP_ATAN2,
+ OP_REFLECT,
+ OP_STEP
};
protected:
@@ -345,6 +391,8 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeVectorOp::Operator)
+///////////////////////////////////////
+
class VisualShaderNodeColorOp : public VisualShaderNode {
GDCLASS(VisualShaderNodeColorOp, VisualShaderNode)
@@ -358,7 +406,7 @@ public:
OP_DODGE,
OP_BURN,
OP_SOFT_LIGHT,
- OP_HARD_LIGHT,
+ OP_HARD_LIGHT
};
protected:
@@ -389,6 +437,10 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeColorOp::Operator)
+///////////////////////////////////////
+/// TRANSFORM-TRANSFORM MULTIPLICATION
+///////////////////////////////////////
+
class VisualShaderNodeTransformMult : public VisualShaderNode {
GDCLASS(VisualShaderNodeTransformMult, VisualShaderNode)
@@ -396,6 +448,8 @@ public:
enum Operator {
OP_AxB,
OP_BxA,
+ OP_AxB_COMP,
+ OP_BxA_COMP
};
protected:
@@ -426,6 +480,10 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeTransformMult::Operator)
+///////////////////////////////////////
+/// TRANSFORM-VECTOR MULTIPLICATION
+///////////////////////////////////////
+
class VisualShaderNodeTransformVecMult : public VisualShaderNode {
GDCLASS(VisualShaderNodeTransformVecMult, VisualShaderNode)
@@ -466,6 +524,8 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeTransformVecMult::Operator)
///////////////////////////////////////
+/// SCALAR FUNC
+///////////////////////////////////////
class VisualShaderNodeScalarFunc : public VisualShaderNode {
GDCLASS(VisualShaderNodeScalarFunc, VisualShaderNode)
@@ -492,6 +552,17 @@ public:
FUNC_FRAC,
FUNC_SATURATE,
FUNC_NEGATE,
+ FUNC_ACOSH,
+ FUNC_ASINH,
+ FUNC_ATANH,
+ FUNC_DEGREES,
+ FUNC_EXP2,
+ FUNC_INVERSE_SQRT,
+ FUNC_LOG2,
+ FUNC_RADIANS,
+ FUNC_RECIPROCAL,
+ FUNC_ROUNDEVEN,
+ FUNC_TRUNC
};
protected:
@@ -523,6 +594,8 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeScalarFunc::Function)
///////////////////////////////////////
+/// VECTOR FUNC
+///////////////////////////////////////
class VisualShaderNodeVectorFunc : public VisualShaderNode {
GDCLASS(VisualShaderNodeVectorFunc, VisualShaderNode)
@@ -535,6 +608,34 @@ public:
FUNC_RECIPROCAL,
FUNC_RGB2HSV,
FUNC_HSV2RGB,
+ FUNC_ABS,
+ FUNC_ACOS,
+ FUNC_ACOSH,
+ FUNC_ASIN,
+ FUNC_ASINH,
+ FUNC_ATAN,
+ FUNC_ATANH,
+ FUNC_CEIL,
+ FUNC_COS,
+ FUNC_COSH,
+ FUNC_DEGREES,
+ FUNC_EXP,
+ FUNC_EXP2,
+ FUNC_FLOOR,
+ FUNC_FRAC,
+ FUNC_INVERSE_SQRT,
+ FUNC_LOG,
+ FUNC_LOG2,
+ FUNC_RADIANS,
+ FUNC_ROUND,
+ FUNC_ROUNDEVEN,
+ FUNC_SIGN,
+ FUNC_SIN,
+ FUNC_SINH,
+ FUNC_SQRT,
+ FUNC_TAN,
+ FUNC_TANH,
+ FUNC_TRUNC
};
protected:
@@ -566,6 +667,90 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeVectorFunc::Function)
///////////////////////////////////////
+/// COLOR FUNC
+///////////////////////////////////////
+
+class VisualShaderNodeColorFunc : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeColorFunc, VisualShaderNode)
+
+public:
+ enum Function {
+ FUNC_GRAYSCALE,
+ FUNC_SEPIA
+ };
+
+protected:
+ Function func;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_function(Function p_op);
+ Function get_function() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeColorFunc();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeColorFunc::Function)
+
+///////////////////////////////////////
+/// TRANSFORM FUNC
+///////////////////////////////////////
+
+class VisualShaderNodeTransformFunc : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeTransformFunc, VisualShaderNode)
+
+public:
+ enum Function {
+ FUNC_INVERSE,
+ FUNC_TRANSPOSE
+ };
+
+protected:
+ Function func;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_function(Function p_op);
+ Function get_function() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeTransformFunc();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeTransformFunc::Function)
+
+///////////////////////////////////////
+/// DOT
+///////////////////////////////////////
class VisualShaderNodeDotProduct : public VisualShaderNode {
GDCLASS(VisualShaderNodeDotProduct, VisualShaderNode)
@@ -587,6 +772,8 @@ public:
};
///////////////////////////////////////
+/// LENGTH
+///////////////////////////////////////
class VisualShaderNodeVectorLen : public VisualShaderNode {
GDCLASS(VisualShaderNodeVectorLen, VisualShaderNode)
@@ -608,6 +795,337 @@ public:
};
///////////////////////////////////////
+/// DETERMINANT
+///////////////////////////////////////
+
+class VisualShaderNodeDeterminant : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeDeterminant, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeDeterminant();
+};
+
+///////////////////////////////////////
+/// CLAMP
+///////////////////////////////////////
+
+class VisualShaderNodeScalarClamp : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeScalarClamp, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeScalarClamp();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorClamp : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorClamp, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorClamp();
+};
+
+///////////////////////////////////////
+/// DERIVATIVE FUNCTIONS
+///////////////////////////////////////
+
+class VisualShaderNodeScalarDerivativeFunc : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeScalarDerivativeFunc, VisualShaderNode)
+
+public:
+ enum Function {
+ FUNC_SUM,
+ FUNC_X,
+ FUNC_Y
+ };
+
+protected:
+ Function func;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_function(Function p_op);
+ Function get_function() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeScalarDerivativeFunc();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeScalarDerivativeFunc::Function)
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorDerivativeFunc : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorDerivativeFunc, VisualShaderNode)
+
+public:
+ enum Function {
+ FUNC_SUM,
+ FUNC_X,
+ FUNC_Y
+ };
+
+protected:
+ Function func;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_function(Function p_op);
+ Function get_function() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeVectorDerivativeFunc();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeVectorDerivativeFunc::Function)
+
+///////////////////////////////////////
+/// FACEFORWARD
+///////////////////////////////////////
+
+class VisualShaderNodeFaceForward : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeFaceForward, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeFaceForward();
+};
+
+///////////////////////////////////////
+/// OUTER PRODUCT
+///////////////////////////////////////
+
+class VisualShaderNodeOuterProduct : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeOuterProduct, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeOuterProduct();
+};
+
+///////////////////////////////////////
+/// STEP
+///////////////////////////////////////
+
+class VisualShaderNodeVectorScalarStep : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorScalarStep, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorScalarStep();
+};
+
+///////////////////////////////////////
+/// SMOOTHSTEP
+///////////////////////////////////////
+
+class VisualShaderNodeScalarSmoothStep : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeScalarSmoothStep, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeScalarSmoothStep();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorSmoothStep : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorSmoothStep, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorSmoothStep();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorScalarSmoothStep : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorScalarSmoothStep, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorScalarSmoothStep();
+};
+
+///////////////////////////////////////
+/// DISTANCE
+///////////////////////////////////////
+
+class VisualShaderNodeVectorDistance : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorDistance, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorDistance();
+};
+
+///////////////////////////////////////
+/// REFRACT
+///////////////////////////////////////
+
+class VisualShaderNodeVectorRefract : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorRefract, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorRefract();
+};
+
+///////////////////////////////////////
+/// MIX
+///////////////////////////////////////
class VisualShaderNodeScalarInterp : public VisualShaderNode {
GDCLASS(VisualShaderNodeScalarInterp, VisualShaderNode)
@@ -650,6 +1168,8 @@ public:
};
///////////////////////////////////////
+/// COMPOSE
+///////////////////////////////////////
class VisualShaderNodeVectorCompose : public VisualShaderNode {
GDCLASS(VisualShaderNodeVectorCompose, VisualShaderNode)
@@ -692,6 +1212,8 @@ public:
};
///////////////////////////////////////
+/// DECOMPOSE
+///////////////////////////////////////
class VisualShaderNodeVectorDecompose : public VisualShaderNode {
GDCLASS(VisualShaderNodeVectorDecompose, VisualShaderNode)
@@ -734,6 +1256,8 @@ public:
};
///////////////////////////////////////
+/// UNIFORMS
+///////////////////////////////////////
class VisualShaderNodeScalarUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeScalarUniform, VisualShaderNodeUniform)
@@ -755,6 +1279,30 @@ public:
VisualShaderNodeScalarUniform();
};
+///////////////////////////////////////
+
+class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform {
+ GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeBooleanUniform();
+};
+
+///////////////////////////////////////
+
class VisualShaderNodeColorUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform)
@@ -775,6 +1323,8 @@ public:
VisualShaderNodeColorUniform();
};
+///////////////////////////////////////
+
class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform)
@@ -795,6 +1345,8 @@ public:
VisualShaderNodeVec3Uniform();
};
+///////////////////////////////////////
+
class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform)
@@ -815,7 +1367,7 @@ public:
VisualShaderNodeTransformUniform();
};
-//////////////////////////////////
+///////////////////////////////////////
class VisualShaderNodeTextureUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeTextureUniform, VisualShaderNodeUniform)
@@ -867,7 +1419,7 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureType)
VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::ColorDefault)
-//////////////////////////////////
+///////////////////////////////////////
class VisualShaderNodeCubeMapUniform : public VisualShaderNode {
GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNode)
diff --git a/servers/arvr/arvr_interface.cpp b/servers/arvr/arvr_interface.cpp
index 3e59daff6c..686ad0ba9b 100644
--- a/servers/arvr/arvr_interface.cpp
+++ b/servers/arvr/arvr_interface.cpp
@@ -123,6 +123,11 @@ ARVRInterface::ARVRInterface() {
ARVRInterface::~ARVRInterface(){};
+// optional render to external texture which enhances performance on those platforms that require us to submit our end result into special textures.
+unsigned int ARVRInterface::get_external_texture_for_eye(ARVRInterface::Eyes p_eye) {
+ return 0;
+};
+
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
bool ARVRInterface::get_anchor_detection_is_enabled() const {
return false;
diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h
index 6908f3006a..8459a82388 100644
--- a/servers/arvr/arvr_interface.h
+++ b/servers/arvr/arvr_interface.h
@@ -108,6 +108,7 @@ public:
virtual bool is_stereo() = 0; /* returns true if this interface requires stereo rendering (for VR HMDs) or mono rendering (for mobile AR) */
virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */
virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */
+ virtual unsigned int get_external_texture_for_eye(ARVRInterface::Eyes p_eye); /* if applicable return external texture to render to */
virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */
virtual void process() = 0;
diff --git a/servers/arvr/arvr_positional_tracker.cpp b/servers/arvr/arvr_positional_tracker.cpp
index b96e9596f3..aabe617a8a 100644
--- a/servers/arvr/arvr_positional_tracker.cpp
+++ b/servers/arvr/arvr_positional_tracker.cpp
@@ -46,6 +46,7 @@ void ARVRPositionalTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_position"), &ARVRPositionalTracker::get_position);
ClassDB::bind_method(D_METHOD("get_hand"), &ARVRPositionalTracker::get_hand);
ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &ARVRPositionalTracker::get_transform);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRPositionalTracker::get_mesh);
// these functions we don't want to expose to normal users but do need to be callable from GDNative
ClassDB::bind_method(D_METHOD("_set_type", "type"), &ARVRPositionalTracker::set_type);
@@ -53,7 +54,7 @@ void ARVRPositionalTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &ARVRPositionalTracker::set_joy_id);
ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &ARVRPositionalTracker::set_orientation);
ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &ARVRPositionalTracker::set_rw_position);
-
+ ClassDB::bind_method(D_METHOD("_set_mesh", "mesh"), &ARVRPositionalTracker::set_mesh);
ClassDB::bind_method(D_METHOD("get_rumble"), &ARVRPositionalTracker::get_rumble);
ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &ARVRPositionalTracker::set_rumble);
@@ -154,6 +155,18 @@ Vector3 ARVRPositionalTracker::get_rw_position() const {
return rw_position;
};
+void ARVRPositionalTracker::set_mesh(const Ref<Mesh> &p_mesh) {
+ _THREAD_SAFE_METHOD_
+
+ mesh = p_mesh;
+};
+
+Ref<Mesh> ARVRPositionalTracker::get_mesh() const {
+ _THREAD_SAFE_METHOD_
+
+ return mesh;
+};
+
ARVRPositionalTracker::TrackerHand ARVRPositionalTracker::get_hand() const {
return hand;
};
diff --git a/servers/arvr/arvr_positional_tracker.h b/servers/arvr/arvr_positional_tracker.h
index 7cb9486f59..0d6a69540f 100644
--- a/servers/arvr/arvr_positional_tracker.h
+++ b/servers/arvr/arvr_positional_tracker.h
@@ -32,6 +32,7 @@
#define ARVR_POSITIONAL_TRACKER_H
#include "core/os/thread_safe.h"
+#include "scene/resources/mesh.h"
#include "servers/arvr_server.h"
/**
@@ -40,9 +41,6 @@
The positional tracker object as an object that represents the position and orientation of a tracked object like a controller or headset.
An AR/VR Interface will registered the trackers it manages with our AR/VR server and update its position and orientation.
This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking.
-
- @TODO:
- - create subclass of spatial node that uses one of our positional trackers to automatically determine its position
*/
class ARVRPositionalTracker : public Object {
@@ -65,6 +63,7 @@ private:
Basis orientation; // our orientation
bool tracks_position; // do we track position?
Vector3 rw_position; // our position "in the real world, so without world_scale applied"
+ Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker
TrackerHand hand; // if known, the hand this tracker is held in
real_t rumble; // rumble strength, 0.0 is off, 1.0 is maximum, note that we only record here, arvr_interface is responsible for execution
@@ -91,6 +90,8 @@ public:
void set_hand(const ARVRPositionalTracker::TrackerHand p_hand);
real_t get_rumble() const;
void set_rumble(real_t p_rumble);
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
Transform get_transform(bool p_adjust_by_reference_frame) const;
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 8c092a02a2..7b2b48fe47 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -1045,8 +1045,10 @@ void AudioServer::update() {
void AudioServer::load_default_bus_layout() {
- if (ResourceLoader::exists("res://default_bus_layout.tres")) {
- Ref<AudioBusLayout> default_layout = ResourceLoader::load("res://default_bus_layout.tres");
+ String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout");
+
+ if (ResourceLoader::exists(layout_path)) {
+ Ref<AudioBusLayout> default_layout = ResourceLoader::load(layout_path);
if (default_layout.is_valid()) {
set_bus_layout(default_layout);
}
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index 1de9c7df93..0ba8a6605d 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -653,6 +653,12 @@ class Physics2DServerManager {
ClassInfo(const ClassInfo &p_ci) :
name(p_ci.name),
create_callback(p_ci.create_callback) {}
+
+ ClassInfo operator=(const ClassInfo &p_ci) {
+ name = p_ci.name;
+ create_callback = p_ci.create_callback;
+ return *this;
+ }
};
static Vector<ClassInfo> physics_2d_servers;
diff --git a/servers/physics_server.h b/servers/physics_server.h
index c71bb01943..9895ef2455 100644
--- a/servers/physics_server.h
+++ b/servers/physics_server.h
@@ -794,6 +794,12 @@ class PhysicsServerManager {
ClassInfo(const ClassInfo &p_ci) :
name(p_ci.name),
create_callback(p_ci.create_callback) {}
+
+ ClassInfo operator=(const ClassInfo &p_ci) {
+ name = p_ci.name;
+ create_callback = p_ci.create_callback;
+ return *this;
+ }
};
static Vector<ClassInfo> physics_servers;
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index dd54698471..39530bbbee 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -554,6 +554,7 @@ public:
virtual RID render_target_create() = 0;
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0;
virtual RID render_target_get_texture(RID p_render_target) const = 0;
+ virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0;
virtual bool render_target_was_used(RID p_render_target) = 0;
virtual void render_target_clear_used(RID p_render_target) = 0;
@@ -1101,7 +1102,7 @@ public:
virtual void initialize() = 0;
virtual void begin_frame(double frame_step) = 0;
virtual void set_current_render_target(RID p_render_target) = 0;
- virtual void restore_render_target() = 0;
+ virtual void restore_render_target(bool p_3d) = 0;
virtual void clear_render_target(const Color &p_color) = 0;
virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) = 0;
virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) = 0;
diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp
index af6e3db149..4adf53c183 100644
--- a/servers/visual/visual_server_canvas.cpp
+++ b/servers/visual/visual_server_canvas.cpp
@@ -629,7 +629,7 @@ void VisualServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p
if (p_tile) {
rect->flags |= RasterizerCanvas::CANVAS_RECT_TILE;
rect->flags |= RasterizerCanvas::CANVAS_RECT_REGION;
- rect->source = Rect2(0, 0, p_rect.size.width, p_rect.size.height);
+ rect->source = Rect2(0, 0, fabsf(p_rect.size.width), fabsf(p_rect.size.height));
}
if (p_rect.size.x < 0) {
diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp
index 79fdefe5c1..9ad3e4a308 100644
--- a/servers/visual/visual_server_viewport.cpp
+++ b/servers/visual/visual_server_viewport.cpp
@@ -62,6 +62,16 @@ static Transform2D _canvas_get_transform(VisualServerViewport::Viewport *p_viewp
return xf;
}
+void VisualServerViewport::_draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye) {
+ Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
+
+ if (p_viewport->use_arvr && arvr_interface.is_valid()) {
+ VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ } else {
+ VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ }
+}
+
void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye) {
/* Camera should always be BEFORE any other 3D */
@@ -89,13 +99,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
}
if (!scenario_draw_canvas_bg && can_draw_3d) {
- Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
- if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
- } else {
- VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
- }
+ _draw_3d(p_viewport, p_eye);
}
if (!p_viewport->hide_canvas) {
@@ -201,17 +205,13 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
//VSG::canvas_render->reset_canvas();
}
- VSG::rasterizer->restore_render_target();
+ VSG::rasterizer->restore_render_target(!scenario_draw_canvas_bg && can_draw_3d);
if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) {
- Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
if (!can_draw_3d) {
VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas);
- } else if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
} else {
- VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ _draw_3d(p_viewport, p_eye);
}
scenario_draw_canvas_bg = false;
}
@@ -237,14 +237,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
i++;
if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
- Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
if (!can_draw_3d) {
VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas);
- } else if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
} else {
- VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ _draw_3d(p_viewport, p_eye);
}
scenario_draw_canvas_bg = false;
@@ -252,14 +248,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
}
if (scenario_draw_canvas_bg) {
- Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
if (!can_draw_3d) {
VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas);
- } else if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
} else {
- VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ _draw_3d(p_viewport, p_eye);
}
scenario_draw_canvas_bg = false;
@@ -308,12 +300,22 @@ void VisualServerViewport::draw_viewports() {
// render mono or left eye first
ARVRInterface::Eyes leftOrMono = arvr_interface->is_stereo() ? ARVRInterface::EYE_LEFT : ARVRInterface::EYE_MONO;
+
+ // check for an external texture destination for our left eye/mono
+ VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(leftOrMono));
+
+ // set our render target as current
VSG::rasterizer->set_current_render_target(vp->render_target);
+
+ // and draw left eye/mono
_draw_viewport(vp, leftOrMono);
arvr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect);
// render right eye
if (leftOrMono == ARVRInterface::EYE_LEFT) {
+ // check for an external texture destination for our right eye
+ VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(ARVRInterface::EYE_RIGHT));
+
// commit for eye may have changed the render target
VSG::rasterizer->set_current_render_target(vp->render_target);
@@ -324,6 +326,7 @@ void VisualServerViewport::draw_viewports() {
// and for our frame timing, mark when we've finished committing our eyes
ARVRServer::get_singleton()->_mark_commit();
} else {
+ VSG::storage->render_target_set_external_texture(vp->render_target, 0);
VSG::rasterizer->set_current_render_target(vp->render_target);
VSG::scene_render->set_debug_draw_mode(vp->debug_draw);
diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h
index 5176551540..555b40a103 100644
--- a/servers/visual/visual_server_viewport.h
+++ b/servers/visual/visual_server_viewport.h
@@ -147,6 +147,7 @@ public:
private:
Color clear_color;
+ void _draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye);
void _draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye = ARVRInterface::EYE_MONO);
public: